mirror of
https://github.com/kubernetes/kubernetes.git
synced 2026-02-03 20:40:26 -05:00
Merge pull request #134152 from pohly/dra-device-taints-1.35
DRA: device taints: new ResourceSlice API, new features
This commit is contained in:
commit
c1a6a3ca71
106 changed files with 5879 additions and 1693 deletions
|
|
@ -172,6 +172,7 @@ API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,C
|
|||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,CronJobControllerConfiguration,ConcurrentCronJobSyncs
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,DaemonSetControllerConfiguration,ConcurrentDaemonSetSyncs
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,DeploymentControllerConfiguration,ConcurrentDeploymentSyncs
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,DeviceTaintEvictionControllerConfiguration,ConcurrentSyncs
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,EndpointControllerConfiguration,ConcurrentEndpointSyncs
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,EndpointControllerConfiguration,EndpointUpdatesBatchPeriod
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,EndpointSliceControllerConfiguration,ConcurrentServiceEndpointSyncs
|
||||
|
|
@ -199,6 +200,7 @@ API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,K
|
|||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,KubeControllerManagerConfiguration,DaemonSetController
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,KubeControllerManagerConfiguration,DeploymentController
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,KubeControllerManagerConfiguration,DeprecatedController
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,KubeControllerManagerConfiguration,DeviceTaintEvictionController
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,KubeControllerManagerConfiguration,EndpointController
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,KubeControllerManagerConfiguration,EndpointSliceController
|
||||
API rule violation: names_match,k8s.io/kube-controller-manager/config/v1alpha1,KubeControllerManagerConfiguration,EndpointSliceMirroringController
|
||||
|
|
|
|||
|
|
@ -2101,6 +2101,21 @@
|
|||
},
|
||||
"scope": "Cluster",
|
||||
"singularResource": "devicetaintrule",
|
||||
"subresources": [
|
||||
{
|
||||
"responseKind": {
|
||||
"group": "",
|
||||
"kind": "DeviceTaintRule",
|
||||
"version": ""
|
||||
},
|
||||
"subresource": "status",
|
||||
"verbs": [
|
||||
"get",
|
||||
"patch",
|
||||
"update"
|
||||
]
|
||||
}
|
||||
],
|
||||
"verbs": [
|
||||
"create",
|
||||
"delete",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,17 @@
|
|||
"update",
|
||||
"watch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "DeviceTaintRule",
|
||||
"name": "devicetaintrules/status",
|
||||
"namespaced": false,
|
||||
"singularName": "",
|
||||
"verbs": [
|
||||
"get",
|
||||
"patch",
|
||||
"update"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
271
api/openapi-spec/swagger.json
generated
271
api/openapi-spec/swagger.json
generated
|
|
@ -15452,7 +15452,7 @@
|
|||
"description": "NodeSelector defines the nodes where the device is available.\n\nMust use exactly one term.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set."
|
||||
},
|
||||
"taints": {
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1.DeviceTaint"
|
||||
},
|
||||
|
|
@ -15899,7 +15899,7 @@
|
|||
"description": "The device this taint is attached to has the \"effect\" on any claim which does not tolerate the taint and, through the claim, to pods using the claim.",
|
||||
"properties": {
|
||||
"effect": {
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
|
|
@ -16363,7 +16363,7 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
"devices": {
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1.Device"
|
||||
},
|
||||
|
|
@ -16405,34 +16405,11 @@
|
|||
],
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.resource.v1alpha3.CELDeviceSelector": {
|
||||
"description": "CELDeviceSelector contains a CEL expression for selecting a device.",
|
||||
"properties": {
|
||||
"expression": {
|
||||
"description": "Expression is a CEL expression which evaluates a single device. It must evaluate to true when the device under consideration satisfies the desired criteria, and false when it does not. Any other result is an error and causes allocation of devices to abort.\n\nThe expression's input is an object named \"device\", which carries the following properties:\n - driver (string): the name of the driver which defines this device.\n - attributes (map[string]object): the device's attributes, grouped by prefix\n (e.g. device.attributes[\"dra.example.com\"] evaluates to an object with all\n of the attributes which were prefixed by \"dra.example.com\".\n - capacity (map[string]object): the device's capacities, grouped by prefix.\n\nExample: Consider a device with driver=\"dra.example.com\", which exposes two attributes named \"model\" and \"ext.example.com/family\" and which exposes one capacity named \"modules\". This input to this expression would have the following fields:\n\n device.driver\n device.attributes[\"dra.example.com\"].model\n device.attributes[\"ext.example.com\"].family\n device.capacity[\"dra.example.com\"].modules\n\nThe device.driver field can be used to check for a specific driver, either as a high-level precondition (i.e. you only want to consider devices from this driver) or as part of a multi-clause expression that is meant to consider devices from different drivers.\n\nThe value type of each attribute is defined by the device definition, and users who write these expressions must consult the documentation for their specific drivers. The value type of each capacity is Quantity.\n\nIf an unknown prefix is used as a lookup in either device.attributes or device.capacity, an empty map will be returned. Any reference to an unknown field will cause an evaluation error and allocation to abort.\n\nA robust expression should check for the existence of attributes before referencing them.\n\nFor ease of use, the cel.bind() function is enabled, and can be used to simplify expressions that access multiple attributes with the same domain. For example:\n\n cel.bind(dra, device.attributes[\"dra.example.com\"], dra.someBool && dra.anotherBool)\n\nThe length of the expression must be smaller or equal to 10 Ki. The cost of evaluating it is also limited based on the estimated number of logical steps.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"expression"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.resource.v1alpha3.DeviceSelector": {
|
||||
"description": "DeviceSelector must have exactly one field set.",
|
||||
"properties": {
|
||||
"cel": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.CELDeviceSelector",
|
||||
"description": "CEL contains a CEL expression for selecting a device."
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.resource.v1alpha3.DeviceTaint": {
|
||||
"description": "The device this taint is attached to has the \"effect\" on any claim which does not tolerate the taint and, through the claim, to pods using the claim.",
|
||||
"properties": {
|
||||
"effect": {
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
|
|
@ -16472,6 +16449,10 @@
|
|||
"spec": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceTaintRuleSpec",
|
||||
"description": "Spec specifies the selector and one taint.\n\nChanging the spec automatically increments the metadata.generation number."
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceTaintRuleStatus",
|
||||
"description": "Status provides information about what was requested in the spec."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
@ -16526,7 +16507,7 @@
|
|||
"properties": {
|
||||
"deviceSelector": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceTaintSelector",
|
||||
"description": "DeviceSelector defines which device(s) the taint is applied to. All selector criteria must be satified for a device to match. The empty selector matches all devices. Without a selector, no devices are matches."
|
||||
"description": "DeviceSelector defines which device(s) the taint is applied to. All selector criteria must be satisfied for a device to match. The empty selector matches all devices. Without a selector, no devices are matches."
|
||||
},
|
||||
"taint": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceTaint",
|
||||
|
|
@ -16538,6 +16519,25 @@
|
|||
],
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.resource.v1alpha3.DeviceTaintRuleStatus": {
|
||||
"description": "DeviceTaintRuleStatus provides information about an on-going pod eviction.",
|
||||
"properties": {
|
||||
"conditions": {
|
||||
"description": "Conditions provide information about the state of the DeviceTaintRule and the cluster at some point in time, in a machine-readable and human-readable format.\n\nThe following condition is currently defined as part of this API, more may get added: - Type: EvictionInProgress - Status: True if there are currently pods which need to be evicted, False otherwise\n (includes the effects which don't cause eviction).\n- Reason: not specified, may change - Message: includes information about number of pending pods and already evicted pods\n in a human-readable format, updated periodically, may change\n\nFor `effect: None`, the condition above gets set once for each change to the spec, with the message containing information about what would happen if the effect was `NoExecute`. This feedback can be used to decide whether changing the effect to `NoExecute` will work as intended. It only gets set once to avoid having to constantly update the status.\n\nMust have 8 or fewer entries.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.Condition"
|
||||
},
|
||||
"type": "array",
|
||||
"x-kubernetes-list-map-keys": [
|
||||
"type"
|
||||
],
|
||||
"x-kubernetes-list-type": "map",
|
||||
"x-kubernetes-patch-merge-key": "type",
|
||||
"x-kubernetes-patch-strategy": "merge"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.resource.v1alpha3.DeviceTaintSelector": {
|
||||
"description": "DeviceTaintSelector defines which device(s) a DeviceTaintRule applies to. The empty selector matches all devices. Without a selector, no devices are matched.",
|
||||
"properties": {
|
||||
|
|
@ -16545,10 +16545,6 @@
|
|||
"description": "If device is set, only devices with that name are selected. This field corresponds to slice.spec.devices[].name.\n\nSetting also driver and pool may be required to avoid ambiguity, but is not required.",
|
||||
"type": "string"
|
||||
},
|
||||
"deviceClassName": {
|
||||
"description": "If DeviceClassName is set, the selectors defined there must be satisfied by a device to be selected. This field corresponds to class.metadata.name.",
|
||||
"type": "string"
|
||||
},
|
||||
"driver": {
|
||||
"description": "If driver is set, only devices from that driver are selected. This fields corresponds to slice.spec.driver.",
|
||||
"type": "string"
|
||||
|
|
@ -16556,14 +16552,6 @@
|
|||
"pool": {
|
||||
"description": "If pool is set, only devices in that pool are selected.\n\nAlso setting the driver name may be useful to avoid ambiguity when different drivers use the same pool name, but this is not required because selecting pools from different drivers may also be useful, for example when drivers with node-local devices use the node name as their pool name.",
|
||||
"type": "string"
|
||||
},
|
||||
"selectors": {
|
||||
"description": "Selectors contains the same selection criteria as a ResourceClaim. Currently, CEL expressions are supported. All of these selectors must be satisfied.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceSelector"
|
||||
},
|
||||
"type": "array",
|
||||
"x-kubernetes-list-type": "atomic"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
|
|
@ -16694,7 +16682,7 @@
|
|||
"description": "NodeSelector defines the nodes where the device is available.\n\nMust use exactly one term.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set."
|
||||
},
|
||||
"taints": {
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1beta1.DeviceTaint"
|
||||
},
|
||||
|
|
@ -17291,7 +17279,7 @@
|
|||
"description": "The device this taint is attached to has the \"effect\" on any claim which does not tolerate the taint and, through the claim, to pods using the claim.",
|
||||
"properties": {
|
||||
"effect": {
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
|
|
@ -17709,7 +17697,7 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
"devices": {
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1beta1.Device"
|
||||
},
|
||||
|
|
@ -17984,7 +17972,7 @@
|
|||
"description": "NodeSelector defines the nodes where the device is available.\n\nMust use exactly one term.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set."
|
||||
},
|
||||
"taints": {
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1beta2.DeviceTaint"
|
||||
},
|
||||
|
|
@ -18431,7 +18419,7 @@
|
|||
"description": "The device this taint is attached to has the \"effect\" on any claim which does not tolerate the taint and, through the claim, to pods using the claim.",
|
||||
"properties": {
|
||||
"effect": {
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
|
|
@ -18895,7 +18883,7 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
"devices": {
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1beta2.Device"
|
||||
},
|
||||
|
|
@ -81370,6 +81358,197 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/apis/resource.k8s.io/v1alpha3/devicetaintrules/{name}/status": {
|
||||
"get": {
|
||||
"consumes": [
|
||||
"*/*"
|
||||
],
|
||||
"description": "read status of the specified DeviceTaintRule",
|
||||
"operationId": "readResourceV1alpha3DeviceTaintRuleStatus",
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml",
|
||||
"application/vnd.kubernetes.protobuf",
|
||||
"application/cbor"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
},
|
||||
"schemes": [
|
||||
"https"
|
||||
],
|
||||
"tags": [
|
||||
"resource_v1alpha3"
|
||||
],
|
||||
"x-kubernetes-action": "get",
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"group": "resource.k8s.io",
|
||||
"kind": "DeviceTaintRule",
|
||||
"version": "v1alpha3"
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"description": "name of the DeviceTaintRule",
|
||||
"in": "path",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
},
|
||||
{
|
||||
"$ref": "#/parameters/pretty-tJGM1-ng"
|
||||
}
|
||||
],
|
||||
"patch": {
|
||||
"consumes": [
|
||||
"application/json-patch+json",
|
||||
"application/merge-patch+json",
|
||||
"application/strategic-merge-patch+json",
|
||||
"application/apply-patch+yaml",
|
||||
"application/apply-patch+cbor"
|
||||
],
|
||||
"description": "partially update status of the specified DeviceTaintRule",
|
||||
"operationId": "patchResourceV1alpha3DeviceTaintRuleStatus",
|
||||
"parameters": [
|
||||
{
|
||||
"$ref": "#/parameters/body-78PwaGsr"
|
||||
},
|
||||
{
|
||||
"description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
|
||||
"in": "query",
|
||||
"name": "dryRun",
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
},
|
||||
{
|
||||
"$ref": "#/parameters/fieldManager-7c6nTn1T"
|
||||
},
|
||||
{
|
||||
"description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
|
||||
"in": "query",
|
||||
"name": "fieldValidation",
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
},
|
||||
{
|
||||
"$ref": "#/parameters/force-tOGGb0Yi"
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml",
|
||||
"application/vnd.kubernetes.protobuf",
|
||||
"application/cbor"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
},
|
||||
"schemes": [
|
||||
"https"
|
||||
],
|
||||
"tags": [
|
||||
"resource_v1alpha3"
|
||||
],
|
||||
"x-kubernetes-action": "patch",
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"group": "resource.k8s.io",
|
||||
"kind": "DeviceTaintRule",
|
||||
"version": "v1alpha3"
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"consumes": [
|
||||
"*/*"
|
||||
],
|
||||
"description": "replace status of the specified DeviceTaintRule",
|
||||
"operationId": "replaceResourceV1alpha3DeviceTaintRuleStatus",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "body",
|
||||
"name": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
|
||||
"in": "query",
|
||||
"name": "dryRun",
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
},
|
||||
{
|
||||
"$ref": "#/parameters/fieldManager-Qy4HdaTW"
|
||||
},
|
||||
{
|
||||
"description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
|
||||
"in": "query",
|
||||
"name": "fieldValidation",
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json",
|
||||
"application/yaml",
|
||||
"application/vnd.kubernetes.protobuf",
|
||||
"application/cbor"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
},
|
||||
"schemes": [
|
||||
"https"
|
||||
],
|
||||
"tags": [
|
||||
"resource_v1alpha3"
|
||||
],
|
||||
"x-kubernetes-action": "put",
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"group": "resource.k8s.io",
|
||||
"kind": "DeviceTaintRule",
|
||||
"version": "v1alpha3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apis/resource.k8s.io/v1alpha3/watch/devicetaintrules": {
|
||||
"get": {
|
||||
"consumes": [
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@
|
|||
"description": "NodeSelector defines the nodes where the device is available.\n\nMust use exactly one term.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set."
|
||||
},
|
||||
"taints": {
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
|
|
@ -980,7 +980,7 @@
|
|||
"properties": {
|
||||
"effect": {
|
||||
"default": "",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
|
|
@ -1571,7 +1571,7 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
"devices": {
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,40 +1,12 @@
|
|||
{
|
||||
"components": {
|
||||
"schemas": {
|
||||
"io.k8s.api.resource.v1alpha3.CELDeviceSelector": {
|
||||
"description": "CELDeviceSelector contains a CEL expression for selecting a device.",
|
||||
"properties": {
|
||||
"expression": {
|
||||
"default": "",
|
||||
"description": "Expression is a CEL expression which evaluates a single device. It must evaluate to true when the device under consideration satisfies the desired criteria, and false when it does not. Any other result is an error and causes allocation of devices to abort.\n\nThe expression's input is an object named \"device\", which carries the following properties:\n - driver (string): the name of the driver which defines this device.\n - attributes (map[string]object): the device's attributes, grouped by prefix\n (e.g. device.attributes[\"dra.example.com\"] evaluates to an object with all\n of the attributes which were prefixed by \"dra.example.com\".\n - capacity (map[string]object): the device's capacities, grouped by prefix.\n\nExample: Consider a device with driver=\"dra.example.com\", which exposes two attributes named \"model\" and \"ext.example.com/family\" and which exposes one capacity named \"modules\". This input to this expression would have the following fields:\n\n device.driver\n device.attributes[\"dra.example.com\"].model\n device.attributes[\"ext.example.com\"].family\n device.capacity[\"dra.example.com\"].modules\n\nThe device.driver field can be used to check for a specific driver, either as a high-level precondition (i.e. you only want to consider devices from this driver) or as part of a multi-clause expression that is meant to consider devices from different drivers.\n\nThe value type of each attribute is defined by the device definition, and users who write these expressions must consult the documentation for their specific drivers. The value type of each capacity is Quantity.\n\nIf an unknown prefix is used as a lookup in either device.attributes or device.capacity, an empty map will be returned. Any reference to an unknown field will cause an evaluation error and allocation to abort.\n\nA robust expression should check for the existence of attributes before referencing them.\n\nFor ease of use, the cel.bind() function is enabled, and can be used to simplify expressions that access multiple attributes with the same domain. For example:\n\n cel.bind(dra, device.attributes[\"dra.example.com\"], dra.someBool && dra.anotherBool)\n\nThe length of the expression must be smaller or equal to 10 Ki. The cost of evaluating it is also limited based on the estimated number of logical steps.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"expression"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.resource.v1alpha3.DeviceSelector": {
|
||||
"description": "DeviceSelector must have exactly one field set.",
|
||||
"properties": {
|
||||
"cel": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.CELDeviceSelector"
|
||||
}
|
||||
],
|
||||
"description": "CEL contains a CEL expression for selecting a device."
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.resource.v1alpha3.DeviceTaint": {
|
||||
"description": "The device this taint is attached to has the \"effect\" on any claim which does not tolerate the taint and, through the claim, to pods using the claim.",
|
||||
"properties": {
|
||||
"effect": {
|
||||
"default": "",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
|
|
@ -89,6 +61,15 @@
|
|||
],
|
||||
"default": {},
|
||||
"description": "Spec specifies the selector and one taint.\n\nChanging the spec automatically increments the metadata.generation number."
|
||||
},
|
||||
"status": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRuleStatus"
|
||||
}
|
||||
],
|
||||
"default": {},
|
||||
"description": "Status provides information about what was requested in the spec."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
@ -157,7 +138,7 @@
|
|||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintSelector"
|
||||
}
|
||||
],
|
||||
"description": "DeviceSelector defines which device(s) the taint is applied to. All selector criteria must be satified for a device to match. The empty selector matches all devices. Without a selector, no devices are matches."
|
||||
"description": "DeviceSelector defines which device(s) the taint is applied to. All selector criteria must be satisfied for a device to match. The empty selector matches all devices. Without a selector, no devices are matches."
|
||||
},
|
||||
"taint": {
|
||||
"allOf": [
|
||||
|
|
@ -174,6 +155,30 @@
|
|||
],
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.resource.v1alpha3.DeviceTaintRuleStatus": {
|
||||
"description": "DeviceTaintRuleStatus provides information about an on-going pod eviction.",
|
||||
"properties": {
|
||||
"conditions": {
|
||||
"description": "Conditions provide information about the state of the DeviceTaintRule and the cluster at some point in time, in a machine-readable and human-readable format.\n\nThe following condition is currently defined as part of this API, more may get added: - Type: EvictionInProgress - Status: True if there are currently pods which need to be evicted, False otherwise\n (includes the effects which don't cause eviction).\n- Reason: not specified, may change - Message: includes information about number of pending pods and already evicted pods\n in a human-readable format, updated periodically, may change\n\nFor `effect: None`, the condition above gets set once for each change to the spec, with the message containing information about what would happen if the effect was `NoExecute`. This feedback can be used to decide whether changing the effect to `NoExecute` will work as intended. It only gets set once to avoid having to constantly update the status.\n\nMust have 8 or fewer entries.",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Condition"
|
||||
}
|
||||
],
|
||||
"default": {}
|
||||
},
|
||||
"type": "array",
|
||||
"x-kubernetes-list-map-keys": [
|
||||
"type"
|
||||
],
|
||||
"x-kubernetes-list-type": "map",
|
||||
"x-kubernetes-patch-merge-key": "type",
|
||||
"x-kubernetes-patch-strategy": "merge"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.api.resource.v1alpha3.DeviceTaintSelector": {
|
||||
"description": "DeviceTaintSelector defines which device(s) a DeviceTaintRule applies to. The empty selector matches all devices. Without a selector, no devices are matched.",
|
||||
"properties": {
|
||||
|
|
@ -181,10 +186,6 @@
|
|||
"description": "If device is set, only devices with that name are selected. This field corresponds to slice.spec.devices[].name.\n\nSetting also driver and pool may be required to avoid ambiguity, but is not required.",
|
||||
"type": "string"
|
||||
},
|
||||
"deviceClassName": {
|
||||
"description": "If DeviceClassName is set, the selectors defined there must be satisfied by a device to be selected. This field corresponds to class.metadata.name.",
|
||||
"type": "string"
|
||||
},
|
||||
"driver": {
|
||||
"description": "If driver is set, only devices from that driver are selected. This fields corresponds to slice.spec.driver.",
|
||||
"type": "string"
|
||||
|
|
@ -192,19 +193,6 @@
|
|||
"pool": {
|
||||
"description": "If pool is set, only devices in that pool are selected.\n\nAlso setting the driver name may be useful to avoid ambiguity when different drivers use the same pool name, but this is not required because selecting pools from different drivers may also be useful, for example when drivers with node-local devices use the node name as their pool name.",
|
||||
"type": "string"
|
||||
},
|
||||
"selectors": {
|
||||
"description": "Selectors contains the same selection criteria as a ResourceClaim. Currently, CEL expressions are supported. All of these selectors must be satisfied.",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceSelector"
|
||||
}
|
||||
],
|
||||
"default": {}
|
||||
},
|
||||
"type": "array",
|
||||
"x-kubernetes-list-type": "atomic"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
|
|
@ -323,6 +311,52 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"io.k8s.apimachinery.pkg.apis.meta.v1.Condition": {
|
||||
"description": "Condition contains details for one aspect of the current state of this API Resource.",
|
||||
"properties": {
|
||||
"lastTransitionTime": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Time"
|
||||
}
|
||||
],
|
||||
"description": "lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable."
|
||||
},
|
||||
"message": {
|
||||
"default": "",
|
||||
"description": "message is a human readable message indicating details about the transition. This may be an empty string.",
|
||||
"type": "string"
|
||||
},
|
||||
"observedGeneration": {
|
||||
"description": "observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.",
|
||||
"format": "int64",
|
||||
"type": "integer"
|
||||
},
|
||||
"reason": {
|
||||
"default": "",
|
||||
"description": "reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.",
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"default": "",
|
||||
"description": "status of the condition, one of True, False, Unknown.",
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"default": "",
|
||||
"description": "type of condition in CamelCase or in foo.example.com/CamelCase.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"status",
|
||||
"lastTransitionTime",
|
||||
"reason",
|
||||
"message"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"io.k8s.apimachinery.pkg.apis.meta.v1.DeleteOptions": {
|
||||
"description": "DeleteOptions may be provided when deleting an API object.",
|
||||
"properties": {
|
||||
|
|
@ -2334,6 +2368,315 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/apis/resource.k8s.io/v1alpha3/devicetaintrules/{name}/status": {
|
||||
"get": {
|
||||
"description": "read status of the specified DeviceTaintRule",
|
||||
"operationId": "readResourceV1alpha3DeviceTaintRuleStatus",
|
||||
"responses": {
|
||||
"200": {
|
||||
"content": {
|
||||
"application/cbor": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/vnd.kubernetes.protobuf": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/yaml": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "OK"
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"resource_v1alpha3"
|
||||
],
|
||||
"x-kubernetes-action": "get",
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"group": "resource.k8s.io",
|
||||
"kind": "DeviceTaintRule",
|
||||
"version": "v1alpha3"
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"description": "name of the DeviceTaintRule",
|
||||
"in": "path",
|
||||
"name": "name",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget).",
|
||||
"in": "query",
|
||||
"name": "pretty",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"patch": {
|
||||
"description": "partially update status of the specified DeviceTaintRule",
|
||||
"operationId": "patchResourceV1alpha3DeviceTaintRuleStatus",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
|
||||
"in": "query",
|
||||
"name": "dryRun",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch).",
|
||||
"in": "query",
|
||||
"name": "fieldManager",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
|
||||
"in": "query",
|
||||
"name": "fieldValidation",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Force is going to \"force\" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests.",
|
||||
"in": "query",
|
||||
"name": "force",
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"uniqueItems": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/apply-patch+cbor": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
|
||||
}
|
||||
},
|
||||
"application/apply-patch+yaml": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
|
||||
}
|
||||
},
|
||||
"application/json-patch+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
|
||||
}
|
||||
},
|
||||
"application/merge-patch+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
|
||||
}
|
||||
},
|
||||
"application/strategic-merge-patch+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.apimachinery.pkg.apis.meta.v1.Patch"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"content": {
|
||||
"application/cbor": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/vnd.kubernetes.protobuf": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/yaml": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "OK"
|
||||
},
|
||||
"201": {
|
||||
"content": {
|
||||
"application/cbor": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/vnd.kubernetes.protobuf": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/yaml": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Created"
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"resource_v1alpha3"
|
||||
],
|
||||
"x-kubernetes-action": "patch",
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"group": "resource.k8s.io",
|
||||
"kind": "DeviceTaintRule",
|
||||
"version": "v1alpha3"
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"description": "replace status of the specified DeviceTaintRule",
|
||||
"operationId": "replaceResourceV1alpha3DeviceTaintRuleStatus",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed",
|
||||
"in": "query",
|
||||
"name": "dryRun",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.",
|
||||
"in": "query",
|
||||
"name": "fieldManager",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.",
|
||||
"in": "query",
|
||||
"name": "fieldValidation",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"uniqueItems": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"*/*": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"content": {
|
||||
"application/cbor": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/vnd.kubernetes.protobuf": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/yaml": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "OK"
|
||||
},
|
||||
"201": {
|
||||
"content": {
|
||||
"application/cbor": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/vnd.kubernetes.protobuf": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
},
|
||||
"application/yaml": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/io.k8s.api.resource.v1alpha3.DeviceTaintRule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Created"
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"resource_v1alpha3"
|
||||
],
|
||||
"x-kubernetes-action": "put",
|
||||
"x-kubernetes-group-version-kind": {
|
||||
"group": "resource.k8s.io",
|
||||
"kind": "DeviceTaintRule",
|
||||
"version": "v1alpha3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apis/resource.k8s.io/v1alpha3/watch/devicetaintrules": {
|
||||
"get": {
|
||||
"description": "watch individual changes to a list of DeviceTaintRule. deprecated: use the 'watch' parameter with a list operation instead.",
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@
|
|||
"description": "NodeSelector defines the nodes where the device is available.\n\nMust use exactly one term.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set."
|
||||
},
|
||||
"taints": {
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
|
|
@ -1038,7 +1038,7 @@
|
|||
"properties": {
|
||||
"effect": {
|
||||
"default": "",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
|
|
@ -1568,7 +1568,7 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
"devices": {
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@
|
|||
"description": "NodeSelector defines the nodes where the device is available.\n\nMust use exactly one term.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set."
|
||||
},
|
||||
"taints": {
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"description": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
|
|
@ -980,7 +980,7 @@
|
|||
"properties": {
|
||||
"effect": {
|
||||
"default": "",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"description": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"type": "string"
|
||||
},
|
||||
"key": {
|
||||
|
|
@ -1571,7 +1571,7 @@
|
|||
"type": "boolean"
|
||||
},
|
||||
"devices": {
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
"description": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ func newDeviceTaintEvictionController(ctx context.Context, controllerContext Con
|
|||
controllerName,
|
||||
)
|
||||
return newControllerLoop(func(ctx context.Context) {
|
||||
if err := deviceTaintEvictionController.Run(ctx); err != nil {
|
||||
if err := deviceTaintEvictionController.Run(ctx, int(controllerContext.ComponentConfig.DeviceTaintEvictionController.ConcurrentSyncs)); err != nil {
|
||||
klog.FromContext(ctx).Error(err, "Device taint processing leading to Pod eviction failed and is now paused")
|
||||
}
|
||||
<-ctx.Done()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright 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 options
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
devicetaintevictionconfig "k8s.io/kubernetes/pkg/controller/devicetainteviction/config"
|
||||
)
|
||||
|
||||
// DeviceTaintEvictionControllerOptions holds the DeviceTaintEvictionController options.
|
||||
type DeviceTaintEvictionControllerOptions struct {
|
||||
*devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration
|
||||
}
|
||||
|
||||
// AddFlags adds flags related to DeviceTaintEvictionController for controller manager to the specified FlagSet.
|
||||
func (o *DeviceTaintEvictionControllerOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
if o == nil {
|
||||
return
|
||||
}
|
||||
|
||||
fs.Int32Var(&o.ConcurrentSyncs, "concurrent-device-taint-eviction-syncs", o.ConcurrentSyncs, "The number of operations (evicting pods, updating DeviceTaintRule status) allowed to run concurrently. Greater number = more responsive, but more CPU (and network) load")
|
||||
}
|
||||
|
||||
// ApplyTo fills up DeviceTaintEvictionController config with options.
|
||||
func (o *DeviceTaintEvictionControllerOptions) ApplyTo(cfg *devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration) error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
cfg.ConcurrentSyncs = o.ConcurrentSyncs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate checks validation of DeviceTaintEvictionControllerOptions.
|
||||
func (o *DeviceTaintEvictionControllerOptions) Validate() []error {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var errs []error
|
||||
if o.ConcurrentSyncs <= 0 {
|
||||
errs = append(errs, fmt.Errorf("concurrent-device-taint-eviction-syncs must be greater than zero, got %d", o.ConcurrentSyncs))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
Copyright 2025 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 options
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
|
||||
devicetaintevictionconfig "k8s.io/kubernetes/pkg/controller/devicetainteviction/config"
|
||||
)
|
||||
|
||||
func TestDeviceTaintEvictionControllerOptions_AddFlags(t *testing.T) {
|
||||
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||
opts := &DeviceTaintEvictionControllerOptions{
|
||||
&devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{
|
||||
ConcurrentSyncs: 50,
|
||||
},
|
||||
}
|
||||
|
||||
opts.AddFlags(fs)
|
||||
|
||||
// Test that the flag was added
|
||||
flag := fs.Lookup("concurrent-device-taint-eviction-syncs")
|
||||
if flag == nil {
|
||||
t.Error("concurrent-device-taint-eviction-syncs flag was not added")
|
||||
return
|
||||
}
|
||||
|
||||
// Test that the flag has the correct default value
|
||||
if flag.DefValue != "50" {
|
||||
t.Errorf("expected default value 50, got %s", flag.DefValue)
|
||||
}
|
||||
|
||||
// Test flag parsing
|
||||
args := []string{"--concurrent-device-taint-eviction-syncs=25"}
|
||||
if err := fs.Parse(args); err != nil {
|
||||
t.Errorf("failed to parse flags: %v", err)
|
||||
}
|
||||
|
||||
if opts.ConcurrentSyncs != 25 {
|
||||
t.Errorf("expected ConcurrentSyncs to be 25, got %d", opts.ConcurrentSyncs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTaintEvictionControllerOptions_AddFlags_Nil(t *testing.T) {
|
||||
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||
var opts *DeviceTaintEvictionControllerOptions
|
||||
|
||||
// Should not panic when options is nil
|
||||
opts.AddFlags(fs)
|
||||
|
||||
// Flag should not be added
|
||||
flag := fs.Lookup("concurrent-device-taint-eviction-syncs")
|
||||
if flag != nil {
|
||||
t.Error("concurrent-device-taint-eviction-syncs flag should not be added when options is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTaintEvictionControllerOptions_ApplyTo(t *testing.T) {
|
||||
opts := &DeviceTaintEvictionControllerOptions{
|
||||
&devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{
|
||||
ConcurrentSyncs: 75,
|
||||
},
|
||||
}
|
||||
|
||||
cfg := &devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{}
|
||||
|
||||
err := opts.ApplyTo(cfg)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if cfg.ConcurrentSyncs != 75 {
|
||||
t.Errorf("expected ConcurrentSyncs to be 75, got %d", cfg.ConcurrentSyncs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTaintEvictionControllerOptions_ApplyTo_Nil(t *testing.T) {
|
||||
var opts *DeviceTaintEvictionControllerOptions
|
||||
cfg := &devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{
|
||||
ConcurrentSyncs: 50,
|
||||
}
|
||||
|
||||
err := opts.ApplyTo(cfg)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Configuration should remain unchanged
|
||||
if cfg.ConcurrentSyncs != 50 {
|
||||
t.Errorf("expected ConcurrentSyncs to remain 50, got %d", cfg.ConcurrentSyncs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTaintEvictionControllerOptions_Validate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
concurrentSyncs int32
|
||||
expectErrors bool
|
||||
expectedErrorSubString string
|
||||
}{
|
||||
{
|
||||
name: "valid concurrent syncs",
|
||||
concurrentSyncs: 50,
|
||||
expectErrors: false,
|
||||
},
|
||||
{
|
||||
name: "valid minimum concurrent syncs",
|
||||
concurrentSyncs: 1,
|
||||
expectErrors: false,
|
||||
},
|
||||
{
|
||||
name: "invalid zero concurrent syncs",
|
||||
concurrentSyncs: 0,
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "concurrent-device-taint-eviction-syncs must be greater than zero, got 0",
|
||||
},
|
||||
{
|
||||
name: "invalid negative concurrent syncs",
|
||||
concurrentSyncs: -5,
|
||||
expectErrors: true,
|
||||
expectedErrorSubString: "concurrent-device-taint-eviction-syncs must be greater than zero, got -5",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
opts := &DeviceTaintEvictionControllerOptions{
|
||||
&devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{
|
||||
ConcurrentSyncs: tc.concurrentSyncs,
|
||||
},
|
||||
}
|
||||
|
||||
errs := opts.Validate()
|
||||
|
||||
if tc.expectErrors && len(errs) == 0 {
|
||||
t.Error("expected validation errors, but got none")
|
||||
}
|
||||
|
||||
if !tc.expectErrors && len(errs) > 0 {
|
||||
t.Errorf("expected no validation errors, but got: %v", errs)
|
||||
}
|
||||
|
||||
if tc.expectErrors && len(errs) > 0 {
|
||||
gotErr := utilerrors.NewAggregate(errs).Error()
|
||||
if !strings.Contains(gotErr, tc.expectedErrorSubString) {
|
||||
t.Errorf("expected error to contain %q, but got %q", tc.expectedErrorSubString, gotErr)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTaintEvictionControllerOptions_Validate_Nil(t *testing.T) {
|
||||
var opts *DeviceTaintEvictionControllerOptions
|
||||
|
||||
errs := opts.Validate()
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("expected no validation errors for nil options, but got: %v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTaintEvictionControllerOptions_Integration(t *testing.T) {
|
||||
// Test the complete workflow: create options, set flags, apply to config
|
||||
fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||
opts := &DeviceTaintEvictionControllerOptions{
|
||||
&devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{
|
||||
ConcurrentSyncs: 50,
|
||||
},
|
||||
}
|
||||
|
||||
// Add flags
|
||||
opts.AddFlags(fs)
|
||||
|
||||
// Parse flags with custom value
|
||||
args := []string{"--concurrent-device-taint-eviction-syncs=100"}
|
||||
if err := fs.Parse(args); err != nil {
|
||||
t.Fatalf("failed to parse flags: %v", err)
|
||||
}
|
||||
|
||||
// Validate
|
||||
errs := opts.Validate()
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("validation failed: %v", errs)
|
||||
}
|
||||
|
||||
// Apply to config
|
||||
cfg := &devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{}
|
||||
if err := opts.ApplyTo(cfg); err != nil {
|
||||
t.Fatalf("failed to apply options: %v", err)
|
||||
}
|
||||
|
||||
// Verify final configuration
|
||||
expected := &devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{
|
||||
ConcurrentSyncs: 100,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cfg, expected) {
|
||||
t.Errorf("expected config %+v, got %+v", expected, cfg)
|
||||
}
|
||||
}
|
||||
|
|
@ -77,6 +77,7 @@ type KubeControllerManagerOptions struct {
|
|||
CSRSigningController *CSRSigningControllerOptions
|
||||
DaemonSetController *DaemonSetControllerOptions
|
||||
DeploymentController *DeploymentControllerOptions
|
||||
DeviceTaintEvictionController *DeviceTaintEvictionControllerOptions
|
||||
StatefulSetController *StatefulSetControllerOptions
|
||||
DeprecatedFlags *DeprecatedControllerOptions
|
||||
EndpointController *EndpointControllerOptions
|
||||
|
|
@ -151,6 +152,9 @@ func NewKubeControllerManagerOptions() (*KubeControllerManagerOptions, error) {
|
|||
DeploymentController: &DeploymentControllerOptions{
|
||||
&componentConfig.DeploymentController,
|
||||
},
|
||||
DeviceTaintEvictionController: &DeviceTaintEvictionControllerOptions{
|
||||
&componentConfig.DeviceTaintEvictionController,
|
||||
},
|
||||
StatefulSetController: &StatefulSetControllerOptions{
|
||||
&componentConfig.StatefulSetController,
|
||||
},
|
||||
|
|
@ -272,6 +276,7 @@ func (s *KubeControllerManagerOptions) Flags(allControllers []string, disabledBy
|
|||
s.AttachDetachController.AddFlags(fss.FlagSet(names.PersistentVolumeAttachDetachController))
|
||||
s.CSRSigningController.AddFlags(fss.FlagSet(names.CertificateSigningRequestSigningController))
|
||||
s.DeploymentController.AddFlags(fss.FlagSet(names.DeploymentController))
|
||||
s.DeviceTaintEvictionController.AddFlags(fss.FlagSet(names.DeviceTaintEvictionController))
|
||||
s.StatefulSetController.AddFlags(fss.FlagSet(names.StatefulSetController))
|
||||
s.DaemonSetController.AddFlags(fss.FlagSet(names.DaemonSetController))
|
||||
s.DeprecatedFlags.AddFlags(fss.FlagSet("deprecated"))
|
||||
|
|
@ -341,6 +346,9 @@ func (s *KubeControllerManagerOptions) ApplyTo(c *kubecontrollerconfig.Config, a
|
|||
if err := s.DeploymentController.ApplyTo(&c.ComponentConfig.DeploymentController); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.DeviceTaintEvictionController.ApplyTo(&c.ComponentConfig.DeviceTaintEvictionController); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.StatefulSetController.ApplyTo(&c.ComponentConfig.StatefulSetController); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -440,6 +448,7 @@ func (s *KubeControllerManagerOptions) Validate(allControllers []string, disable
|
|||
errs = append(errs, s.CSRSigningController.Validate()...)
|
||||
errs = append(errs, s.DaemonSetController.Validate()...)
|
||||
errs = append(errs, s.DeploymentController.Validate()...)
|
||||
errs = append(errs, s.DeviceTaintEvictionController.Validate()...)
|
||||
errs = append(errs, s.StatefulSetController.Validate()...)
|
||||
errs = append(errs, s.DeprecatedFlags.Validate()...)
|
||||
errs = append(errs, s.EndpointController.Validate()...)
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import (
|
|||
cronjobconfig "k8s.io/kubernetes/pkg/controller/cronjob/config"
|
||||
daemonconfig "k8s.io/kubernetes/pkg/controller/daemon/config"
|
||||
deploymentconfig "k8s.io/kubernetes/pkg/controller/deployment/config"
|
||||
devicetaintevictionconfig "k8s.io/kubernetes/pkg/controller/devicetainteviction/config"
|
||||
endpointconfig "k8s.io/kubernetes/pkg/controller/endpoint/config"
|
||||
endpointsliceconfig "k8s.io/kubernetes/pkg/controller/endpointslice/config"
|
||||
endpointslicemirroringconfig "k8s.io/kubernetes/pkg/controller/endpointslicemirroring/config"
|
||||
|
|
@ -98,6 +99,7 @@ var args = []string{
|
|||
"--cluster-signing-legacy-unknown-cert-file=/cluster-signing-legacy-unknown/cert-file",
|
||||
"--cluster-signing-legacy-unknown-key-file=/cluster-signing-legacy-unknown/key-file",
|
||||
"--concurrent-deployment-syncs=10",
|
||||
"--concurrent-device-taint-eviction-syncs=10",
|
||||
"--concurrent-daemonset-syncs=10",
|
||||
"--concurrent-horizontal-pod-autoscaler-syncs=10",
|
||||
"--concurrent-statefulset-syncs=15",
|
||||
|
|
@ -273,6 +275,11 @@ func TestAddFlags(t *testing.T) {
|
|||
ConcurrentDeploymentSyncs: 10,
|
||||
},
|
||||
},
|
||||
DeviceTaintEvictionController: &DeviceTaintEvictionControllerOptions{
|
||||
&devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{
|
||||
ConcurrentSyncs: 10,
|
||||
},
|
||||
},
|
||||
StatefulSetController: &StatefulSetControllerOptions{
|
||||
&statefulsetconfig.StatefulSetControllerConfiguration{
|
||||
ConcurrentStatefulSetSyncs: 15,
|
||||
|
|
@ -624,6 +631,9 @@ func TestApplyTo(t *testing.T) {
|
|||
DeploymentController: deploymentconfig.DeploymentControllerConfiguration{
|
||||
ConcurrentDeploymentSyncs: 10,
|
||||
},
|
||||
DeviceTaintEvictionController: devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{
|
||||
ConcurrentSyncs: 10,
|
||||
},
|
||||
StatefulSetController: statefulsetconfig.StatefulSetControllerConfiguration{
|
||||
ConcurrentStatefulSetSyncs: 15,
|
||||
},
|
||||
|
|
@ -1262,6 +1272,15 @@ func TestValidateControllersOptions(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DeviceTaintEvictionControllerOptions",
|
||||
expectErrors: false,
|
||||
options: &DeviceTaintEvictionControllerOptions{
|
||||
&devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration{
|
||||
ConcurrentSyncs: 10,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DeprecatedControllerOptions",
|
||||
expectErrors: false,
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ type ResourceSliceSpec struct {
|
|||
|
||||
// Devices lists some or all of the devices in this pool.
|
||||
//
|
||||
// Must not have more than 128 entries.
|
||||
// Must not have more than 128 entries. If any device uses taints the limit is 64.
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
|
|
@ -243,6 +243,7 @@ type ResourcePool struct {
|
|||
|
||||
const ResourceSliceMaxSharedCapacity = 128
|
||||
const ResourceSliceMaxDevices = 128
|
||||
const ResourceSliceMaxDevicesWithTaints = 64
|
||||
const PoolNameMaxLength = validation.DNS1123SubdomainMaxLength // Same as for a single node name.
|
||||
const BindingConditionsMaxSize = 4
|
||||
const BindingFailureConditionsMaxSize = 4
|
||||
|
|
@ -326,7 +327,9 @@ type Device struct {
|
|||
|
||||
// If specified, these are the driver-defined taints.
|
||||
//
|
||||
// The maximum number of taints is 4.
|
||||
// The maximum number of taints is 16. If taints are set for
|
||||
// any device in a ResourceSlice, then the maximum number of
|
||||
// allowed devices per ResourceSlice is 64 instead of 128.
|
||||
//
|
||||
// This is an alpha field and requires enabling the DRADeviceTaints
|
||||
// feature gate.
|
||||
|
|
@ -601,8 +604,8 @@ type DeviceAttribute struct {
|
|||
// DeviceAttributeMaxValueLength is the maximum length of a string or version attribute value.
|
||||
const DeviceAttributeMaxValueLength = 64
|
||||
|
||||
// DeviceTaintsMaxLength is the maximum number of taints per device.
|
||||
const DeviceTaintsMaxLength = 4
|
||||
// DeviceTaintsMaxLength is the maximum number of taints per Device.
|
||||
const DeviceTaintsMaxLength = 16
|
||||
|
||||
// The device this taint is attached to has the "effect" on
|
||||
// any claim which does not tolerate the taint and, through the claim,
|
||||
|
|
@ -622,8 +625,10 @@ type DeviceTaint struct {
|
|||
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
//
|
||||
// +required
|
||||
Effect DeviceTaintEffect
|
||||
|
|
@ -632,6 +637,14 @@ type DeviceTaint struct {
|
|||
//
|
||||
// Implementing PreferNoSchedule would depend on a scoring solution for DRA.
|
||||
// It might get added as part of that.
|
||||
//
|
||||
// A possible future new effect is NoExecuteWithPodDisruptionBudget:
|
||||
// honor the pod disruption budget instead of simply deleting pods.
|
||||
// This is currently undecided, it could also be a separate field.
|
||||
//
|
||||
// Validation must be prepared to allow unknown enums in stored objects,
|
||||
// which will enable adding new enums within a single release without
|
||||
// ratcheting.
|
||||
|
||||
// TimeAdded represents the time at which the taint was added.
|
||||
// Added automatically during create or update if not set.
|
||||
|
|
@ -650,6 +663,9 @@ type DeviceTaint struct {
|
|||
type DeviceTaintEffect string
|
||||
|
||||
const (
|
||||
// No effect, the taint is purely informational.
|
||||
DeviceTaintEffectNone DeviceTaintEffect = "None"
|
||||
|
||||
// Do not allow new pods to schedule which use a tainted device unless they tolerate the taint,
|
||||
// but allow all pods submitted to Kubelet without going through the scheduler
|
||||
// to start, and allow all already-running pods to continue running.
|
||||
|
|
@ -1876,18 +1892,16 @@ type DeviceTaintRule struct {
|
|||
// Changing the spec automatically increments the metadata.generation number.
|
||||
Spec DeviceTaintRuleSpec
|
||||
|
||||
// ^^^
|
||||
// A spec gets added because adding a status seems likely.
|
||||
// Such a status could provide feedback on applying the
|
||||
// eviction and/or statistics (number of matching devices,
|
||||
// affected allocated claims, pods remaining to be evicted,
|
||||
// etc.).
|
||||
// Status provides information about what was requested in the spec.
|
||||
//
|
||||
// +optional
|
||||
Status DeviceTaintRuleStatus
|
||||
}
|
||||
|
||||
// DeviceTaintRuleSpec specifies the selector and one taint.
|
||||
type DeviceTaintRuleSpec struct {
|
||||
// DeviceSelector defines which device(s) the taint is applied to.
|
||||
// All selector criteria must be satified for a device to
|
||||
// All selector criteria must be satisfied for a device to
|
||||
// match. The empty selector matches all devices. Without
|
||||
// a selector, no devices are matches.
|
||||
//
|
||||
|
|
@ -1904,13 +1918,6 @@ type DeviceTaintRuleSpec struct {
|
|||
// The empty selector matches all devices. Without a selector, no devices
|
||||
// are matched.
|
||||
type DeviceTaintSelector struct {
|
||||
// If DeviceClassName is set, the selectors defined there must be
|
||||
// satisfied by a device to be selected. This field corresponds
|
||||
// to class.metadata.name.
|
||||
//
|
||||
// +optional
|
||||
DeviceClassName *string
|
||||
|
||||
// If driver is set, only devices from that driver are selected.
|
||||
// This fields corresponds to slice.spec.driver.
|
||||
//
|
||||
|
|
@ -1937,16 +1944,43 @@ type DeviceTaintSelector struct {
|
|||
//
|
||||
// +optional
|
||||
Device *string
|
||||
}
|
||||
|
||||
// Selectors contains the same selection criteria as a ResourceClaim.
|
||||
// Currently, CEL expressions are supported. All of these selectors
|
||||
// must be satisfied.
|
||||
// DeviceTaintRuleStatus provides information about an on-going pod eviction.
|
||||
type DeviceTaintRuleStatus struct {
|
||||
// Conditions provide information about the state of the DeviceTaintRule
|
||||
// and the cluster at some point in time,
|
||||
// in a machine-readable and human-readable format.
|
||||
//
|
||||
// The following condition is currently defined as part of this API, more may
|
||||
// get added:
|
||||
// - Type: EvictionInProgress
|
||||
// - Status: True if there are currently pods which need to be evicted, False otherwise
|
||||
// (includes the effects which don't cause eviction).
|
||||
// - Reason: not specified, may change
|
||||
// - Message: includes information about number of pending pods and already evicted pods
|
||||
// in a human-readable format, updated periodically, may change
|
||||
//
|
||||
// For `effect: None`, the condition above gets set once for each change to
|
||||
// the spec, with the message containing information about what would happen
|
||||
// if the effect was `NoExecute`. This feedback can be used to decide whether
|
||||
// changing the effect to `NoExecute` will work as intended. It only gets
|
||||
// set once to avoid having to constantly update the status.
|
||||
//
|
||||
// Must have 8 or less entries.
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
Selectors []DeviceSelector
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
Conditions []metav1.Condition
|
||||
}
|
||||
|
||||
// DeviceTaintRuleStatusMaxConditions is the maximum number of conditions in DeviceTaintRuleStatus.
|
||||
const DeviceTaintRuleStatusMaxConditions = 8
|
||||
|
||||
// DeviceTaintConditionEvictionInProgress is the publicly documented condition type for the DeviceTaintRuleStatus.
|
||||
const DeviceTaintConditionEvictionInProgress = "EvictionInProgress"
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// DeviceTaintRuleList is a collection of DeviceTaintRules.
|
||||
|
|
|
|||
2
pkg/apis/resource/v1/zz_generated.validations.go
generated
2
pkg/apis/resource/v1/zz_generated.validations.go
generated
|
|
@ -1237,7 +1237,7 @@ func Validate_DeviceTaint(ctx context.Context, op operation.Operation, fldPath *
|
|||
return errs
|
||||
}
|
||||
|
||||
var symbolsForDeviceTaintEffect = sets.New(resourcev1.DeviceTaintEffectNoExecute, resourcev1.DeviceTaintEffectNoSchedule)
|
||||
var symbolsForDeviceTaintEffect = sets.New(resourcev1.DeviceTaintEffectNoExecute, resourcev1.DeviceTaintEffectNoSchedule, resourcev1.DeviceTaintEffectNone)
|
||||
|
||||
// Validate_DeviceTaintEffect validates an instance of DeviceTaintEffect according
|
||||
// to declarative validation rules in the API schema.
|
||||
|
|
|
|||
|
|
@ -98,6 +98,16 @@ func RegisterConversions(s *runtime.Scheme) error {
|
|||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*resourcev1alpha3.DeviceTaintRuleStatus)(nil), (*resource.DeviceTaintRuleStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha3_DeviceTaintRuleStatus_To_resource_DeviceTaintRuleStatus(a.(*resourcev1alpha3.DeviceTaintRuleStatus), b.(*resource.DeviceTaintRuleStatus), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*resource.DeviceTaintRuleStatus)(nil), (*resourcev1alpha3.DeviceTaintRuleStatus)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_resource_DeviceTaintRuleStatus_To_v1alpha3_DeviceTaintRuleStatus(a.(*resource.DeviceTaintRuleStatus), b.(*resourcev1alpha3.DeviceTaintRuleStatus), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*resourcev1alpha3.DeviceTaintSelector)(nil), (*resource.DeviceTaintSelector)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha3_DeviceTaintSelector_To_resource_DeviceTaintSelector(a.(*resourcev1alpha3.DeviceTaintSelector), b.(*resource.DeviceTaintSelector), scope)
|
||||
}); err != nil {
|
||||
|
|
@ -182,6 +192,9 @@ func autoConvert_v1alpha3_DeviceTaintRule_To_resource_DeviceTaintRule(in *resour
|
|||
if err := Convert_v1alpha3_DeviceTaintRuleSpec_To_resource_DeviceTaintRuleSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_v1alpha3_DeviceTaintRuleStatus_To_resource_DeviceTaintRuleStatus(&in.Status, &out.Status, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -195,6 +208,9 @@ func autoConvert_resource_DeviceTaintRule_To_v1alpha3_DeviceTaintRule(in *resour
|
|||
if err := Convert_resource_DeviceTaintRuleSpec_To_v1alpha3_DeviceTaintRuleSpec(&in.Spec, &out.Spec, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_resource_DeviceTaintRuleStatus_To_v1alpha3_DeviceTaintRuleStatus(&in.Status, &out.Status, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -251,12 +267,30 @@ func Convert_resource_DeviceTaintRuleSpec_To_v1alpha3_DeviceTaintRuleSpec(in *re
|
|||
return autoConvert_resource_DeviceTaintRuleSpec_To_v1alpha3_DeviceTaintRuleSpec(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha3_DeviceTaintRuleStatus_To_resource_DeviceTaintRuleStatus(in *resourcev1alpha3.DeviceTaintRuleStatus, out *resource.DeviceTaintRuleStatus, s conversion.Scope) error {
|
||||
out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha3_DeviceTaintRuleStatus_To_resource_DeviceTaintRuleStatus is an autogenerated conversion function.
|
||||
func Convert_v1alpha3_DeviceTaintRuleStatus_To_resource_DeviceTaintRuleStatus(in *resourcev1alpha3.DeviceTaintRuleStatus, out *resource.DeviceTaintRuleStatus, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha3_DeviceTaintRuleStatus_To_resource_DeviceTaintRuleStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_resource_DeviceTaintRuleStatus_To_v1alpha3_DeviceTaintRuleStatus(in *resource.DeviceTaintRuleStatus, out *resourcev1alpha3.DeviceTaintRuleStatus, s conversion.Scope) error {
|
||||
out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_resource_DeviceTaintRuleStatus_To_v1alpha3_DeviceTaintRuleStatus is an autogenerated conversion function.
|
||||
func Convert_resource_DeviceTaintRuleStatus_To_v1alpha3_DeviceTaintRuleStatus(in *resource.DeviceTaintRuleStatus, out *resourcev1alpha3.DeviceTaintRuleStatus, s conversion.Scope) error {
|
||||
return autoConvert_resource_DeviceTaintRuleStatus_To_v1alpha3_DeviceTaintRuleStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha3_DeviceTaintSelector_To_resource_DeviceTaintSelector(in *resourcev1alpha3.DeviceTaintSelector, out *resource.DeviceTaintSelector, s conversion.Scope) error {
|
||||
out.DeviceClassName = (*string)(unsafe.Pointer(in.DeviceClassName))
|
||||
out.Driver = (*string)(unsafe.Pointer(in.Driver))
|
||||
out.Pool = (*string)(unsafe.Pointer(in.Pool))
|
||||
out.Device = (*string)(unsafe.Pointer(in.Device))
|
||||
out.Selectors = *(*[]resource.DeviceSelector)(unsafe.Pointer(&in.Selectors))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -266,11 +300,9 @@ func Convert_v1alpha3_DeviceTaintSelector_To_resource_DeviceTaintSelector(in *re
|
|||
}
|
||||
|
||||
func autoConvert_resource_DeviceTaintSelector_To_v1alpha3_DeviceTaintSelector(in *resource.DeviceTaintSelector, out *resourcev1alpha3.DeviceTaintSelector, s conversion.Scope) error {
|
||||
out.DeviceClassName = (*string)(unsafe.Pointer(in.DeviceClassName))
|
||||
out.Driver = (*string)(unsafe.Pointer(in.Driver))
|
||||
out.Pool = (*string)(unsafe.Pointer(in.Pool))
|
||||
out.Device = (*string)(unsafe.Pointer(in.Device))
|
||||
out.Selectors = *(*[]resourcev1alpha3.DeviceSelector)(unsafe.Pointer(&in.Selectors))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1331,7 +1331,7 @@ func Validate_DeviceTaint(ctx context.Context, op operation.Operation, fldPath *
|
|||
return errs
|
||||
}
|
||||
|
||||
var symbolsForDeviceTaintEffect = sets.New(resourcev1beta1.DeviceTaintEffectNoExecute, resourcev1beta1.DeviceTaintEffectNoSchedule)
|
||||
var symbolsForDeviceTaintEffect = sets.New(resourcev1beta1.DeviceTaintEffectNoExecute, resourcev1beta1.DeviceTaintEffectNoSchedule, resourcev1beta1.DeviceTaintEffectNone)
|
||||
|
||||
// Validate_DeviceTaintEffect validates an instance of DeviceTaintEffect according
|
||||
// to declarative validation rules in the API schema.
|
||||
|
|
|
|||
|
|
@ -1261,7 +1261,7 @@ func Validate_DeviceTaint(ctx context.Context, op operation.Operation, fldPath *
|
|||
return errs
|
||||
}
|
||||
|
||||
var symbolsForDeviceTaintEffect = sets.New(resourcev1beta2.DeviceTaintEffectNoExecute, resourcev1beta2.DeviceTaintEffectNoSchedule)
|
||||
var symbolsForDeviceTaintEffect = sets.New(resourcev1beta2.DeviceTaintEffectNoExecute, resourcev1beta2.DeviceTaintEffectNoSchedule, resourcev1beta2.DeviceTaintEffectNone)
|
||||
|
||||
// Validate_DeviceTaintEffect validates an instance of DeviceTaintEffect according
|
||||
// to declarative validation rules in the API schema.
|
||||
|
|
|
|||
|
|
@ -704,9 +704,14 @@ func validateResourceSliceSpec(spec, oldSpec *resource.ResourceSliceSpec, fldPat
|
|||
}
|
||||
|
||||
sharedCounterToCounterNames := gatherSharedCounterCounterNames(spec.SharedCounters)
|
||||
allErrs = append(allErrs, validateSet(spec.Devices, resource.ResourceSliceMaxDevices,
|
||||
maxDevices := resource.ResourceSliceMaxDevices
|
||||
if haveDeviceTaints(spec) {
|
||||
maxDevices = resource.ResourceSliceMaxDevicesWithTaints
|
||||
}
|
||||
allErrs = append(allErrs, validateSet(spec.Devices, maxDevices,
|
||||
func(device resource.Device, fldPath *field.Path) field.ErrorList {
|
||||
return validateDevice(device, fldPath, sharedCounterToCounterNames, spec.PerDeviceNodeSelection)
|
||||
oldDevice := lookupDevice(oldSpec, device.Name)
|
||||
return validateDevice(device, oldDevice, fldPath, sharedCounterToCounterNames, spec.PerDeviceNodeSelection)
|
||||
},
|
||||
func(device resource.Device) string {
|
||||
return device.Name
|
||||
|
|
@ -740,6 +745,32 @@ func validateResourceSliceSpec(spec, oldSpec *resource.ResourceSliceSpec, fldPat
|
|||
return allErrs
|
||||
}
|
||||
|
||||
func haveDeviceTaints(spec *resource.ResourceSliceSpec) bool {
|
||||
if spec == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, device := range spec.Devices {
|
||||
if len(device.Taints) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func lookupDevice(spec *resource.ResourceSliceSpec, deviceName string) *resource.Device {
|
||||
if spec == nil {
|
||||
return nil
|
||||
}
|
||||
for i := range spec.Devices {
|
||||
device := &spec.Devices[i]
|
||||
if device.Name == deviceName {
|
||||
return device
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateCounterSet(counterSet resource.CounterSet, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
if counterSet.Name == "" {
|
||||
|
|
@ -782,7 +813,7 @@ func validateResourcePool(pool resource.ResourcePool, fldPath *field.Path) field
|
|||
return allErrs
|
||||
}
|
||||
|
||||
func validateDevice(device resource.Device, fldPath *field.Path, sharedCounterToCounterNames map[string]sets.Set[string], perDeviceNodeSelection *bool) field.ErrorList {
|
||||
func validateDevice(device resource.Device, oldDevice *resource.Device, fldPath *field.Path, sharedCounterToCounterNames map[string]sets.Set[string], perDeviceNodeSelection *bool) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
allowMultipleAllocations := device.AllowMultipleAllocations != nil && *device.AllowMultipleAllocations
|
||||
allErrs = append(allErrs, validateDeviceName(device.Name, fldPath.Child("name"))...)
|
||||
|
|
@ -799,7 +830,15 @@ func validateDevice(device resource.Device, fldPath *field.Path, sharedCounterTo
|
|||
} else {
|
||||
allErrs = append(allErrs, validateMap(device.Capacity, -1, attributeAndCapacityMaxKeyLength, validateQualifiedName, validateSingleAllocatableDeviceCapacity, fldPath.Child("capacity"))...)
|
||||
}
|
||||
allErrs = append(allErrs, validateSlice(device.Taints, resource.DeviceTaintsMaxLength, validateDeviceTaint, fldPath.Child("taints"))...)
|
||||
// If the entire set is the same as before then validation can be skipped.
|
||||
// We could also do the DeepEqual on the entire spec, but here it is a bit cheaper.
|
||||
if oldDevice == nil || !apiequality.Semantic.DeepEqual(oldDevice.Taints, device.Taints) {
|
||||
allErrs = append(allErrs, validateSlice(device.Taints, resource.DeviceTaintsMaxLength,
|
||||
func(taint resource.DeviceTaint, fldPath *field.Path) field.ErrorList {
|
||||
return validateDeviceTaint(taint, nil, fldPath)
|
||||
},
|
||||
fldPath.Child("taints"))...)
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, validateSet(device.ConsumesCounters, -1,
|
||||
validateDeviceCounterConsumption,
|
||||
|
|
@ -1362,7 +1401,11 @@ func validateDeviceTaintRuleSpec(spec, oldSpec *resource.DeviceTaintRuleSpec, fl
|
|||
oldFilter = oldSpec.DeviceSelector // +k8s:verify-mutation:reason=clone
|
||||
}
|
||||
allErrs = append(allErrs, validateDeviceTaintSelector(spec.DeviceSelector, oldFilter, fldPath.Child("deviceSelector"))...)
|
||||
allErrs = append(allErrs, validateDeviceTaint(spec.Taint, fldPath.Child("taint"))...)
|
||||
var oldTaint *resource.DeviceTaint
|
||||
if oldSpec != nil {
|
||||
oldTaint = &oldSpec.Taint // +k8s:verify-mutation:reason=clone
|
||||
}
|
||||
allErrs = append(allErrs, validateDeviceTaint(spec.Taint, oldTaint, fldPath.Child("taint"))...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
|
@ -1372,9 +1415,6 @@ func validateDeviceTaintSelector(filter, oldFilter *resource.DeviceTaintSelector
|
|||
if filter == nil {
|
||||
return allErrs
|
||||
}
|
||||
if filter.DeviceClassName != nil {
|
||||
allErrs = append(allErrs, validateDeviceClassName(*filter.DeviceClassName, fldPath.Child("deviceClassName"))...)
|
||||
}
|
||||
if filter.Driver != nil {
|
||||
allErrs = append(allErrs, validateDriverName(*filter.Driver, fldPath.Child("driver"))...)
|
||||
}
|
||||
|
|
@ -1385,37 +1425,26 @@ func validateDeviceTaintSelector(filter, oldFilter *resource.DeviceTaintSelector
|
|||
allErrs = append(allErrs, validateDeviceName(*filter.Device, fldPath.Child("device"))...)
|
||||
}
|
||||
|
||||
// If the selectors are exactly as before, we treat the CEL expressions as "stored".
|
||||
// Any change, including merely reordering selectors, triggers validation as new
|
||||
// expressions.
|
||||
stored := false
|
||||
if oldFilter != nil {
|
||||
stored = apiequality.Semantic.DeepEqual(filter.Selectors, oldFilter.Selectors)
|
||||
}
|
||||
allErrs = append(allErrs, validateSlice(filter.Selectors, resource.DeviceSelectorsMaxSize,
|
||||
func(selector resource.DeviceSelector, fldPath *field.Path) field.ErrorList {
|
||||
return validateSelector(selector, fldPath, stored)
|
||||
},
|
||||
fldPath.Child("selectors"))...)
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
var validDeviceTolerationOperators = []resource.DeviceTolerationOperator{resource.DeviceTolerationOpEqual, resource.DeviceTolerationOpExists}
|
||||
var validDeviceTaintEffects = sets.New(resource.DeviceTaintEffectNoSchedule, resource.DeviceTaintEffectNoExecute)
|
||||
var validDeviceTaintEffects = sets.New(resource.DeviceTaintEffectNoSchedule, resource.DeviceTaintEffectNoExecute, resource.DeviceTaintEffectNone)
|
||||
|
||||
func validateDeviceTaint(taint resource.DeviceTaint, fldPath *field.Path) field.ErrorList {
|
||||
func validateDeviceTaint(taint resource.DeviceTaint, oldTaint *resource.DeviceTaint, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
allErrs = append(allErrs, metav1validation.ValidateLabelName(taint.Key, fldPath.Child("key"))...) // Includes checking for non-empty.
|
||||
if taint.Value != "" {
|
||||
allErrs = append(allErrs, validateLabelValue(taint.Value, fldPath.Child("value"))...)
|
||||
}
|
||||
switch {
|
||||
case taint.Effect == "":
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("effect"), "").MarkCoveredByDeclarative()) // Required in a taint.
|
||||
case !validDeviceTaintEffects.Has(taint.Effect):
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("effect"), taint.Effect, sets.List(validDeviceTaintEffects)).MarkCoveredByDeclarative())
|
||||
if oldTaint == nil || oldTaint.Effect != taint.Effect {
|
||||
switch {
|
||||
case taint.Effect == "":
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("effect"), "").MarkCoveredByDeclarative()) // Required in a taint.
|
||||
case !validDeviceTaintEffects.Has(taint.Effect):
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("effect"), taint.Effect, sets.List(validDeviceTaintEffects)).MarkCoveredByDeclarative())
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
|
|
@ -1498,3 +1527,17 @@ func validateDeviceBindingParameters(bindingConditions, bindingFailureConditions
|
|||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateDeviceTaintRuleStatusUpdate tests if a DeviceTaintRule status update is valid.
|
||||
func ValidateDeviceTaintRuleStatusUpdate(rule, oldRule *resource.DeviceTaintRule) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
|
||||
fldPath := field.NewPath("status")
|
||||
allErrs = corevalidation.ValidateObjectMetaUpdate(&rule.ObjectMeta, &oldRule.ObjectMeta, field.NewPath("metadata")) // Covers invalid name changes.
|
||||
allErrs = append(allErrs, metav1validation.ValidateConditions(rule.Status.Conditions, fldPath.Child("conditions"))...)
|
||||
if len(rule.Status.Conditions) > resource.DeviceTaintRuleStatusMaxConditions {
|
||||
allErrs = append(allErrs, field.TooMany(fldPath.Child("conditions"), len(rule.Status.Conditions), resource.DeviceTaintRuleStatusMaxConditions))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
package validation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
|
@ -37,10 +36,9 @@ func testDeviceTaintRule(name string, spec resourceapi.DeviceTaintRuleSpec) *res
|
|||
|
||||
var validDeviceTaintRuleSpec = resourceapi.DeviceTaintRuleSpec{
|
||||
DeviceSelector: &resourceapi.DeviceTaintSelector{
|
||||
DeviceClassName: ptr.To(goodName),
|
||||
Driver: ptr.To("test.example.com"),
|
||||
Pool: ptr.To(goodName),
|
||||
Device: ptr.To(goodName),
|
||||
Driver: ptr.To("test.example.com"),
|
||||
Pool: ptr.To(goodName),
|
||||
Device: ptr.To(goodName),
|
||||
},
|
||||
Taint: resourceapi.DeviceTaint{
|
||||
Key: "example.com/taint",
|
||||
|
|
@ -187,14 +185,6 @@ func TestValidateDeviceTaint(t *testing.T) {
|
|||
return taintRule
|
||||
}(),
|
||||
},
|
||||
"bad-class": {
|
||||
wantFailures: field.ErrorList{field.Invalid(field.NewPath("spec", "deviceSelector", "deviceClassName"), badName, "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')")},
|
||||
taintRule: func() *resourceapi.DeviceTaintRule {
|
||||
taintRule := testDeviceTaintRule(goodName, validDeviceTaintRuleSpec)
|
||||
taintRule.Spec.DeviceSelector.DeviceClassName = ptr.To(badName)
|
||||
return taintRule
|
||||
}(),
|
||||
},
|
||||
"bad-driver": {
|
||||
wantFailures: field.ErrorList{field.Invalid(field.NewPath("spec", "deviceSelector", "driver"), badName, "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')")},
|
||||
taintRule: func() *resourceapi.DeviceTaintRule {
|
||||
|
|
@ -219,70 +209,7 @@ func TestValidateDeviceTaint(t *testing.T) {
|
|||
return taintRule
|
||||
}(),
|
||||
},
|
||||
"CEL-compile-errors": {
|
||||
wantFailures: field.ErrorList{
|
||||
field.Invalid(field.NewPath("spec", "deviceSelector", "selectors").Index(1).Child("cel", "expression"), `device.attributes[true].someBoolean`, "compilation failed: ERROR: <input>:1:18: found no matching overload for '_[_]' applied to '(map(string, map(string, any)), bool)'\n | device.attributes[true].someBoolean\n | .................^"),
|
||||
},
|
||||
taintRule: func() *resourceapi.DeviceTaintRule {
|
||||
taintRule := testDeviceTaintRule(goodName, validDeviceTaintRuleSpec)
|
||||
taintRule.Spec.DeviceSelector.Selectors = []resourceapi.DeviceSelector{
|
||||
{
|
||||
// Good selector.
|
||||
CEL: &resourceapi.CELDeviceSelector{
|
||||
Expression: `device.driver == "dra.example.com"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Bad selector.
|
||||
CEL: &resourceapi.CELDeviceSelector{
|
||||
Expression: `device.attributes[true].someBoolean`,
|
||||
},
|
||||
},
|
||||
}
|
||||
return taintRule
|
||||
}(),
|
||||
},
|
||||
"CEL-length": {
|
||||
wantFailures: field.ErrorList{
|
||||
field.TooLong(field.NewPath("spec", "deviceSelector", "selectors").Index(1).Child("cel", "expression"), "" /*unused*/, resourceapi.CELSelectorExpressionMaxLength),
|
||||
},
|
||||
taintRule: func() *resourceapi.DeviceTaintRule {
|
||||
taintRule := testDeviceTaintRule(goodName, validDeviceTaintRuleSpec)
|
||||
expression := `device.driver == ""`
|
||||
taintRule.Spec.DeviceSelector.Selectors = []resourceapi.DeviceSelector{
|
||||
{
|
||||
// Good selector.
|
||||
CEL: &resourceapi.CELDeviceSelector{
|
||||
Expression: strings.ReplaceAll(expression, `""`, `"`+strings.Repeat("x", resourceapi.CELSelectorExpressionMaxLength-len(expression))+`"`),
|
||||
},
|
||||
},
|
||||
{
|
||||
// Too long by one selector.
|
||||
CEL: &resourceapi.CELDeviceSelector{
|
||||
Expression: strings.ReplaceAll(expression, `""`, `"`+strings.Repeat("x", resourceapi.CELSelectorExpressionMaxLength-len(expression)+1)+`"`),
|
||||
},
|
||||
},
|
||||
}
|
||||
return taintRule
|
||||
}(),
|
||||
},
|
||||
"CEL-cost": {
|
||||
wantFailures: field.ErrorList{
|
||||
field.Forbidden(field.NewPath("spec", "deviceSelector", "selectors").Index(0).Child("cel", "expression"), "too complex, exceeds cost limit"),
|
||||
},
|
||||
taintRule: func() *resourceapi.DeviceTaintRule {
|
||||
claim := testDeviceTaintRule(goodName, validDeviceTaintRuleSpec)
|
||||
claim.Spec.DeviceSelector.Selectors = []resourceapi.DeviceSelector{
|
||||
{
|
||||
CEL: &resourceapi.CELDeviceSelector{
|
||||
// From https://github.com/kubernetes/kubernetes/blob/50fc400f178d2078d0ca46aee955ee26375fc437/test/integration/apiserver/cel/validatingadmissionpolicy_test.go#L2150.
|
||||
Expression: `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].all(x, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].all(y, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].all(z, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].all(z2, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].all(z3, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].all(z4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].all(z5, int('1'.find('[0-9]*')) < 100)))))))`,
|
||||
},
|
||||
},
|
||||
}
|
||||
return claim
|
||||
}(),
|
||||
},
|
||||
// Minimal tests for DeviceTaint. Full coverage of validateDeviceTaint is in ResourceSlice test.
|
||||
"valid-taint": {
|
||||
taintRule: func() *resourceapi.DeviceTaintRule {
|
||||
claim := testDeviceTaintRule(goodName, validDeviceTaintRuleSpec)
|
||||
|
|
@ -294,20 +221,33 @@ func TestValidateDeviceTaint(t *testing.T) {
|
|||
return claim
|
||||
}(),
|
||||
},
|
||||
"invalid-taint": {
|
||||
"required-taint": {
|
||||
wantFailures: field.ErrorList{
|
||||
field.Required(field.NewPath("spec", "taint", "effect"), "").MarkCoveredByDeclarative(),
|
||||
},
|
||||
taintRule: func() *resourceapi.DeviceTaintRule {
|
||||
claim := testDeviceTaintRule(goodName, validDeviceTaintRuleSpec)
|
||||
claim.Spec.Taint = resourceapi.DeviceTaint{
|
||||
// Minimal test. Full coverage of validateDeviceTaint is in ResourceSlice test.
|
||||
Key: goodName,
|
||||
Value: goodName,
|
||||
}
|
||||
return claim
|
||||
}(),
|
||||
},
|
||||
"invalid-taint": {
|
||||
wantFailures: field.ErrorList{
|
||||
field.NotSupported(field.NewPath("spec", "taint", "effect"), resourceapi.DeviceTaintEffect("some-other-effect"), []resourceapi.DeviceTaintEffect{resourceapi.DeviceTaintEffectNoExecute, resourceapi.DeviceTaintEffectNoSchedule, resourceapi.DeviceTaintEffectNone}).MarkCoveredByDeclarative(),
|
||||
},
|
||||
taintRule: func() *resourceapi.DeviceTaintRule {
|
||||
claim := testDeviceTaintRule(goodName, validDeviceTaintRuleSpec)
|
||||
claim.Spec.Taint = resourceapi.DeviceTaint{
|
||||
Effect: "some-other-effect",
|
||||
Key: goodName,
|
||||
Value: goodName,
|
||||
}
|
||||
return claim
|
||||
}(),
|
||||
},
|
||||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
|
|
@ -321,6 +261,8 @@ func TestValidateDeviceTaint(t *testing.T) {
|
|||
func TestValidateDeviceTaintUpdate(t *testing.T) {
|
||||
name := "valid"
|
||||
validTaintRule := testDeviceTaintRule(name, validDeviceTaintRuleSpec)
|
||||
invalidTaintEffectRule := validTaintRule.DeepCopy()
|
||||
invalidTaintEffectRule.Spec.Taint.Effect = "some-other-effect"
|
||||
|
||||
scenarios := map[string]struct {
|
||||
old *resourceapi.DeviceTaintRule
|
||||
|
|
@ -339,6 +281,21 @@ func TestValidateDeviceTaintUpdate(t *testing.T) {
|
|||
return taintRule
|
||||
},
|
||||
},
|
||||
"valid-existing-unknown-effect": {
|
||||
old: invalidTaintEffectRule,
|
||||
update: func(taintRule *resourceapi.DeviceTaintRule) *resourceapi.DeviceTaintRule {
|
||||
taintRule.Labels = map[string]string{"a": "b"}
|
||||
return taintRule
|
||||
},
|
||||
},
|
||||
"invalid-new-unknown-effect": {
|
||||
wantFailures: field.ErrorList{field.NotSupported(field.NewPath("spec", "taint", "effect"), resourceapi.DeviceTaintEffect("some-other-effect"), []resourceapi.DeviceTaintEffect{resourceapi.DeviceTaintEffectNoExecute, resourceapi.DeviceTaintEffectNoSchedule, resourceapi.DeviceTaintEffectNone})}.MarkCoveredByDeclarative(),
|
||||
old: validTaintRule,
|
||||
update: func(taintRule *resourceapi.DeviceTaintRule) *resourceapi.DeviceTaintRule {
|
||||
taintRule.Spec.Taint.Effect = "some-other-effect"
|
||||
return taintRule
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
|
|
|
|||
|
|
@ -824,7 +824,7 @@ func TestValidateClaim(t *testing.T) {
|
|||
|
||||
field.Invalid(fldPath.Index(5).Child("key"), badName, "name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')").MarkCoveredByDeclarative(),
|
||||
field.Invalid(fldPath.Index(5).Child("value"), badName, "a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyValue', or 'my_value', or '12345', regex used for validation is '(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?')"),
|
||||
field.NotSupported(fldPath.Index(5).Child("effect"), resource.DeviceTaintEffect("some-other-effect"), []resource.DeviceTaintEffect{resource.DeviceTaintEffectNoExecute, resource.DeviceTaintEffectNoSchedule}).MarkCoveredByDeclarative(),
|
||||
field.NotSupported(fldPath.Index(5).Child("effect"), resource.DeviceTaintEffect("some-other-effect"), []resource.DeviceTaintEffect{resource.DeviceTaintEffectNoExecute, resource.DeviceTaintEffectNoSchedule, resource.DeviceTaintEffectNone}).MarkCoveredByDeclarative(),
|
||||
)
|
||||
return allErrs
|
||||
}(),
|
||||
|
|
|
|||
|
|
@ -108,6 +108,25 @@ func TestValidateResourceSlice(t *testing.T) {
|
|||
wantFailures: field.ErrorList{field.TooMany(field.NewPath("spec", "devices"), resourceapi.ResourceSliceMaxDevices+1, resourceapi.ResourceSliceMaxDevices)},
|
||||
slice: testResourceSlice(goodName, goodName, goodName, resourceapi.ResourceSliceMaxDevices+1),
|
||||
},
|
||||
"good-taints": {
|
||||
slice: func() *resourceapi.ResourceSlice {
|
||||
slice := testResourceSlice(goodName, goodName, goodName, resourceapi.ResourceSliceMaxDevicesWithTaints)
|
||||
for i := range slice.Spec.Devices {
|
||||
slice.Spec.Devices[i].Taints = []resourceapi.DeviceTaint{{Key: "example.com/taint", Effect: resourceapi.DeviceTaintEffectNoExecute}}
|
||||
}
|
||||
return slice
|
||||
}(),
|
||||
},
|
||||
"too-large-taints": {
|
||||
wantFailures: field.ErrorList{field.TooMany(field.NewPath("spec", "devices"), resourceapi.ResourceSliceMaxDevicesWithTaints+1, resourceapi.ResourceSliceMaxDevicesWithTaints)},
|
||||
slice: func() *resourceapi.ResourceSlice {
|
||||
slice := testResourceSlice(goodName, goodName, goodName, resourceapi.ResourceSliceMaxDevicesWithTaints+1)
|
||||
for i := range slice.Spec.Devices {
|
||||
slice.Spec.Devices[i].Taints = []resourceapi.DeviceTaint{{Key: "example.com/taint", Effect: resourceapi.DeviceTaintEffectNoExecute}}
|
||||
}
|
||||
return slice
|
||||
}(),
|
||||
},
|
||||
"missing-name": {
|
||||
wantFailures: field.ErrorList{field.Required(field.NewPath("metadata", "name"), "name or generateName is required")},
|
||||
slice: testResourceSlice("", goodName, driverName, 1),
|
||||
|
|
@ -497,7 +516,7 @@ func TestValidateResourceSlice(t *testing.T) {
|
|||
|
||||
field.Invalid(fldPath.Index(3).Child("key"), badName, "name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')"),
|
||||
field.Invalid(fldPath.Index(3).Child("value"), badName, "a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyValue', or 'my_value', or '12345', regex used for validation is '(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?')"),
|
||||
field.NotSupported(fldPath.Index(3).Child("effect"), resourceapi.DeviceTaintEffect("some-other-op"), []resourceapi.DeviceTaintEffect{resourceapi.DeviceTaintEffectNoExecute, resourceapi.DeviceTaintEffectNoSchedule}).MarkCoveredByDeclarative(),
|
||||
field.NotSupported(fldPath.Index(3).Child("effect"), resourceapi.DeviceTaintEffect("some-other-effect"), []resourceapi.DeviceTaintEffect{resourceapi.DeviceTaintEffectNoExecute, resourceapi.DeviceTaintEffectNoSchedule, resourceapi.DeviceTaintEffectNone}).MarkCoveredByDeclarative(),
|
||||
}
|
||||
}(),
|
||||
slice: func() *resourceapi.ResourceSlice {
|
||||
|
|
@ -522,7 +541,7 @@ func TestValidateResourceSlice(t *testing.T) {
|
|||
// Invalid strings.
|
||||
Key: badName,
|
||||
Value: badName,
|
||||
Effect: "some-other-op",
|
||||
Effect: "some-other-effect",
|
||||
},
|
||||
}
|
||||
return slice
|
||||
|
|
@ -867,6 +886,17 @@ func TestValidateResourceSlice(t *testing.T) {
|
|||
func TestValidateResourceSliceUpdate(t *testing.T) {
|
||||
name := "valid"
|
||||
validResourceSlice := testResourceSlice(name, name, name, 1)
|
||||
invalidResourceSliceWithTaints := validResourceSlice.DeepCopy()
|
||||
invalidResourceSliceWithTaints.Spec.Devices[0].Taints = []resourceapi.DeviceTaint{
|
||||
{
|
||||
Key: "unhealthy-power",
|
||||
Effect: resourceapi.DeviceTaintEffectNoExecute,
|
||||
},
|
||||
{
|
||||
Key: "unhealthy-mem",
|
||||
Effect: "some-other-effect",
|
||||
},
|
||||
}
|
||||
|
||||
scenarios := map[string]struct {
|
||||
oldResourceSlice *resourceapi.ResourceSlice
|
||||
|
|
@ -938,6 +968,31 @@ func TestValidateResourceSliceUpdate(t *testing.T) {
|
|||
return slice
|
||||
},
|
||||
},
|
||||
"invalid-new-effect-in-old-device": {
|
||||
wantFailures: field.ErrorList{field.NotSupported(field.NewPath("spec", "devices").Index(0).Child("taints").Index(1).Child("effect"), resourceapi.DeviceTaintEffect("some-other-effect"), []resourceapi.DeviceTaintEffect{resourceapi.DeviceTaintEffectNoExecute, resourceapi.DeviceTaintEffectNoSchedule, resourceapi.DeviceTaintEffectNone})}.MarkCoveredByDeclarative(),
|
||||
oldResourceSlice: validResourceSlice,
|
||||
update: func(slice *resourceapi.ResourceSlice) *resourceapi.ResourceSlice {
|
||||
slice.Spec.Devices[0].Taints = invalidResourceSliceWithTaints.Spec.Devices[0].Taints
|
||||
return slice
|
||||
},
|
||||
},
|
||||
"valid-old-effect": {
|
||||
oldResourceSlice: invalidResourceSliceWithTaints,
|
||||
update: func(slice *resourceapi.ResourceSlice) *resourceapi.ResourceSlice {
|
||||
slice.Spec.Devices[0].Attributes["foo"] = resourceapi.DeviceAttribute{StringValue: ptr.To("bar")}
|
||||
return slice
|
||||
},
|
||||
},
|
||||
"invalid-new-effect-in-new-device": {
|
||||
wantFailures: field.ErrorList{field.NotSupported(field.NewPath("spec", "devices").Index(1).Child("taints").Index(1).Child("effect"), resourceapi.DeviceTaintEffect("some-other-effect"), []resourceapi.DeviceTaintEffect{resourceapi.DeviceTaintEffectNoExecute, resourceapi.DeviceTaintEffectNoSchedule, resourceapi.DeviceTaintEffectNone})}.MarkCoveredByDeclarative(),
|
||||
oldResourceSlice: invalidResourceSliceWithTaints,
|
||||
update: func(slice *resourceapi.ResourceSlice) *resourceapi.ResourceSlice {
|
||||
device := slice.Spec.Devices[0].DeepCopy()
|
||||
device.Name += "-other"
|
||||
slice.Spec.Devices = append(slice.Spec.Devices, *device)
|
||||
return slice
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
|
|
|
|||
36
pkg/apis/resource/zz_generated.deepcopy.go
generated
36
pkg/apis/resource/zz_generated.deepcopy.go
generated
|
|
@ -831,6 +831,7 @@ func (in *DeviceTaintRule) DeepCopyInto(out *DeviceTaintRule) {
|
|||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -907,14 +908,32 @@ func (in *DeviceTaintRuleSpec) DeepCopy() *DeviceTaintRuleSpec {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeviceTaintRuleStatus) DeepCopyInto(out *DeviceTaintRuleStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeviceTaintRuleStatus.
|
||||
func (in *DeviceTaintRuleStatus) DeepCopy() *DeviceTaintRuleStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeviceTaintRuleStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeviceTaintSelector) DeepCopyInto(out *DeviceTaintSelector) {
|
||||
*out = *in
|
||||
if in.DeviceClassName != nil {
|
||||
in, out := &in.DeviceClassName, &out.DeviceClassName
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.Driver != nil {
|
||||
in, out := &in.Driver, &out.Driver
|
||||
*out = new(string)
|
||||
|
|
@ -930,13 +949,6 @@ func (in *DeviceTaintSelector) DeepCopyInto(out *DeviceTaintSelector) {
|
|||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.Selectors != nil {
|
||||
in, out := &in.Selectors, &out.Selectors
|
||||
*out = make([]DeviceSelector, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
cronjobconfig "k8s.io/kubernetes/pkg/controller/cronjob/config"
|
||||
daemonconfig "k8s.io/kubernetes/pkg/controller/daemon/config"
|
||||
deploymentconfig "k8s.io/kubernetes/pkg/controller/deployment/config"
|
||||
devicetaintevictionconfig "k8s.io/kubernetes/pkg/controller/devicetainteviction/config"
|
||||
endpointconfig "k8s.io/kubernetes/pkg/controller/endpoint/config"
|
||||
endpointsliceconfig "k8s.io/kubernetes/pkg/controller/endpointslice/config"
|
||||
endpointslicemirroringconfig "k8s.io/kubernetes/pkg/controller/endpointslicemirroring/config"
|
||||
|
|
@ -62,6 +63,9 @@ type KubeControllerManagerConfiguration struct {
|
|||
// AttachDetachControllerConfiguration holds configuration for
|
||||
// AttachDetachController related features.
|
||||
AttachDetachController attachdetachconfig.AttachDetachControllerConfiguration
|
||||
// CronJobControllerConfiguration holds configuration for CronJobController
|
||||
// related features.
|
||||
CronJobController cronjobconfig.CronJobControllerConfiguration
|
||||
// CSRSigningControllerConfiguration holds configuration for
|
||||
// CSRSigningController related features.
|
||||
CSRSigningController csrsigningconfig.CSRSigningControllerConfiguration
|
||||
|
|
@ -71,9 +75,8 @@ type KubeControllerManagerConfiguration struct {
|
|||
// DeploymentControllerConfiguration holds configuration for
|
||||
// DeploymentController related features.
|
||||
DeploymentController deploymentconfig.DeploymentControllerConfiguration
|
||||
// StatefulSetControllerConfiguration holds configuration for
|
||||
// StatefulSetController related features.
|
||||
StatefulSetController statefulsetconfig.StatefulSetControllerConfiguration
|
||||
// DeviceTaintEvictionControllerConfiguration contains elements configuring the device taint eviction controller.
|
||||
DeviceTaintEvictionController devicetaintevictionconfig.DeviceTaintEvictionControllerConfiguration
|
||||
// DeprecatedControllerConfiguration holds configuration for some deprecated
|
||||
// features.
|
||||
DeprecatedController DeprecatedControllerConfiguration
|
||||
|
|
@ -96,9 +99,6 @@ type KubeControllerManagerConfiguration struct {
|
|||
HPAController poautosclerconfig.HPAControllerConfiguration
|
||||
// JobControllerConfiguration holds configuration for JobController related features.
|
||||
JobController jobconfig.JobControllerConfiguration
|
||||
// CronJobControllerConfiguration holds configuration for CronJobController
|
||||
// related features.
|
||||
CronJobController cronjobconfig.CronJobControllerConfiguration
|
||||
// LegacySATokenCleanerConfiguration holds configuration for LegacySATokenCleaner related features.
|
||||
LegacySATokenCleaner serviceaccountconfig.LegacySATokenCleanerConfiguration
|
||||
// NamespaceControllerConfiguration holds configuration for NamespaceController
|
||||
|
|
@ -130,6 +130,9 @@ type KubeControllerManagerConfiguration struct {
|
|||
// ServiceControllerConfiguration holds configuration for ServiceController
|
||||
// related features.
|
||||
ServiceController serviceconfig.ServiceControllerConfiguration
|
||||
// StatefulSetControllerConfiguration holds configuration for
|
||||
// StatefulSetController related features.
|
||||
StatefulSetController statefulsetconfig.StatefulSetControllerConfiguration
|
||||
// TTLAfterFinishedControllerConfiguration holds configuration for
|
||||
// TTLAfterFinishedController related features.
|
||||
TTLAfterFinishedController ttlafterfinishedconfig.TTLAfterFinishedControllerConfiguration
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import (
|
|||
cronjobconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/cronjob/config/v1alpha1"
|
||||
daemonconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/daemon/config/v1alpha1"
|
||||
deploymentconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/deployment/config/v1alpha1"
|
||||
devicetaintevictionconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/devicetainteviction/config/v1alpha1"
|
||||
endpointconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/endpoint/config/v1alpha1"
|
||||
endpointsliceconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/endpointslice/config/v1alpha1"
|
||||
endpointslicemirroringconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/endpointslicemirroring/config/v1alpha1"
|
||||
|
|
@ -71,6 +72,8 @@ func SetDefaults_KubeControllerManagerConfiguration(obj *kubectrlmgrconfigv1alph
|
|||
daemonconfigv1alpha1.RecommendedDefaultDaemonSetControllerConfiguration(&obj.DaemonSetController)
|
||||
// Use the default RecommendedDefaultDeploymentControllerConfiguration options
|
||||
deploymentconfigv1alpha1.RecommendedDefaultDeploymentControllerConfiguration(&obj.DeploymentController)
|
||||
// Use the default RecommendedDefaultDeviceTaintEvictionControllerConfiguration options
|
||||
devicetaintevictionconfigv1alpha1.RecommendedDefaultDeviceTaintEvictionControllerConfiguration(&obj.DeviceTaintEvictionController)
|
||||
// Use the default RecommendedDefaultStatefulSetControllerConfiguration options
|
||||
statefulsetconfigv1alpha1.RecommendedDefaultStatefulSetControllerConfiguration(&obj.StatefulSetController)
|
||||
// Use the default RecommendedDefaultEndpointControllerConfiguration options
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import (
|
|||
cronjobconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/cronjob/config/v1alpha1"
|
||||
daemonconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/daemon/config/v1alpha1"
|
||||
deploymentconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/deployment/config/v1alpha1"
|
||||
devicetaintevictionconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/devicetainteviction/config/v1alpha1"
|
||||
endpointconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/endpoint/config/v1alpha1"
|
||||
endpointsliceconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/endpointslice/config/v1alpha1"
|
||||
endpointslicemirroringconfigv1alpha1 "k8s.io/kubernetes/pkg/controller/endpointslicemirroring/config/v1alpha1"
|
||||
|
|
@ -224,6 +225,9 @@ func autoConvert_v1alpha1_KubeControllerManagerConfiguration_To_config_KubeContr
|
|||
if err := validatingadmissionpolicystatusconfigv1alpha1.Convert_v1alpha1_ValidatingAdmissionPolicyStatusControllerConfiguration_To_config_ValidatingAdmissionPolicyStatusControllerConfiguration(&in.ValidatingAdmissionPolicyStatusController, &out.ValidatingAdmissionPolicyStatusController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := devicetaintevictionconfigv1alpha1.Convert_v1alpha1_DeviceTaintEvictionControllerConfiguration_To_config_DeviceTaintEvictionControllerConfiguration(&in.DeviceTaintEvictionController, &out.DeviceTaintEvictionController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -242,6 +246,9 @@ func autoConvert_config_KubeControllerManagerConfiguration_To_v1alpha1_KubeContr
|
|||
if err := attachdetachconfigv1alpha1.Convert_config_AttachDetachControllerConfiguration_To_v1alpha1_AttachDetachControllerConfiguration(&in.AttachDetachController, &out.AttachDetachController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cronjobconfigv1alpha1.Convert_config_CronJobControllerConfiguration_To_v1alpha1_CronJobControllerConfiguration(&in.CronJobController, &out.CronJobController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := signerconfigv1alpha1.Convert_config_CSRSigningControllerConfiguration_To_v1alpha1_CSRSigningControllerConfiguration(&in.CSRSigningController, &out.CSRSigningController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -251,7 +258,7 @@ func autoConvert_config_KubeControllerManagerConfiguration_To_v1alpha1_KubeContr
|
|||
if err := deploymentconfigv1alpha1.Convert_config_DeploymentControllerConfiguration_To_v1alpha1_DeploymentControllerConfiguration(&in.DeploymentController, &out.DeploymentController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := statefulsetconfigv1alpha1.Convert_config_StatefulSetControllerConfiguration_To_v1alpha1_StatefulSetControllerConfiguration(&in.StatefulSetController, &out.StatefulSetController, s); err != nil {
|
||||
if err := devicetaintevictionconfigv1alpha1.Convert_config_DeviceTaintEvictionControllerConfiguration_To_v1alpha1_DeviceTaintEvictionControllerConfiguration(&in.DeviceTaintEvictionController, &out.DeviceTaintEvictionController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := Convert_config_DeprecatedControllerConfiguration_To_v1alpha1_DeprecatedControllerConfiguration(&in.DeprecatedController, &out.DeprecatedController, s); err != nil {
|
||||
|
|
@ -278,9 +285,6 @@ func autoConvert_config_KubeControllerManagerConfiguration_To_v1alpha1_KubeContr
|
|||
if err := jobconfigv1alpha1.Convert_config_JobControllerConfiguration_To_v1alpha1_JobControllerConfiguration(&in.JobController, &out.JobController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cronjobconfigv1alpha1.Convert_config_CronJobControllerConfiguration_To_v1alpha1_CronJobControllerConfiguration(&in.CronJobController, &out.CronJobController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := serviceaccountconfigv1alpha1.Convert_config_LegacySATokenCleanerConfiguration_To_v1alpha1_LegacySATokenCleanerConfiguration(&in.LegacySATokenCleaner, &out.LegacySATokenCleaner, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -314,6 +318,9 @@ func autoConvert_config_KubeControllerManagerConfiguration_To_v1alpha1_KubeContr
|
|||
if err := serviceconfigv1alpha1.Convert_config_ServiceControllerConfiguration_To_v1alpha1_ServiceControllerConfiguration(&in.ServiceController, &out.ServiceController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := statefulsetconfigv1alpha1.Convert_config_StatefulSetControllerConfiguration_To_v1alpha1_StatefulSetControllerConfiguration(&in.StatefulSetController, &out.StatefulSetController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ttlafterfinishedconfigv1alpha1.Convert_config_TTLAfterFinishedControllerConfiguration_To_v1alpha1_TTLAfterFinishedControllerConfiguration(&in.TTLAfterFinishedController, &out.TTLAfterFinishedController, s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,10 +48,11 @@ func (in *KubeControllerManagerConfiguration) DeepCopyInto(out *KubeControllerMa
|
|||
in.Generic.DeepCopyInto(&out.Generic)
|
||||
out.KubeCloudShared = in.KubeCloudShared
|
||||
out.AttachDetachController = in.AttachDetachController
|
||||
out.CronJobController = in.CronJobController
|
||||
out.CSRSigningController = in.CSRSigningController
|
||||
out.DaemonSetController = in.DaemonSetController
|
||||
out.DeploymentController = in.DeploymentController
|
||||
out.StatefulSetController = in.StatefulSetController
|
||||
out.DeviceTaintEvictionController = in.DeviceTaintEvictionController
|
||||
out.DeprecatedController = in.DeprecatedController
|
||||
out.EndpointController = in.EndpointController
|
||||
out.EndpointSliceController = in.EndpointSliceController
|
||||
|
|
@ -60,7 +61,6 @@ func (in *KubeControllerManagerConfiguration) DeepCopyInto(out *KubeControllerMa
|
|||
in.GarbageCollectorController.DeepCopyInto(&out.GarbageCollectorController)
|
||||
out.HPAController = in.HPAController
|
||||
out.JobController = in.JobController
|
||||
out.CronJobController = in.CronJobController
|
||||
out.LegacySATokenCleaner = in.LegacySATokenCleaner
|
||||
out.NamespaceController = in.NamespaceController
|
||||
out.NodeIPAMController = in.NodeIPAMController
|
||||
|
|
@ -72,6 +72,7 @@ func (in *KubeControllerManagerConfiguration) DeepCopyInto(out *KubeControllerMa
|
|||
out.ResourceQuotaController = in.ResourceQuotaController
|
||||
out.SAController = in.SAController
|
||||
out.ServiceController = in.ServiceController
|
||||
out.StatefulSetController = in.StatefulSetController
|
||||
out.TTLAfterFinishedController = in.TTLAfterFinishedController
|
||||
out.ValidatingAdmissionPolicyStatusController = in.ValidatingAdmissionPolicyStatusController
|
||||
return
|
||||
|
|
|
|||
19
pkg/controller/devicetainteviction/config/doc.go
Normal file
19
pkg/controller/devicetainteviction/config/doc.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
package config
|
||||
26
pkg/controller/devicetainteviction/config/types.go
Normal file
26
pkg/controller/devicetainteviction/config/types.go
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Copyright 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 config
|
||||
|
||||
// DeviceTaintEvictionControllerConfiguration contains elements configuring the device taint eviction controller.
|
||||
type DeviceTaintEvictionControllerConfiguration struct {
|
||||
// ConcurrentSyncs is the number of operations (deleting a pod, updating a ResourcClaim status, etc.)
|
||||
// that will be done concurrently. Larger number = processing, but more CPU (and network) load.
|
||||
//
|
||||
// The default is 10.
|
||||
ConcurrentSyncs int32
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Copyright 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 v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/kube-controller-manager/config/v1alpha1"
|
||||
"k8s.io/kubernetes/pkg/controller/devicetainteviction/config"
|
||||
)
|
||||
|
||||
// Important! The public back-and-forth conversion functions for the types in this package
|
||||
// with DeviceTaintEvictionControllerConfiguration types need to be manually exposed like this in order for
|
||||
// other packages that reference this package to be able to call these conversion functions
|
||||
// in an autogenerated manner.
|
||||
// TODO: Fix the bug in conversion-gen so it automatically discovers these Convert_* functions
|
||||
// in autogenerated code as well.
|
||||
|
||||
// Convert_v1alpha1_DeviceTaintEvictionControllerConfiguration_To_config_DeviceTaintEvictionControllerConfiguration is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_DeviceTaintEvictionControllerConfiguration_To_config_DeviceTaintEvictionControllerConfiguration(in *v1alpha1.DeviceTaintEvictionControllerConfiguration, out *config.DeviceTaintEvictionControllerConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_DeviceTaintEvictionControllerConfiguration_To_config_DeviceTaintEvictionControllerConfiguration(in, out, s)
|
||||
}
|
||||
|
||||
// Convert_config_DeviceTaintEvictionControllerConfiguration_To_v1alpha1_DeviceTaintEvictionControllerConfiguration is an autogenerated conversion function.
|
||||
func Convert_config_DeviceTaintEvictionControllerConfiguration_To_v1alpha1_DeviceTaintEvictionControllerConfiguration(in *config.DeviceTaintEvictionControllerConfiguration, out *v1alpha1.DeviceTaintEvictionControllerConfiguration, s conversion.Scope) error {
|
||||
return autoConvert_config_DeviceTaintEvictionControllerConfiguration_To_v1alpha1_DeviceTaintEvictionControllerConfiguration(in, out, s)
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Copyright 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 v1alpha1
|
||||
|
||||
import (
|
||||
kubectrlmgrconfigv1alpha1 "k8s.io/kube-controller-manager/config/v1alpha1"
|
||||
)
|
||||
|
||||
// RecommendedDefaultDeviceTaintEvictionControllerConfiguration defaults a pointer to a
|
||||
// DeviceTaintEvictionControllerConfiguration struct. This will set the recommended default
|
||||
// values, but they may be subject to change between API versions. This function
|
||||
// is intentionally not registered in the scheme as a "normal" `SetDefaults_Foo`
|
||||
// function to allow consumers of this type to set whatever defaults for their
|
||||
// embedded configs. Forcing consumers to use these defaults would be problematic
|
||||
// as defaulting in the scheme is done as part of the conversion, and there would
|
||||
// be no easy way to opt-out. Instead, if you want to use this defaulting method
|
||||
// run it in your wrapper struct of this type in its `SetDefaults_` method.
|
||||
func RecommendedDefaultDeviceTaintEvictionControllerConfiguration(obj *kubectrlmgrconfigv1alpha1.DeviceTaintEvictionControllerConfiguration) {
|
||||
if obj.ConcurrentSyncs == 0 {
|
||||
// This is a compromise between getting work done and not overwhelming the apiserver
|
||||
// and pod informers. Integration testing with 100 workers modified pods so quickly
|
||||
// that a watch in the integration test couldn't keep up:
|
||||
// cacher.go:855] cacher (pods): 100 objects queued in incoming channel.
|
||||
// cache_watcher.go:203] Forcing pods watcher close due to unresponsiveness: key: "/pods/", labels: "", fields: "". len(c.input) = 10, len(c.result) = 10, graceful = false
|
||||
obj.ConcurrentSyncs = 8
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright 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 v1alpha1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
kubectrlmgrconfigv1alpha1 "k8s.io/kube-controller-manager/config/v1alpha1"
|
||||
)
|
||||
|
||||
func TestRecommendedDefaultDeviceTaintEvictionControllerConfiguration(t *testing.T) {
|
||||
config := new(kubectrlmgrconfigv1alpha1.DeviceTaintEvictionControllerConfiguration)
|
||||
RecommendedDefaultDeviceTaintEvictionControllerConfiguration(config)
|
||||
if config.ConcurrentSyncs != 8 {
|
||||
t.Errorf("incorrect default value, expected 8 but got %v", config.ConcurrentSyncs)
|
||||
}
|
||||
}
|
||||
21
pkg/controller/devicetainteviction/config/v1alpha1/doc.go
Normal file
21
pkg/controller/devicetainteviction/config/v1alpha1/doc.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
// +k8s:conversion-gen=k8s.io/kubernetes/pkg/controller/devicetainteviction/config
|
||||
// +k8s:conversion-gen-external-types=k8s.io/kube-controller-manager/config/v1alpha1
|
||||
|
||||
package v1alpha1
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright 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 v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
// SchemeBuilder is the scheme builder with scheme init functions to run for this API package
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
// localSchemeBuilder extends the SchemeBuilder instance with the external types. In this package,
|
||||
// defaulting and conversion init funcs are registered as well.
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
// AddToScheme is a global function that registers this API group & version to a scheme
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
92
pkg/controller/devicetainteviction/config/v1alpha1/zz_generated.conversion.go
generated
Normal file
92
pkg/controller/devicetainteviction/config/v1alpha1/zz_generated.conversion.go
generated
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by conversion-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
configv1alpha1 "k8s.io/kube-controller-manager/config/v1alpha1"
|
||||
config "k8s.io/kubernetes/pkg/controller/devicetainteviction/config"
|
||||
)
|
||||
|
||||
func init() {
|
||||
localSchemeBuilder.Register(RegisterConversions)
|
||||
}
|
||||
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(s *runtime.Scheme) error {
|
||||
if err := s.AddGeneratedConversionFunc((*configv1alpha1.GroupResource)(nil), (*v1.GroupResource)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_GroupResource_To_v1_GroupResource(a.(*configv1alpha1.GroupResource), b.(*v1.GroupResource), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddGeneratedConversionFunc((*v1.GroupResource)(nil), (*configv1alpha1.GroupResource)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1_GroupResource_To_v1alpha1_GroupResource(a.(*v1.GroupResource), b.(*configv1alpha1.GroupResource), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*config.DeviceTaintEvictionControllerConfiguration)(nil), (*configv1alpha1.DeviceTaintEvictionControllerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_config_DeviceTaintEvictionControllerConfiguration_To_v1alpha1_DeviceTaintEvictionControllerConfiguration(a.(*config.DeviceTaintEvictionControllerConfiguration), b.(*configv1alpha1.DeviceTaintEvictionControllerConfiguration), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.AddConversionFunc((*configv1alpha1.DeviceTaintEvictionControllerConfiguration)(nil), (*config.DeviceTaintEvictionControllerConfiguration)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
||||
return Convert_v1alpha1_DeviceTaintEvictionControllerConfiguration_To_config_DeviceTaintEvictionControllerConfiguration(a.(*configv1alpha1.DeviceTaintEvictionControllerConfiguration), b.(*config.DeviceTaintEvictionControllerConfiguration), scope)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_DeviceTaintEvictionControllerConfiguration_To_config_DeviceTaintEvictionControllerConfiguration(in *configv1alpha1.DeviceTaintEvictionControllerConfiguration, out *config.DeviceTaintEvictionControllerConfiguration, s conversion.Scope) error {
|
||||
out.ConcurrentSyncs = in.ConcurrentSyncs
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_config_DeviceTaintEvictionControllerConfiguration_To_v1alpha1_DeviceTaintEvictionControllerConfiguration(in *config.DeviceTaintEvictionControllerConfiguration, out *configv1alpha1.DeviceTaintEvictionControllerConfiguration, s conversion.Scope) error {
|
||||
out.ConcurrentSyncs = in.ConcurrentSyncs
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_GroupResource_To_v1_GroupResource(in *configv1alpha1.GroupResource, out *v1.GroupResource, s conversion.Scope) error {
|
||||
out.Group = in.Group
|
||||
out.Resource = in.Resource
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_GroupResource_To_v1_GroupResource is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_GroupResource_To_v1_GroupResource(in *configv1alpha1.GroupResource, out *v1.GroupResource, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_GroupResource_To_v1_GroupResource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_GroupResource_To_v1alpha1_GroupResource(in *v1.GroupResource, out *configv1alpha1.GroupResource, s conversion.Scope) error {
|
||||
out.Group = in.Group
|
||||
out.Resource = in.Resource
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1_GroupResource_To_v1alpha1_GroupResource is an autogenerated conversion function.
|
||||
func Convert_v1_GroupResource_To_v1alpha1_GroupResource(in *v1.GroupResource, out *configv1alpha1.GroupResource, s conversion.Scope) error {
|
||||
return autoConvert_v1_GroupResource_To_v1alpha1_GroupResource(in, out, s)
|
||||
}
|
||||
22
pkg/controller/devicetainteviction/config/v1alpha1/zz_generated.deepcopy.go
generated
Normal file
22
pkg/controller/devicetainteviction/config/v1alpha1/zz_generated.deepcopy.go
generated
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
38
pkg/controller/devicetainteviction/config/zz_generated.deepcopy.go
generated
Normal file
38
pkg/controller/devicetainteviction/config/zz_generated.deepcopy.go
generated
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by deepcopy-gen. DO NOT EDIT.
|
||||
|
||||
package config
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeviceTaintEvictionControllerConfiguration) DeepCopyInto(out *DeviceTaintEvictionControllerConfiguration) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeviceTaintEvictionControllerConfiguration.
|
||||
func (in *DeviceTaintEvictionControllerConfiguration) DeepCopy() *DeviceTaintEvictionControllerConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeviceTaintEvictionControllerConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
257
pkg/controller/devicetainteviction/mockqueue_test.go
Normal file
257
pkg/controller/devicetainteviction/mockqueue_test.go
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
Copyright 2024 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 devicetainteviction
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
)
|
||||
|
||||
// TODO (pohly): move this to k8s.io/client-go/util/workqueue/mockqueue.go
|
||||
// if it turns out to be generally useful. Doc comments are already written
|
||||
// as if the code was there.
|
||||
|
||||
// MockQueue is an implementation of [TypedRateLimitingInterface] which
|
||||
// can be used to test a function which pulls work items out of a queue
|
||||
// and processes them. It is thread-safe.
|
||||
//
|
||||
// A null instance is directly usable. The usual usage is:
|
||||
//
|
||||
// var m workqueue.Mock[string]
|
||||
// m.SyncOne("some-item", func(queue workqueue.TypedRateLimitingInterface[string]) { ... } )
|
||||
// if diff := cmp.Diff(workqueue.MockState[string]{}, m.State()); diff != "" {
|
||||
// t.Errorf("unexpected state of mock work queue after sync (-want, +got):\n%s", diff)
|
||||
// }
|
||||
//
|
||||
// All slices get reset to nil when they become empty, so there are no spurious
|
||||
// differences because of nil vs. empty slice.
|
||||
type Mock[T comparable] struct {
|
||||
mutex sync.Mutex
|
||||
state MockState[T]
|
||||
}
|
||||
|
||||
type MockState[T comparable] struct {
|
||||
// Ready contains the items which are ready for processing.
|
||||
Ready []T
|
||||
|
||||
// InFlight contains the items which are currently being processed (= Get
|
||||
// was called, Done not yet).
|
||||
InFlight []T
|
||||
|
||||
// MismatchedDone contains the items for which Done was called without
|
||||
// a matching Get.
|
||||
MismatchedDone []T
|
||||
|
||||
// Later contains the items which are meant to be added to the queue after
|
||||
// a certain delay (= AddAfter was called for them). They appear in the
|
||||
// order in which AddAfter got called.
|
||||
Later []MockDelayedItem[T]
|
||||
|
||||
// Failures contains the items and their retry count which failed to be
|
||||
// processed (AddRateLimited called at least once, Forget not yet).
|
||||
// The retry count is always larger than zero.
|
||||
Failures map[T]int
|
||||
|
||||
// ShutDownCalled tracks how often ShutDown got called.
|
||||
ShutDownCalled int
|
||||
|
||||
// ShutDownWithDrainCalled tracks how often ShutDownWithDrain got called.
|
||||
ShutDownWithDrainCalled int
|
||||
}
|
||||
|
||||
// DeepCopy takes a snapshot of all slices. It cannot do a deep copy of the items in those slices,
|
||||
// but typically those keys are immutable.
|
||||
func (m MockState[T]) DeepCopy() *MockState[T] {
|
||||
m.Ready = slices.Clone(m.Ready)
|
||||
m.InFlight = slices.Clone(m.InFlight)
|
||||
m.MismatchedDone = slices.Clone(m.MismatchedDone)
|
||||
m.Later = slices.Clone(m.Later)
|
||||
m.Failures = maps.Clone(m.Failures)
|
||||
return &m
|
||||
}
|
||||
|
||||
// MockDelayedItem is an item which was queue for later processing.
|
||||
type MockDelayedItem[T comparable] struct {
|
||||
Item T
|
||||
Duration time.Duration
|
||||
}
|
||||
|
||||
// SyncOne adds the item to the work queue and calls sync.
|
||||
// That sync function can pull one or more items from the work
|
||||
// queue until the queue is empty. Then it is told that the queue
|
||||
// is shutting down, which must cause it to return.
|
||||
//
|
||||
// The test can then retrieve the state of the queue to check the result.
|
||||
func (m *Mock[T]) SyncOne(item T, sync func(workqueue.TypedRateLimitingInterface[T])) {
|
||||
// sync must run with the mutex not locked.
|
||||
defer sync(m)
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
m.state.Ready = append(m.state.Ready, item)
|
||||
}
|
||||
|
||||
// State returns the current state of the queue.
|
||||
func (m *Mock[T]) State() MockState[T] {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
return *m.state.DeepCopy()
|
||||
}
|
||||
|
||||
// Add implements [TypedInterface].
|
||||
func (m *Mock[T]) Add(item T) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
if !slices.Contains(m.state.Ready, item) {
|
||||
m.state.Ready = append(m.state.Ready, item)
|
||||
}
|
||||
}
|
||||
|
||||
// Len implements [TypedInterface].
|
||||
func (m *Mock[T]) Len() int {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
return len(m.state.Ready)
|
||||
}
|
||||
|
||||
// Get implements [TypedInterface].
|
||||
func (m *Mock[T]) Get() (item T, shutdown bool) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
if len(m.state.Ready) == 0 {
|
||||
shutdown = true
|
||||
return
|
||||
}
|
||||
item = m.state.Ready[0]
|
||||
m.state.Ready = m.state.Ready[1:]
|
||||
if len(m.state.Ready) == 0 {
|
||||
m.state.Ready = nil
|
||||
}
|
||||
m.state.InFlight = append(m.state.InFlight, item)
|
||||
return item, false
|
||||
}
|
||||
|
||||
// Done implements [TypedInterface].
|
||||
func (m *Mock[T]) Done(item T) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
index := slices.Index(m.state.InFlight, item)
|
||||
if index < 0 {
|
||||
m.state.MismatchedDone = append(m.state.MismatchedDone, item)
|
||||
}
|
||||
m.state.InFlight = slices.Delete(m.state.InFlight, index, index+1)
|
||||
if len(m.state.InFlight) == 0 {
|
||||
m.state.InFlight = nil
|
||||
}
|
||||
}
|
||||
|
||||
// ShutDown implements [TypedInterface].
|
||||
func (m *Mock[T]) ShutDown() {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
m.state.ShutDownCalled++
|
||||
}
|
||||
|
||||
// ShutDownWithDrain implements [TypedInterface].
|
||||
func (m *Mock[T]) ShutDownWithDrain() {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
m.state.ShutDownWithDrainCalled++
|
||||
}
|
||||
|
||||
// ShuttingDown implements [TypedInterface].
|
||||
func (m *Mock[T]) ShuttingDown() bool {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
return m.state.ShutDownCalled > 0 || m.state.ShutDownWithDrainCalled > 0
|
||||
}
|
||||
|
||||
// AddAfter implements [TypedDelayingInterface.AddAfter]
|
||||
func (m *Mock[T]) AddAfter(item T, duration time.Duration) {
|
||||
if duration == 0 {
|
||||
m.Add(item)
|
||||
return
|
||||
}
|
||||
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
for i := range m.state.Later {
|
||||
if m.state.Later[i].Item == item {
|
||||
// https://github.com/kubernetes/client-go/blob/270e5ab1714527c455865953da8ceba2810dbb50/util/workqueue/delaying_queue.go#L340-L349
|
||||
// only shortens the delay for an existing item. It does not make it longer.
|
||||
if m.state.Later[i].Duration > duration {
|
||||
m.state.Later[i].Duration = duration
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
m.state.Later = append(m.state.Later, MockDelayedItem[T]{Item: item, Duration: duration})
|
||||
}
|
||||
|
||||
// CancelAfter is an extension of the TypedDelayingInterface: it allows a test to remove an item that may or may not have been added before via AddAfter.
|
||||
func (m *Mock[T]) CancelAfter(item T) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
m.state.Later = slices.DeleteFunc(m.state.Later, func(later MockDelayedItem[T]) bool {
|
||||
return later.Item == item
|
||||
})
|
||||
}
|
||||
|
||||
// AddRateLimited implements [TypedRateLimitingInterface.AddRateLimited].
|
||||
func (m *Mock[T]) AddRateLimited(item T) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
if m.state.Failures == nil {
|
||||
m.state.Failures = make(map[T]int)
|
||||
}
|
||||
m.state.Failures[item]++
|
||||
}
|
||||
|
||||
// Forget implements [TypedRateLimitingInterface.Forget].
|
||||
func (m *Mock[T]) Forget(item T) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
if m.state.Failures == nil {
|
||||
return
|
||||
}
|
||||
delete(m.state.Failures, item)
|
||||
}
|
||||
|
||||
// NumRequeues implements [TypedRateLimitingInterface.NumRequeues].
|
||||
func (m *Mock[T]) NumRequeues(item T) int {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
return m.state.Failures[item]
|
||||
}
|
||||
153
pkg/generated/openapi/zz_generated.openapi.go
generated
153
pkg/generated/openapi/zz_generated.openapi.go
generated
|
|
@ -1066,6 +1066,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
|||
v1alpha3.DeviceTaintRule{}.OpenAPIModelName(): schema_k8sio_api_resource_v1alpha3_DeviceTaintRule(ref),
|
||||
v1alpha3.DeviceTaintRuleList{}.OpenAPIModelName(): schema_k8sio_api_resource_v1alpha3_DeviceTaintRuleList(ref),
|
||||
v1alpha3.DeviceTaintRuleSpec{}.OpenAPIModelName(): schema_k8sio_api_resource_v1alpha3_DeviceTaintRuleSpec(ref),
|
||||
v1alpha3.DeviceTaintRuleStatus{}.OpenAPIModelName(): schema_k8sio_api_resource_v1alpha3_DeviceTaintRuleStatus(ref),
|
||||
v1alpha3.DeviceTaintSelector{}.OpenAPIModelName(): schema_k8sio_api_resource_v1alpha3_DeviceTaintSelector(ref),
|
||||
resourcev1beta1.AllocatedDeviceStatus{}.OpenAPIModelName(): schema_k8sio_api_resource_v1beta1_AllocatedDeviceStatus(ref),
|
||||
resourcev1beta1.AllocationResult{}.OpenAPIModelName(): schema_k8sio_api_resource_v1beta1_AllocationResult(ref),
|
||||
|
|
@ -1380,6 +1381,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
|||
kubecontrollermanagerconfigv1alpha1.DaemonSetControllerConfiguration{}.OpenAPIModelName(): schema_k8sio_kube_controller_manager_config_v1alpha1_DaemonSetControllerConfiguration(ref),
|
||||
kubecontrollermanagerconfigv1alpha1.DeploymentControllerConfiguration{}.OpenAPIModelName(): schema_k8sio_kube_controller_manager_config_v1alpha1_DeploymentControllerConfiguration(ref),
|
||||
kubecontrollermanagerconfigv1alpha1.DeprecatedControllerConfiguration{}.OpenAPIModelName(): schema_k8sio_kube_controller_manager_config_v1alpha1_DeprecatedControllerConfiguration(ref),
|
||||
kubecontrollermanagerconfigv1alpha1.DeviceTaintEvictionControllerConfiguration{}.OpenAPIModelName(): schema_k8sio_kube_controller_manager_config_v1alpha1_DeviceTaintEvictionControllerConfiguration(ref),
|
||||
kubecontrollermanagerconfigv1alpha1.EndpointControllerConfiguration{}.OpenAPIModelName(): schema_k8sio_kube_controller_manager_config_v1alpha1_EndpointControllerConfiguration(ref),
|
||||
kubecontrollermanagerconfigv1alpha1.EndpointSliceControllerConfiguration{}.OpenAPIModelName(): schema_k8sio_kube_controller_manager_config_v1alpha1_EndpointSliceControllerConfiguration(ref),
|
||||
kubecontrollermanagerconfigv1alpha1.EndpointSliceMirroringControllerConfiguration{}.OpenAPIModelName(): schema_k8sio_kube_controller_manager_config_v1alpha1_EndpointSliceMirroringControllerConfiguration(ref),
|
||||
|
|
@ -48409,7 +48411,7 @@ func schema_k8sio_api_resource_v1_Device(ref common.ReferenceCallback) common.Op
|
|||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
Description: "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
|
|
@ -49373,11 +49375,11 @@ func schema_k8sio_api_resource_v1_DeviceTaint(ref common.ReferenceCallback) comm
|
|||
},
|
||||
"effect": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.",
|
||||
Description: "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.\n - `\"None\"` No effect, the taint is purely informational.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule"},
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule", "None"},
|
||||
},
|
||||
},
|
||||
"timeAdded": {
|
||||
|
|
@ -49427,10 +49429,10 @@ func schema_k8sio_api_resource_v1_DeviceToleration(ref common.ReferenceCallback)
|
|||
},
|
||||
"effect": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule and NoExecute.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.",
|
||||
Description: "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule and NoExecute.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.\n - `\"None\"` No effect, the taint is purely informational.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule"},
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule", "None"},
|
||||
},
|
||||
},
|
||||
"tolerationSeconds": {
|
||||
|
|
@ -50159,7 +50161,7 @@ func schema_k8sio_api_resource_v1_ResourceSliceSpec(ref common.ReferenceCallback
|
|||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
Description: "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
|
|
@ -50273,11 +50275,11 @@ func schema_k8sio_api_resource_v1alpha3_DeviceTaint(ref common.ReferenceCallback
|
|||
},
|
||||
"effect": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.",
|
||||
Description: "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.\n - `\"None\"` No effect, the taint is purely informational.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule"},
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule", "None"},
|
||||
},
|
||||
},
|
||||
"timeAdded": {
|
||||
|
|
@ -50330,12 +50332,19 @@ func schema_k8sio_api_resource_v1alpha3_DeviceTaintRule(ref common.ReferenceCall
|
|||
Ref: ref(v1alpha3.DeviceTaintRuleSpec{}.OpenAPIModelName()),
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Status provides information about what was requested in the spec.",
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref(v1alpha3.DeviceTaintRuleStatus{}.OpenAPIModelName()),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"spec"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
v1alpha3.DeviceTaintRuleSpec{}.OpenAPIModelName(), metav1.ObjectMeta{}.OpenAPIModelName()},
|
||||
v1alpha3.DeviceTaintRuleSpec{}.OpenAPIModelName(), v1alpha3.DeviceTaintRuleStatus{}.OpenAPIModelName(), metav1.ObjectMeta{}.OpenAPIModelName()},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50399,7 +50408,7 @@ func schema_k8sio_api_resource_v1alpha3_DeviceTaintRuleSpec(ref common.Reference
|
|||
Properties: map[string]spec.Schema{
|
||||
"deviceSelector": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "DeviceSelector defines which device(s) the taint is applied to. All selector criteria must be satified for a device to match. The empty selector matches all devices. Without a selector, no devices are matches.",
|
||||
Description: "DeviceSelector defines which device(s) the taint is applied to. All selector criteria must be satisfied for a device to match. The empty selector matches all devices. Without a selector, no devices are matches.",
|
||||
Ref: ref(v1alpha3.DeviceTaintSelector{}.OpenAPIModelName()),
|
||||
},
|
||||
},
|
||||
|
|
@ -50419,6 +50428,45 @@ func schema_k8sio_api_resource_v1alpha3_DeviceTaintRuleSpec(ref common.Reference
|
|||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_resource_v1alpha3_DeviceTaintRuleStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "DeviceTaintRuleStatus provides information about an on-going pod eviction.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"conditions": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-map-keys": []interface{}{
|
||||
"type",
|
||||
},
|
||||
"x-kubernetes-list-type": "map",
|
||||
"x-kubernetes-patch-merge-key": "type",
|
||||
"x-kubernetes-patch-strategy": "merge",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Conditions provide information about the state of the DeviceTaintRule and the cluster at some point in time, in a machine-readable and human-readable format.\n\nThe following condition is currently defined as part of this API, more may get added: - Type: EvictionInProgress - Status: True if there are currently pods which need to be evicted, False otherwise\n (includes the effects which don't cause eviction).\n- Reason: not specified, may change - Message: includes information about number of pending pods and already evicted pods\n in a human-readable format, updated periodically, may change\n\nFor `effect: None`, the condition above gets set once for each change to the spec, with the message containing information about what would happen if the effect was `NoExecute`. This feedback can be used to decide whether changing the effect to `NoExecute` will work as intended. It only gets set once to avoid having to constantly update the status.\n\nMust have 8 or fewer entries.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref(metav1.Condition{}.OpenAPIModelName()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
metav1.Condition{}.OpenAPIModelName()},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_api_resource_v1alpha3_DeviceTaintSelector(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
|
@ -50426,13 +50474,6 @@ func schema_k8sio_api_resource_v1alpha3_DeviceTaintSelector(ref common.Reference
|
|||
Description: "DeviceTaintSelector defines which device(s) a DeviceTaintRule applies to. The empty selector matches all devices. Without a selector, no devices are matched.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"deviceClassName": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "If DeviceClassName is set, the selectors defined there must be satisfied by a device to be selected. This field corresponds to class.metadata.name.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"driver": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "If driver is set, only devices from that driver are selected. This fields corresponds to slice.spec.driver.",
|
||||
|
|
@ -50454,30 +50495,9 @@ func schema_k8sio_api_resource_v1alpha3_DeviceTaintSelector(ref common.Reference
|
|||
Format: "",
|
||||
},
|
||||
},
|
||||
"selectors": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-type": "atomic",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Selectors contains the same selection criteria as a ResourceClaim. Currently, CEL expressions are supported. All of these selectors must be satisfied.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref(v1alpha3.DeviceSelector{}.OpenAPIModelName()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
v1alpha3.DeviceSelector{}.OpenAPIModelName()},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50679,7 +50699,7 @@ func schema_k8sio_api_resource_v1beta1_BasicDevice(ref common.ReferenceCallback)
|
|||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
Description: "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
|
|
@ -51931,11 +51951,11 @@ func schema_k8sio_api_resource_v1beta1_DeviceTaint(ref common.ReferenceCallback)
|
|||
},
|
||||
"effect": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.",
|
||||
Description: "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.\n - `\"None\"` No effect, the taint is purely informational.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule"},
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule", "None"},
|
||||
},
|
||||
},
|
||||
"timeAdded": {
|
||||
|
|
@ -51985,10 +52005,10 @@ func schema_k8sio_api_resource_v1beta1_DeviceToleration(ref common.ReferenceCall
|
|||
},
|
||||
"effect": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule and NoExecute.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.",
|
||||
Description: "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule and NoExecute.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.\n - `\"None\"` No effect, the taint is purely informational.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule"},
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule", "None"},
|
||||
},
|
||||
},
|
||||
"tolerationSeconds": {
|
||||
|
|
@ -52627,7 +52647,7 @@ func schema_k8sio_api_resource_v1beta1_ResourceSliceSpec(ref common.ReferenceCal
|
|||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
Description: "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
|
|
@ -53071,7 +53091,7 @@ func schema_k8sio_api_resource_v1beta2_Device(ref common.ReferenceCallback) comm
|
|||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
Description: "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
|
|
@ -54035,11 +54055,11 @@ func schema_k8sio_api_resource_v1beta2_DeviceTaint(ref common.ReferenceCallback)
|
|||
},
|
||||
"effect": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.",
|
||||
Description: "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.\n - `\"None\"` No effect, the taint is purely informational.",
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule"},
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule", "None"},
|
||||
},
|
||||
},
|
||||
"timeAdded": {
|
||||
|
|
@ -54089,10 +54109,10 @@ func schema_k8sio_api_resource_v1beta2_DeviceToleration(ref common.ReferenceCall
|
|||
},
|
||||
"effect": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule and NoExecute.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.",
|
||||
Description: "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule and NoExecute.\n\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the device taint.\n - `\"NoSchedule\"` Do not allow new pods to schedule which use a tainted device unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running.\n - `\"None\"` No effect, the taint is purely informational.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule"},
|
||||
Enum: []interface{}{"NoExecute", "NoSchedule", "None"},
|
||||
},
|
||||
},
|
||||
"tolerationSeconds": {
|
||||
|
|
@ -54821,7 +54841,7 @@ func schema_k8sio_api_resource_v1beta2_ResourceSliceSpec(ref common.ReferenceCal
|
|||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
Description: "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
|
|
@ -66888,6 +66908,28 @@ func schema_k8sio_kube_controller_manager_config_v1alpha1_DeprecatedControllerCo
|
|||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_kube_controller_manager_config_v1alpha1_DeviceTaintEvictionControllerConfiguration(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "DeviceTaintEvictionControllerConfiguration contains elements configuring the device taint eviction controller.",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"ConcurrentSyncs": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "ConcurrentSyncs is the number of operations (deleting a pod, updating a ResourcClaim status, etc.) that will be done concurrently. Larger number = processing, but more CPU (and network) load.\n\nThe default is 10.",
|
||||
Default: 0,
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"ConcurrentSyncs"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_k8sio_kube_controller_manager_config_v1alpha1_EndpointControllerConfiguration(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
|
@ -67393,12 +67435,19 @@ func schema_k8sio_kube_controller_manager_config_v1alpha1_KubeControllerManagerC
|
|||
Ref: ref(kubecontrollermanagerconfigv1alpha1.ValidatingAdmissionPolicyStatusControllerConfiguration{}.OpenAPIModelName()),
|
||||
},
|
||||
},
|
||||
"DeviceTaintEvictionController": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "DeviceTaintEvictionControllerConfiguration contains elements configuring the device taint eviction controller.",
|
||||
Default: map[string]interface{}{},
|
||||
Ref: ref(kubecontrollermanagerconfigv1alpha1.DeviceTaintEvictionControllerConfiguration{}.OpenAPIModelName()),
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"Generic", "KubeCloudShared", "AttachDetachController", "CSRSigningController", "DaemonSetController", "DeploymentController", "StatefulSetController", "DeprecatedController", "EndpointController", "EndpointSliceController", "EndpointSliceMirroringController", "EphemeralVolumeController", "GarbageCollectorController", "HPAController", "JobController", "CronJobController", "LegacySATokenCleaner", "NamespaceController", "NodeIPAMController", "NodeLifecycleController", "PersistentVolumeBinderController", "PodGCController", "ReplicaSetController", "ReplicationController", "ResourceQuotaController", "SAController", "ServiceController", "TTLAfterFinishedController", "ValidatingAdmissionPolicyStatusController"},
|
||||
Required: []string{"Generic", "KubeCloudShared", "AttachDetachController", "CSRSigningController", "DaemonSetController", "DeploymentController", "StatefulSetController", "DeprecatedController", "EndpointController", "EndpointSliceController", "EndpointSliceMirroringController", "EphemeralVolumeController", "GarbageCollectorController", "HPAController", "JobController", "CronJobController", "LegacySATokenCleaner", "NamespaceController", "NodeIPAMController", "NodeLifecycleController", "PersistentVolumeBinderController", "PodGCController", "ReplicaSetController", "ReplicationController", "ResourceQuotaController", "SAController", "ServiceController", "TTLAfterFinishedController", "ValidatingAdmissionPolicyStatusController", "DeviceTaintEvictionController"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
configv1alpha1.KubeCloudSharedConfiguration{}.OpenAPIModelName(), serviceconfigv1alpha1.ServiceControllerConfiguration{}.OpenAPIModelName(), controllermanagerconfigv1alpha1.GenericControllerManagerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.AttachDetachControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.CSRSigningControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.CronJobControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.DaemonSetControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.DeploymentControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.DeprecatedControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.EndpointControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.EndpointSliceControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.EndpointSliceMirroringControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.EphemeralVolumeControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.GarbageCollectorControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.HPAControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.JobControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.LegacySATokenCleanerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.NamespaceControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.NodeIPAMControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.NodeLifecycleControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.PersistentVolumeBinderControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.PodGCControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.ReplicaSetControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.ReplicationControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.ResourceQuotaControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.SAControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.StatefulSetControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.TTLAfterFinishedControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.ValidatingAdmissionPolicyStatusControllerConfiguration{}.OpenAPIModelName()},
|
||||
configv1alpha1.KubeCloudSharedConfiguration{}.OpenAPIModelName(), serviceconfigv1alpha1.ServiceControllerConfiguration{}.OpenAPIModelName(), controllermanagerconfigv1alpha1.GenericControllerManagerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.AttachDetachControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.CSRSigningControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.CronJobControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.DaemonSetControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.DeploymentControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.DeprecatedControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.DeviceTaintEvictionControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.EndpointControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.EndpointSliceControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.EndpointSliceMirroringControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.EphemeralVolumeControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.GarbageCollectorControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.HPAControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.JobControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.LegacySATokenCleanerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.NamespaceControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.NodeIPAMControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.NodeLifecycleControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.PersistentVolumeBinderControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.PodGCControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.ReplicaSetControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.ReplicationControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.ResourceQuotaControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.SAControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.StatefulSetControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.TTLAfterFinishedControllerConfiguration{}.OpenAPIModelName(), kubecontrollermanagerconfigv1alpha1.ValidatingAdmissionPolicyStatusControllerConfiguration{}.OpenAPIModelName()},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,14 +17,19 @@ limitations under the License.
|
|||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
"k8s.io/kubernetes/pkg/apis/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||
printerstorage "k8s.io/kubernetes/pkg/printers/storage"
|
||||
"k8s.io/kubernetes/pkg/registry/resource/devicetaintrule"
|
||||
"sigs.k8s.io/structured-merge-diff/v6/fieldpath"
|
||||
)
|
||||
|
||||
// REST implements a RESTStorage for DeviceTaintRule.
|
||||
|
|
@ -33,7 +38,7 @@ type REST struct {
|
|||
}
|
||||
|
||||
// NewREST returns a RESTStorage object that will work against DeviceTaintRule.
|
||||
func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) {
|
||||
func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, *StatusREST, error) {
|
||||
store := &genericregistry.Store{
|
||||
NewFunc: func() runtime.Object { return &resource.DeviceTaintRule{} },
|
||||
NewListFunc: func() runtime.Object { return &resource.DeviceTaintRuleList{} },
|
||||
|
|
@ -44,13 +49,50 @@ func NewREST(optsGetter generic.RESTOptionsGetter) (*REST, error) {
|
|||
UpdateStrategy: devicetaintrule.Strategy,
|
||||
DeleteStrategy: devicetaintrule.Strategy,
|
||||
ReturnDeletedObject: true,
|
||||
ResetFieldsStrategy: devicetaintrule.Strategy,
|
||||
|
||||
TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
|
||||
}
|
||||
options := &generic.StoreOptions{RESTOptions: optsGetter}
|
||||
if err := store.CompleteWithOptions(options); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &REST{store}, nil
|
||||
statusStore := *store
|
||||
statusStore.UpdateStrategy = devicetaintrule.StatusStrategy
|
||||
statusStore.ResetFieldsStrategy = devicetaintrule.StatusStrategy
|
||||
|
||||
return &REST{store}, &StatusREST{store: &statusStore}, nil
|
||||
}
|
||||
|
||||
// StatusREST implements the REST endpoint for changing the status of a DeviceTaintRule.
|
||||
type StatusREST struct {
|
||||
store *genericregistry.Store
|
||||
}
|
||||
|
||||
// New creates a new DeviceTaintRule object.
|
||||
func (r *StatusREST) New() runtime.Object {
|
||||
return &resource.DeviceTaintRule{}
|
||||
}
|
||||
|
||||
func (r *StatusREST) Destroy() {
|
||||
// Given that underlying store is shared with REST,
|
||||
// we don't destroy it here explicitly.
|
||||
}
|
||||
|
||||
// Get retrieves the object from the storage. It is required to support Patch.
|
||||
func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
|
||||
return r.store.Get(ctx, name, options)
|
||||
}
|
||||
|
||||
// Update alters the status subset of an object.
|
||||
func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
|
||||
// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
|
||||
// subresources should never allow create on update.
|
||||
return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
|
||||
}
|
||||
|
||||
// GetResetFields implements rest.ResetFieldsStrategy
|
||||
func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
return r.store.GetResetFields()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,19 +20,24 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistrytest "k8s.io/apiserver/pkg/registry/generic/testing"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
etcd3testing "k8s.io/apiserver/pkg/storage/etcd3/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/resource"
|
||||
_ "k8s.io/kubernetes/pkg/apis/resource/install"
|
||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||
)
|
||||
|
||||
func newStorage(t *testing.T) (*REST, *etcd3testing.EtcdTestServer) {
|
||||
func newStorage(t *testing.T) (*REST, *StatusREST, *etcd3testing.EtcdTestServer) {
|
||||
etcdStorage, server := registrytest.NewEtcdStorageForResource(t, resource.Resource("devicetaintrules"))
|
||||
restOptions := generic.RESTOptions{
|
||||
StorageConfig: etcdStorage,
|
||||
|
|
@ -40,11 +45,11 @@ func newStorage(t *testing.T) (*REST, *etcd3testing.EtcdTestServer) {
|
|||
DeleteCollectionWorkers: 1,
|
||||
ResourcePrefix: "devicetaintrules",
|
||||
}
|
||||
deviceTaintStorage, err := NewREST(restOptions)
|
||||
deviceTaintStorage, statusStorage, err := NewREST(restOptions)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error from REST storage: %v", err)
|
||||
}
|
||||
return deviceTaintStorage, server
|
||||
return deviceTaintStorage, statusStorage, server
|
||||
}
|
||||
|
||||
func validNewDeviceTaint(name string) *resource.DeviceTaintRule {
|
||||
|
|
@ -63,7 +68,7 @@ func validNewDeviceTaint(name string) *resource.DeviceTaintRule {
|
|||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
|
|
@ -80,7 +85,7 @@ func TestCreate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
|
|
@ -98,7 +103,7 @@ func TestUpdate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope().ReturnDeletedObject()
|
||||
|
|
@ -106,7 +111,7 @@ func TestDelete(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
|
|
@ -114,7 +119,7 @@ func TestGet(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
|
|
@ -122,7 +127,7 @@ func TestList(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
storage, server := newStorage(t)
|
||||
storage, _, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
test := genericregistrytest.New(t, storage.Store).ClusterScope()
|
||||
|
|
@ -144,3 +149,39 @@ func TestWatch(t *testing.T) {
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
func TestUpdateStatus(t *testing.T) {
|
||||
storage, statusStorage, server := newStorage(t)
|
||||
defer server.Terminate(t)
|
||||
defer storage.Store.DestroyFunc()
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
|
||||
key, _ := storage.KeyFunc(ctx, "foo")
|
||||
deviceTaintStart := validNewDeviceTaint("foo")
|
||||
err := storage.Storage.Create(ctx, key, deviceTaintStart, nil, 0, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
deviceTaint := deviceTaintStart.DeepCopy()
|
||||
deviceTaint.Status.Conditions = []metav1.Condition{{
|
||||
Type: "EvicitionInProgress",
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: "PodsLeft",
|
||||
Message: "100 pods left",
|
||||
LastTransitionTime: metav1.Time{Time: time.Now().Truncate(time.Second)},
|
||||
}}
|
||||
_, _, err = statusStorage.Update(ctx, deviceTaint.Name, rest.DefaultUpdatedObjectInfo(deviceTaint), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
deviceTaintOut := obj.(*resource.DeviceTaintRule)
|
||||
// only compare relevant changes b/c of difference in metadata
|
||||
if !apiequality.Semantic.DeepEqual(deviceTaint.Status, deviceTaintOut.Status) {
|
||||
t.Errorf("unexpected object: %s", cmp.Diff(deviceTaint.Status, deviceTaintOut.Status))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,14 @@ import (
|
|||
"context"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/apis/resource"
|
||||
"k8s.io/kubernetes/pkg/apis/resource/validation"
|
||||
"sigs.k8s.io/structured-merge-diff/v6/fieldpath"
|
||||
)
|
||||
|
||||
// deviceTaintRuleStrategy implements behavior for DeviceTaintRule objects
|
||||
|
|
@ -34,51 +36,105 @@ type deviceTaintRuleStrategy struct {
|
|||
names.NameGenerator
|
||||
}
|
||||
|
||||
var Strategy = deviceTaintRuleStrategy{legacyscheme.Scheme, names.SimpleNameGenerator}
|
||||
var (
|
||||
Strategy = &deviceTaintRuleStrategy{legacyscheme.Scheme, names.SimpleNameGenerator}
|
||||
StatusStrategy = &deviceTaintRuleStatusStrategy{deviceTaintRuleStrategy: Strategy}
|
||||
)
|
||||
|
||||
func (deviceTaintRuleStrategy) NamespaceScoped() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (deviceTaintRuleStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
patch := obj.(*resource.DeviceTaintRule)
|
||||
patch.Generation = 1
|
||||
// GetResetFields returns the set of fields that get reset by the strategy and
|
||||
// should not be modified by the user. For a new DeviceTaintRule that is the
|
||||
// status.
|
||||
func (*deviceTaintRuleStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"resource.k8s.io/v1alpha3": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("status"),
|
||||
),
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
func (deviceTaintRuleStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||
patch := obj.(*resource.DeviceTaintRule)
|
||||
return validation.ValidateDeviceTaintRule(patch)
|
||||
func (*deviceTaintRuleStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
rule := obj.(*resource.DeviceTaintRule)
|
||||
// Status must not be set by user on create.
|
||||
rule.Status = resource.DeviceTaintRuleStatus{}
|
||||
rule.Generation = 1
|
||||
}
|
||||
|
||||
func (deviceTaintRuleStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
func (*deviceTaintRuleStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||
rule := obj.(*resource.DeviceTaintRule)
|
||||
return validation.ValidateDeviceTaintRule(rule)
|
||||
}
|
||||
|
||||
func (*deviceTaintRuleStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (deviceTaintRuleStrategy) Canonicalize(obj runtime.Object) {
|
||||
func (*deviceTaintRuleStrategy) Canonicalize(obj runtime.Object) {
|
||||
}
|
||||
|
||||
func (deviceTaintRuleStrategy) AllowCreateOnUpdate() bool {
|
||||
func (*deviceTaintRuleStrategy) AllowCreateOnUpdate() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (deviceTaintRuleStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
patch := obj.(*resource.DeviceTaintRule)
|
||||
oldPatch := old.(*resource.DeviceTaintRule)
|
||||
func (*deviceTaintRuleStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
rule := obj.(*resource.DeviceTaintRule)
|
||||
oldRule := old.(*resource.DeviceTaintRule)
|
||||
rule.Status = oldRule.Status
|
||||
|
||||
// Any changes to the spec increment the generation number.
|
||||
if !apiequality.Semantic.DeepEqual(oldPatch.Spec, patch.Spec) {
|
||||
patch.Generation = oldPatch.Generation + 1
|
||||
if !apiequality.Semantic.DeepEqual(oldRule.Spec, rule.Spec) {
|
||||
rule.Generation = oldRule.Generation + 1
|
||||
}
|
||||
}
|
||||
|
||||
func (deviceTaintRuleStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
func (*deviceTaintRuleStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
return validation.ValidateDeviceTaintRuleUpdate(obj.(*resource.DeviceTaintRule), old.(*resource.DeviceTaintRule))
|
||||
}
|
||||
|
||||
func (deviceTaintRuleStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
func (*deviceTaintRuleStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (deviceTaintRuleStrategy) AllowUnconditionalUpdate() bool {
|
||||
func (*deviceTaintRuleStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
type deviceTaintRuleStatusStrategy struct {
|
||||
*deviceTaintRuleStrategy
|
||||
}
|
||||
|
||||
// GetResetFields returns the set of fields that get reset by the strategy and
|
||||
// should not be modified by the user. For a status update that is the spec.
|
||||
func (*deviceTaintRuleStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"resource.k8s.io/v1alpha3": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("metadata"),
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
),
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
func (*deviceTaintRuleStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
|
||||
newRule := obj.(*resource.DeviceTaintRule)
|
||||
oldRule := old.(*resource.DeviceTaintRule)
|
||||
newRule.Spec = oldRule.Spec
|
||||
metav1.ResetObjectMetaForStatus(&newRule.ObjectMeta, &oldRule.ObjectMeta)
|
||||
}
|
||||
|
||||
func (r *deviceTaintRuleStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
|
||||
newRule := obj.(*resource.DeviceTaintRule)
|
||||
oldRule := old.(*resource.DeviceTaintRule)
|
||||
return validation.ValidateDeviceTaintRuleStatusUpdate(newRule, oldRule)
|
||||
}
|
||||
|
||||
// WarningsOnUpdate returns warnings for the given update.
|
||||
func (*deviceTaintRuleStatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,14 +19,17 @@ package devicetaintrule
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/kubernetes/pkg/apis/resource"
|
||||
)
|
||||
|
||||
var patch = &resource.DeviceTaintRule{
|
||||
var obj = &resource.DeviceTaintRule{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "valid-patch",
|
||||
Name: "valid-patch",
|
||||
Generation: 1,
|
||||
},
|
||||
Spec: resource.DeviceTaintRuleSpec{
|
||||
Taint: resource.DeviceTaint{
|
||||
|
|
@ -36,6 +39,31 @@ var patch = &resource.DeviceTaintRule{
|
|||
},
|
||||
}
|
||||
|
||||
var objWithStatus = &resource.DeviceTaintRule{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "valid-patch",
|
||||
Generation: 1,
|
||||
},
|
||||
Spec: resource.DeviceTaintRuleSpec{
|
||||
Taint: resource.DeviceTaint{
|
||||
Key: "example.com/tainted",
|
||||
Effect: resource.DeviceTaintEffectNoExecute,
|
||||
},
|
||||
},
|
||||
Status: resource.DeviceTaintRuleStatus{
|
||||
Conditions: []metav1.Condition{{
|
||||
Type: "foo",
|
||||
Status: metav1.ConditionFalse,
|
||||
LastTransitionTime: metav1.Now(),
|
||||
Reason: "something",
|
||||
Message: "else",
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
var fieldImmutableError = "field is immutable"
|
||||
var metadataError = "a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters"
|
||||
|
||||
func TestDeviceTaintRuleStrategy(t *testing.T) {
|
||||
if Strategy.NamespaceScoped() {
|
||||
t.Errorf("DeviceTaintRule must not be namespace scoped")
|
||||
|
|
@ -47,40 +75,202 @@ func TestDeviceTaintRuleStrategy(t *testing.T) {
|
|||
|
||||
func TestDeviceTaintRuleStrategyCreate(t *testing.T) {
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
patch := patch.DeepCopy()
|
||||
testcases := map[string]struct {
|
||||
obj *resource.DeviceTaintRule
|
||||
expectValidationError string
|
||||
expectObj *resource.DeviceTaintRule
|
||||
}{
|
||||
"simple": {
|
||||
obj: obj,
|
||||
expectObj: obj,
|
||||
},
|
||||
"validation-error": {
|
||||
obj: func() *resource.DeviceTaintRule {
|
||||
obj := obj.DeepCopy()
|
||||
obj.Name = "%#@$%$"
|
||||
return obj
|
||||
}(),
|
||||
expectValidationError: metadataError,
|
||||
},
|
||||
"drop-status": {
|
||||
obj: objWithStatus,
|
||||
expectObj: obj,
|
||||
},
|
||||
"set-generation": {
|
||||
obj: func() *resource.DeviceTaintRule {
|
||||
obj := obj.DeepCopy()
|
||||
obj.Generation = 42 // Cannot be set by client on create, overwritten with 1.
|
||||
return obj
|
||||
}(),
|
||||
expectObj: obj,
|
||||
},
|
||||
}
|
||||
|
||||
Strategy.PrepareForCreate(ctx, patch)
|
||||
errs := Strategy.Validate(ctx, patch)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("unexpected error validating for create %v", errs)
|
||||
for name, tc := range testcases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
obj := tc.obj.DeepCopy()
|
||||
Strategy.PrepareForCreate(ctx, obj)
|
||||
if errs := Strategy.Validate(ctx, obj); len(errs) != 0 {
|
||||
if tc.expectValidationError == "" {
|
||||
t.Fatalf("unexpected error(s): %v", errs)
|
||||
}
|
||||
assert.ErrorContains(t, errs[0], tc.expectValidationError, "the error message should have contained the expected error message")
|
||||
return
|
||||
}
|
||||
if tc.expectValidationError != "" {
|
||||
t.Fatal("expected validation error(s), got none")
|
||||
}
|
||||
if warnings := Strategy.WarningsOnCreate(ctx, obj); len(warnings) != 0 {
|
||||
t.Fatalf("unexpected warnings: %q", warnings)
|
||||
}
|
||||
Strategy.Canonicalize(obj)
|
||||
assert.Equal(t, tc.expectObj, obj)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeviceTaintRuleStrategyUpdate(t *testing.T) {
|
||||
t.Run("no-changes-okay", func(t *testing.T) {
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
patch := patch.DeepCopy()
|
||||
newPatch := patch.DeepCopy()
|
||||
newPatch.ResourceVersion = "4"
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
|
||||
Strategy.PrepareForUpdate(ctx, newPatch, patch)
|
||||
errs := Strategy.ValidateUpdate(ctx, newPatch, patch)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("unexpected validation errors: %v", errs)
|
||||
}
|
||||
})
|
||||
testcases := map[string]struct {
|
||||
oldObj *resource.DeviceTaintRule
|
||||
newObj *resource.DeviceTaintRule
|
||||
expectValidationError string
|
||||
expectObj *resource.DeviceTaintRule
|
||||
}{
|
||||
"no-changes-okay": {
|
||||
oldObj: obj,
|
||||
newObj: obj,
|
||||
expectObj: obj,
|
||||
},
|
||||
"name-change-not-allowed": {
|
||||
oldObj: obj,
|
||||
newObj: func() *resource.DeviceTaintRule {
|
||||
obj := obj.DeepCopy()
|
||||
obj.Name += "-2"
|
||||
return obj
|
||||
}(),
|
||||
expectValidationError: fieldImmutableError,
|
||||
},
|
||||
"drop-status": {
|
||||
oldObj: obj,
|
||||
newObj: objWithStatus,
|
||||
expectObj: obj,
|
||||
},
|
||||
"bump-generation": {
|
||||
oldObj: obj,
|
||||
newObj: func() *resource.DeviceTaintRule {
|
||||
obj := obj.DeepCopy()
|
||||
obj.Spec.Taint.Effect = resource.DeviceTaintEffectNone
|
||||
return obj
|
||||
}(),
|
||||
expectObj: func() *resource.DeviceTaintRule {
|
||||
obj := obj.DeepCopy()
|
||||
obj.Spec.Taint.Effect = resource.DeviceTaintEffectNone
|
||||
obj.Generation++
|
||||
return obj
|
||||
}(),
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("name-change-not-allowed", func(t *testing.T) {
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
patch := patch.DeepCopy()
|
||||
newPatch := patch.DeepCopy()
|
||||
newPatch.Name = "valid-patch-2"
|
||||
newPatch.ResourceVersion = "4"
|
||||
for name, tc := range testcases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
oldObj := tc.oldObj.DeepCopy()
|
||||
newObj := tc.newObj.DeepCopy()
|
||||
newObj.ResourceVersion = "4"
|
||||
|
||||
Strategy.PrepareForUpdate(ctx, newPatch, patch)
|
||||
errs := Strategy.ValidateUpdate(ctx, newPatch, patch)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("expected a validation error")
|
||||
}
|
||||
})
|
||||
Strategy.PrepareForUpdate(ctx, newObj, oldObj)
|
||||
if errs := Strategy.ValidateUpdate(ctx, newObj, oldObj); len(errs) != 0 {
|
||||
if tc.expectValidationError == "" {
|
||||
t.Fatalf("unexpected error(s): %v", errs)
|
||||
}
|
||||
assert.ErrorContains(t, errs[0], tc.expectValidationError, "the error message should have contained the expected error message")
|
||||
return
|
||||
}
|
||||
if tc.expectValidationError != "" {
|
||||
t.Fatal("expected validation error(s), got none")
|
||||
}
|
||||
if warnings := Strategy.WarningsOnUpdate(ctx, newObj, oldObj); len(warnings) != 0 {
|
||||
t.Fatalf("unexpected warnings: %q", warnings)
|
||||
}
|
||||
Strategy.Canonicalize(newObj)
|
||||
expectObj := tc.expectObj.DeepCopy()
|
||||
expectObj.ResourceVersion = "4"
|
||||
assert.Equal(t, expectObj, newObj)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusStrategyUpdate(t *testing.T) {
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
testcases := map[string]struct {
|
||||
oldObj *resource.DeviceTaintRule
|
||||
newObj *resource.DeviceTaintRule
|
||||
expectValidationError string
|
||||
expectObj *resource.DeviceTaintRule
|
||||
}{
|
||||
"no-changes-okay": {
|
||||
oldObj: obj,
|
||||
newObj: obj,
|
||||
expectObj: obj,
|
||||
},
|
||||
"name-change-not-allowed": {
|
||||
oldObj: obj,
|
||||
newObj: func() *resource.DeviceTaintRule {
|
||||
obj := obj.DeepCopy()
|
||||
obj.Name += "-2"
|
||||
return obj
|
||||
}(),
|
||||
expectValidationError: fieldImmutableError,
|
||||
},
|
||||
// Cannot add finalizers, annotations and labels during status update.
|
||||
"drop-meta-changes": {
|
||||
oldObj: obj,
|
||||
newObj: func() *resource.DeviceTaintRule {
|
||||
obj := obj.DeepCopy()
|
||||
obj.Finalizers = []string{"foo"}
|
||||
obj.Annotations = map[string]string{"foo": "bar"}
|
||||
obj.Labels = map[string]string{"foo": "bar"}
|
||||
return obj
|
||||
}(),
|
||||
expectObj: obj,
|
||||
},
|
||||
"drop-spec": {
|
||||
oldObj: obj,
|
||||
newObj: func() *resource.DeviceTaintRule {
|
||||
obj := obj.DeepCopy()
|
||||
obj.Spec.Taint.Effect = resource.DeviceTaintEffectNone
|
||||
return obj
|
||||
}(),
|
||||
expectObj: obj,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testcases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
oldObj := tc.oldObj.DeepCopy()
|
||||
newObj := tc.newObj.DeepCopy()
|
||||
newObj.ResourceVersion = "4"
|
||||
|
||||
StatusStrategy.PrepareForUpdate(ctx, newObj, oldObj)
|
||||
if errs := StatusStrategy.ValidateUpdate(ctx, newObj, oldObj); len(errs) != 0 {
|
||||
if tc.expectValidationError == "" {
|
||||
t.Fatalf("unexpected error(s): %v", errs)
|
||||
}
|
||||
assert.ErrorContains(t, errs[0], tc.expectValidationError, "the error message should have contained the expected error message")
|
||||
return
|
||||
}
|
||||
if tc.expectValidationError != "" {
|
||||
t.Fatal("expected validation error(s), got none")
|
||||
}
|
||||
if warnings := StatusStrategy.WarningsOnUpdate(ctx, newObj, oldObj); len(warnings) != 0 {
|
||||
t.Fatalf("unexpected warnings: %q", warnings)
|
||||
}
|
||||
StatusStrategy.Canonicalize(newObj)
|
||||
|
||||
expectObj := tc.expectObj.DeepCopy()
|
||||
expectObj.ResourceVersion = "4"
|
||||
assert.Equal(t, expectObj, newObj)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,15 +153,19 @@ func NewStatusStrategy(resourceclaimStrategy *resourceclaimStrategy) *resourcecl
|
|||
func (*resourceclaimStatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
|
||||
fields := map[fieldpath.APIVersion]*fieldpath.Set{
|
||||
"resource.k8s.io/v1alpha3": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("metadata"),
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
),
|
||||
"resource.k8s.io/v1beta1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("metadata"),
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
),
|
||||
"resource.k8s.io/v1beta2": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("metadata"),
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
),
|
||||
"resource.k8s.io/v1": fieldpath.NewSet(
|
||||
fieldpath.MakePathOrDie("metadata"),
|
||||
fieldpath.MakePathOrDie("spec"),
|
||||
),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,11 +118,12 @@ func (p RESTStorageProvider) v1alpha3Storage(apiResourceConfigSource serverstora
|
|||
storage := map[string]rest.Storage{}
|
||||
|
||||
if resource := "devicetaintrules"; apiResourceConfigSource.ResourceEnabled(resourcev1alpha3.SchemeGroupVersion.WithResource(resource)) {
|
||||
deviceTaintStorage, err := devicetaintrulestore.NewREST(restOptionsGetter)
|
||||
deviceTaintStorage, deviceTaintStatusStorage, err := devicetaintrulestore.NewREST(restOptionsGetter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storage[resource] = deviceTaintStorage
|
||||
storage[resource+"/status"] = deviceTaintStatusStorage
|
||||
}
|
||||
|
||||
return storage, nil
|
||||
|
|
|
|||
|
|
@ -224,6 +224,8 @@ func buildControllerRoles() ([]rbacv1.ClusterRole, []rbacv1.ClusterRoleBinding)
|
|||
rbacv1helpers.NewRule("get", "list", "watch", "delete").Groups(legacyGroup).Resources("pods").RuleOrDie(),
|
||||
// Sets pod conditions.
|
||||
rbacv1helpers.NewRule("update", "patch").Groups(legacyGroup).Resources("pods/status").RuleOrDie(),
|
||||
// Sets DeviceTaintRule conditions.
|
||||
rbacv1helpers.NewRule("update", "patch").Groups(resourceGroup).Resources("devicetaintrules/status").RuleOrDie(),
|
||||
// The rest is read-only.
|
||||
rbacv1helpers.NewRule("get", "list", "watch").Groups(resourceGroup).Resources("resourceclaims").RuleOrDie(),
|
||||
rbacv1helpers.NewRule("get", "list", "watch").Groups(resourceGroup).Resources("resourceslices").RuleOrDie(),
|
||||
|
|
|
|||
|
|
@ -395,7 +395,9 @@ message Device {
|
|||
|
||||
// If specified, these are the driver-defined taints.
|
||||
//
|
||||
// The maximum number of taints is 4.
|
||||
// The maximum number of taints is 16. If taints are set for
|
||||
// any device in a ResourceSlice, then the maximum number of
|
||||
// allowed devices per ResourceSlice is 64 instead of 128.
|
||||
//
|
||||
// This is an alpha field and requires enabling the DRADeviceTaints
|
||||
// feature gate.
|
||||
|
|
@ -1116,8 +1118,10 @@ message DeviceTaint {
|
|||
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
//
|
||||
// +required
|
||||
// +k8s:required
|
||||
|
|
@ -1658,7 +1662,7 @@ message ResourceSliceSpec {
|
|||
|
||||
// Devices lists some or all of the devices in this pool.
|
||||
//
|
||||
// Must not have more than 128 entries.
|
||||
// Must not have more than 128 entries. If any device uses taints the limit is 64.
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ type ResourceSliceSpec struct {
|
|||
|
||||
// Devices lists some or all of the devices in this pool.
|
||||
//
|
||||
// Must not have more than 128 entries.
|
||||
// Must not have more than 128 entries. If any device uses taints the limit is 64.
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
|
|
@ -250,6 +250,7 @@ type ResourcePool struct {
|
|||
|
||||
const ResourceSliceMaxSharedCapacity = 128
|
||||
const ResourceSliceMaxDevices = 128
|
||||
const ResourceSliceMaxDevicesWithTaints = 64
|
||||
const PoolNameMaxLength = validation.DNS1123SubdomainMaxLength // Same as for a single node name.
|
||||
const BindingConditionsMaxSize = 4
|
||||
const BindingFailureConditionsMaxSize = 4
|
||||
|
|
@ -333,7 +334,9 @@ type Device struct {
|
|||
|
||||
// If specified, these are the driver-defined taints.
|
||||
//
|
||||
// The maximum number of taints is 4.
|
||||
// The maximum number of taints is 16. If taints are set for
|
||||
// any device in a ResourceSlice, then the maximum number of
|
||||
// allowed devices per ResourceSlice is 64 instead of 128.
|
||||
//
|
||||
// This is an alpha field and requires enabling the DRADeviceTaints
|
||||
// feature gate.
|
||||
|
|
@ -618,8 +621,8 @@ type DeviceAttribute struct {
|
|||
// DeviceAttributeMaxValueLength is the maximum length of a string or version attribute value.
|
||||
const DeviceAttributeMaxValueLength = 64
|
||||
|
||||
// DeviceTaintsMaxLength is the maximum number of taints per device.
|
||||
const DeviceTaintsMaxLength = 4
|
||||
// DeviceTaintsMaxLength is the maximum number of taints per Device.
|
||||
const DeviceTaintsMaxLength = 16
|
||||
|
||||
// The device this taint is attached to has the "effect" on
|
||||
// any claim which does not tolerate the taint and, through the claim,
|
||||
|
|
@ -641,8 +644,10 @@ type DeviceTaint struct {
|
|||
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
//
|
||||
// +required
|
||||
// +k8s:required
|
||||
|
|
@ -652,6 +657,14 @@ type DeviceTaint struct {
|
|||
//
|
||||
// Implementing PreferNoSchedule would depend on a scoring solution for DRA.
|
||||
// It might get added as part of that.
|
||||
//
|
||||
// A possible future new effect is NoExecuteWithPodDisruptionBudget:
|
||||
// honor the pod disruption budget instead of simply deleting pods.
|
||||
// This is currently undecided, it could also be a separate field.
|
||||
//
|
||||
// Validation must be prepared to allow unknown enums in stored objects,
|
||||
// which will enable adding new enums within a single release without
|
||||
// ratcheting.
|
||||
|
||||
// TimeAdded represents the time at which the taint was added.
|
||||
// Added automatically during create or update if not set.
|
||||
|
|
@ -671,6 +684,9 @@ type DeviceTaint struct {
|
|||
type DeviceTaintEffect string
|
||||
|
||||
const (
|
||||
// No effect, the taint is purely informational.
|
||||
DeviceTaintEffectNone DeviceTaintEffect = "None"
|
||||
|
||||
// Do not allow new pods to schedule which use a tainted device unless they tolerate the taint,
|
||||
// but allow all pods submitted to Kubelet without going through the scheduler
|
||||
// to start, and allow all already-running pods to continue running.
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ var map_Device = map[string]string{
|
|||
"nodeName": "NodeName identifies the node where the device is available.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set.",
|
||||
"nodeSelector": "NodeSelector defines the nodes where the device is available.\n\nMust use exactly one term.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set.",
|
||||
"allNodes": "AllNodes indicates that all nodes have access to the device.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set.",
|
||||
"taints": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"taints": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"bindsToNode": "BindsToNode indicates if the usage of an allocation involving this device has to be limited to exactly the node that was chosen when allocating the claim. If set to true, the scheduler will set the ResourceClaim.Status.Allocation.NodeSelector to match the node where the allocation was made.\n\nThis is an alpha field and requires enabling the DRADeviceBindingConditions and DRAResourceClaimDeviceStatus feature gates.",
|
||||
"bindingConditions": "BindingConditions defines the conditions for proceeding with binding. All of these conditions must be set in the per-device status conditions with a value of True to proceed with binding the pod to the node while scheduling the pod.\n\nThe maximum number of binding conditions is 4.\n\nThe conditions must be a valid condition type string.\n\nThis is an alpha field and requires enabling the DRADeviceBindingConditions and DRAResourceClaimDeviceStatus feature gates.",
|
||||
"bindingFailureConditions": "BindingFailureConditions defines the conditions for binding failure. They may be set in the per-device status conditions. If any is set to \"True\", a binding failure occurred.\n\nThe maximum number of binding failure conditions is 4.\n\nThe conditions must be a valid condition type string.\n\nThis is an alpha field and requires enabling the DRADeviceBindingConditions and DRAResourceClaimDeviceStatus feature gates.",
|
||||
|
|
@ -320,7 +320,7 @@ var map_DeviceTaint = map[string]string{
|
|||
"": "The device this taint is attached to has the \"effect\" on any claim which does not tolerate the taint and, through the claim, to pods using the claim.",
|
||||
"key": "The taint key to be applied to a device. Must be a label name.",
|
||||
"value": "The taint value corresponding to the taint key. Must be a label value.",
|
||||
"effect": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"effect": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"timeAdded": "TimeAdded represents the time at which the taint was added. Added automatically during create or update if not set.",
|
||||
}
|
||||
|
||||
|
|
@ -498,7 +498,7 @@ var map_ResourceSliceSpec = map[string]string{
|
|||
"nodeName": "NodeName identifies the node which provides the resources in this pool. A field selector can be used to list only ResourceSlice objects belonging to a certain node.\n\nThis field can be used to limit access from nodes to ResourceSlices with the same node name. It also indicates to autoscalers that adding new nodes of the same type as some old node might also make new resources available.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set. This field is immutable.",
|
||||
"nodeSelector": "NodeSelector defines which nodes have access to the resources in the pool, when that pool is not limited to a single node.\n\nMust use exactly one term.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.",
|
||||
"allNodes": "AllNodes indicates that all nodes have access to the resources in the pool.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.",
|
||||
"devices": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
"devices": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
"perDeviceNodeSelection": "PerDeviceNodeSelection defines whether the access from nodes to resources in the pool is set on the ResourceSlice level or on each device. If it is set to true, every device defined the ResourceSlice must specify this individually.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.",
|
||||
"sharedCounters": "SharedCounters defines a list of counter sets, each of which has a name and a list of counters available.\n\nThe names of the SharedCounters must be unique in the ResourceSlice.\n\nThe maximum number of counters in all sets is 32.",
|
||||
}
|
||||
|
|
|
|||
304
staging/src/k8s.io/api/resource/v1alpha3/generated.pb.go
generated
304
staging/src/k8s.io/api/resource/v1alpha3/generated.pb.go
generated
|
|
@ -43,6 +43,8 @@ func (m *DeviceTaintRuleList) Reset() { *m = DeviceTaintRuleList{} }
|
|||
|
||||
func (m *DeviceTaintRuleSpec) Reset() { *m = DeviceTaintRuleSpec{} }
|
||||
|
||||
func (m *DeviceTaintRuleStatus) Reset() { *m = DeviceTaintRuleStatus{} }
|
||||
|
||||
func (m *DeviceTaintSelector) Reset() { *m = DeviceTaintSelector{} }
|
||||
|
||||
func (m *CELDeviceSelector) Marshal() (dAtA []byte, err error) {
|
||||
|
|
@ -178,6 +180,16 @@ func (m *DeviceTaintRule) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
{
|
||||
size, err := m.Status.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x1a
|
||||
{
|
||||
size, err := m.Spec.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
|
|
@ -293,6 +305,43 @@ func (m *DeviceTaintRuleSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *DeviceTaintRuleStatus) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *DeviceTaintRuleStatus) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *DeviceTaintRuleStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Conditions) > 0 {
|
||||
for iNdEx := len(m.Conditions) - 1; iNdEx >= 0; iNdEx-- {
|
||||
{
|
||||
size, err := m.Conditions[iNdEx].MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *DeviceTaintSelector) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
|
|
@ -313,20 +362,6 @@ func (m *DeviceTaintSelector) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Selectors) > 0 {
|
||||
for iNdEx := len(m.Selectors) - 1; iNdEx >= 0; iNdEx-- {
|
||||
{
|
||||
size, err := m.Selectors[iNdEx].MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x2a
|
||||
}
|
||||
}
|
||||
if m.Device != nil {
|
||||
i -= len(*m.Device)
|
||||
copy(dAtA[i:], *m.Device)
|
||||
|
|
@ -348,13 +383,6 @@ func (m *DeviceTaintSelector) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if m.DeviceClassName != nil {
|
||||
i -= len(*m.DeviceClassName)
|
||||
copy(dAtA[i:], *m.DeviceClassName)
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(len(*m.DeviceClassName)))
|
||||
i--
|
||||
dAtA[i] = 0xa
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
|
|
@ -422,6 +450,8 @@ func (m *DeviceTaintRule) Size() (n int) {
|
|||
n += 1 + l + sovGenerated(uint64(l))
|
||||
l = m.Spec.Size()
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
l = m.Status.Size()
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
return n
|
||||
}
|
||||
|
||||
|
|
@ -457,16 +487,27 @@ func (m *DeviceTaintRuleSpec) Size() (n int) {
|
|||
return n
|
||||
}
|
||||
|
||||
func (m *DeviceTaintRuleStatus) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Conditions) > 0 {
|
||||
for _, e := range m.Conditions {
|
||||
l = e.Size()
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *DeviceTaintSelector) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.DeviceClassName != nil {
|
||||
l = len(*m.DeviceClassName)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
if m.Driver != nil {
|
||||
l = len(*m.Driver)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
|
|
@ -479,12 +520,6 @@ func (m *DeviceTaintSelector) Size() (n int) {
|
|||
l = len(*m.Device)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
if len(m.Selectors) > 0 {
|
||||
for _, e := range m.Selectors {
|
||||
l = e.Size()
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
|
|
@ -521,6 +556,7 @@ func (this *DeviceTaintRule) String() string {
|
|||
s := strings.Join([]string{`&DeviceTaintRule{`,
|
||||
`ObjectMeta:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ObjectMeta), "ObjectMeta", "v1.ObjectMeta", 1), `&`, ``, 1) + `,`,
|
||||
`Spec:` + strings.Replace(strings.Replace(this.Spec.String(), "DeviceTaintRuleSpec", "DeviceTaintRuleSpec", 1), `&`, ``, 1) + `,`,
|
||||
`Status:` + strings.Replace(strings.Replace(this.Status.String(), "DeviceTaintRuleStatus", "DeviceTaintRuleStatus", 1), `&`, ``, 1) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
|
|
@ -552,21 +588,29 @@ func (this *DeviceTaintRuleSpec) String() string {
|
|||
}, "")
|
||||
return s
|
||||
}
|
||||
func (this *DeviceTaintRuleStatus) String() string {
|
||||
if this == nil {
|
||||
return "nil"
|
||||
}
|
||||
repeatedStringForConditions := "[]Condition{"
|
||||
for _, f := range this.Conditions {
|
||||
repeatedStringForConditions += fmt.Sprintf("%v", f) + ","
|
||||
}
|
||||
repeatedStringForConditions += "}"
|
||||
s := strings.Join([]string{`&DeviceTaintRuleStatus{`,
|
||||
`Conditions:` + repeatedStringForConditions + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
}
|
||||
func (this *DeviceTaintSelector) String() string {
|
||||
if this == nil {
|
||||
return "nil"
|
||||
}
|
||||
repeatedStringForSelectors := "[]DeviceSelector{"
|
||||
for _, f := range this.Selectors {
|
||||
repeatedStringForSelectors += strings.Replace(strings.Replace(f.String(), "DeviceSelector", "DeviceSelector", 1), `&`, ``, 1) + ","
|
||||
}
|
||||
repeatedStringForSelectors += "}"
|
||||
s := strings.Join([]string{`&DeviceTaintSelector{`,
|
||||
`DeviceClassName:` + valueToStringGenerated(this.DeviceClassName) + `,`,
|
||||
`Driver:` + valueToStringGenerated(this.Driver) + `,`,
|
||||
`Pool:` + valueToStringGenerated(this.Pool) + `,`,
|
||||
`Device:` + valueToStringGenerated(this.Device) + `,`,
|
||||
`Selectors:` + repeatedStringForSelectors + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
|
|
@ -1024,6 +1068,39 @@ func (m *DeviceTaintRule) Unmarshal(dAtA []byte) error {
|
|||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if err := m.Status.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
|
|
@ -1281,6 +1358,90 @@ func (m *DeviceTaintRuleSpec) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
func (m *DeviceTaintRuleStatus) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: DeviceTaintRuleStatus: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: DeviceTaintRuleStatus: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Conditions", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Conditions = append(m.Conditions, v1.Condition{})
|
||||
if err := m.Conditions[len(m.Conditions)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *DeviceTaintSelector) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
|
|
@ -1310,39 +1471,6 @@ func (m *DeviceTaintSelector) Unmarshal(dAtA []byte) error {
|
|||
return fmt.Errorf("proto: DeviceTaintSelector: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field DeviceClassName", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
s := string(dAtA[iNdEx:postIndex])
|
||||
m.DeviceClassName = &s
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Driver", wireType)
|
||||
|
|
@ -1442,40 +1570,6 @@ func (m *DeviceTaintSelector) Unmarshal(dAtA []byte) error {
|
|||
s := string(dAtA[iNdEx:postIndex])
|
||||
m.Device = &s
|
||||
iNdEx = postIndex
|
||||
case 5:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Selectors", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Selectors = append(m.Selectors, DeviceSelector{})
|
||||
if err := m.Selectors[len(m.Selectors)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
|
|
|
|||
|
|
@ -114,8 +114,10 @@ message DeviceTaint {
|
|||
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
//
|
||||
// +required
|
||||
optional string effect = 3;
|
||||
|
|
@ -139,6 +141,11 @@ message DeviceTaintRule {
|
|||
//
|
||||
// Changing the spec automatically increments the metadata.generation number.
|
||||
optional DeviceTaintRuleSpec spec = 2;
|
||||
|
||||
// Status provides information about what was requested in the spec.
|
||||
//
|
||||
// +optional
|
||||
optional DeviceTaintRuleStatus status = 3;
|
||||
}
|
||||
|
||||
// DeviceTaintRuleList is a collection of DeviceTaintRules.
|
||||
|
|
@ -154,7 +161,7 @@ message DeviceTaintRuleList {
|
|||
// DeviceTaintRuleSpec specifies the selector and one taint.
|
||||
message DeviceTaintRuleSpec {
|
||||
// DeviceSelector defines which device(s) the taint is applied to.
|
||||
// All selector criteria must be satified for a device to
|
||||
// All selector criteria must be satisfied for a device to
|
||||
// match. The empty selector matches all devices. Without
|
||||
// a selector, no devices are matches.
|
||||
//
|
||||
|
|
@ -167,17 +174,41 @@ message DeviceTaintRuleSpec {
|
|||
optional DeviceTaint taint = 2;
|
||||
}
|
||||
|
||||
// DeviceTaintRuleStatus provides information about an on-going pod eviction.
|
||||
message DeviceTaintRuleStatus {
|
||||
// Conditions provide information about the state of the DeviceTaintRule
|
||||
// and the cluster at some point in time,
|
||||
// in a machine-readable and human-readable format.
|
||||
//
|
||||
// The following condition is currently defined as part of this API, more may
|
||||
// get added:
|
||||
// - Type: EvictionInProgress
|
||||
// - Status: True if there are currently pods which need to be evicted, False otherwise
|
||||
// (includes the effects which don't cause eviction).
|
||||
// - Reason: not specified, may change
|
||||
// - Message: includes information about number of pending pods and already evicted pods
|
||||
// in a human-readable format, updated periodically, may change
|
||||
//
|
||||
// For `effect: None`, the condition above gets set once for each change to
|
||||
// the spec, with the message containing information about what would happen
|
||||
// if the effect was `NoExecute`. This feedback can be used to decide whether
|
||||
// changing the effect to `NoExecute` will work as intended. It only gets
|
||||
// set once to avoid having to constantly update the status.
|
||||
//
|
||||
// Must have 8 or fewer entries.
|
||||
//
|
||||
// +optional
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
// +patchStrategy=merge
|
||||
// +patchMergeKey=type
|
||||
repeated .k8s.io.apimachinery.pkg.apis.meta.v1.Condition conditions = 1;
|
||||
}
|
||||
|
||||
// DeviceTaintSelector defines which device(s) a DeviceTaintRule applies to.
|
||||
// The empty selector matches all devices. Without a selector, no devices
|
||||
// are matched.
|
||||
message DeviceTaintSelector {
|
||||
// If DeviceClassName is set, the selectors defined there must be
|
||||
// satisfied by a device to be selected. This field corresponds
|
||||
// to class.metadata.name.
|
||||
//
|
||||
// +optional
|
||||
optional string deviceClassName = 1;
|
||||
|
||||
// If driver is set, only devices from that driver are selected.
|
||||
// This fields corresponds to slice.spec.driver.
|
||||
//
|
||||
|
|
@ -204,13 +235,5 @@ message DeviceTaintSelector {
|
|||
//
|
||||
// +optional
|
||||
optional string device = 4;
|
||||
|
||||
// Selectors contains the same selection criteria as a ResourceClaim.
|
||||
// Currently, CEL expressions are supported. All of these selectors
|
||||
// must be satisfied.
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
repeated DeviceSelector selectors = 5;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,4 +33,6 @@ func (*DeviceTaintRuleList) ProtoMessage() {}
|
|||
|
||||
func (*DeviceTaintRuleSpec) ProtoMessage() {}
|
||||
|
||||
func (*DeviceTaintRuleStatus) ProtoMessage() {}
|
||||
|
||||
func (*DeviceTaintSelector) ProtoMessage() {}
|
||||
|
|
|
|||
|
|
@ -134,8 +134,10 @@ type DeviceTaint struct {
|
|||
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
//
|
||||
// +required
|
||||
Effect DeviceTaintEffect `json:"effect" protobuf:"bytes,3,name=effect,casttype=DeviceTaintEffect"`
|
||||
|
|
@ -144,6 +146,14 @@ type DeviceTaint struct {
|
|||
//
|
||||
// Implementing PreferNoSchedule would depend on a scoring solution for DRA.
|
||||
// It might get added as part of that.
|
||||
//
|
||||
// A possible future new effect is NoExecuteWithPodDisruptionBudget:
|
||||
// honor the pod disruption budget instead of simply deleting pods.
|
||||
// This is currently undecided, it could also be a separate field.
|
||||
//
|
||||
// Validation must be prepared to allow unknown enums in stored objects,
|
||||
// which will enable adding new enums within a single release without
|
||||
// ratcheting.
|
||||
|
||||
// TimeAdded represents the time at which the taint was added.
|
||||
// Added automatically during create or update if not set.
|
||||
|
|
@ -162,6 +172,9 @@ type DeviceTaint struct {
|
|||
type DeviceTaintEffect string
|
||||
|
||||
const (
|
||||
// No effect, the taint is purely informational.
|
||||
DeviceTaintEffectNone DeviceTaintEffect = "None"
|
||||
|
||||
// Do not allow new pods to schedule which use a tainted device unless they tolerate the taint,
|
||||
// but allow all pods submitted to Kubelet without going through the scheduler
|
||||
// to start, and allow all already-running pods to continue running.
|
||||
|
|
@ -190,18 +203,16 @@ type DeviceTaintRule struct {
|
|||
// Changing the spec automatically increments the metadata.generation number.
|
||||
Spec DeviceTaintRuleSpec `json:"spec" protobuf:"bytes,2,name=spec"`
|
||||
|
||||
// ^^^
|
||||
// A spec gets added because adding a status seems likely.
|
||||
// Such a status could provide feedback on applying the
|
||||
// eviction and/or statistics (number of matching devices,
|
||||
// affected allocated claims, pods remaining to be evicted,
|
||||
// etc.).
|
||||
// Status provides information about what was requested in the spec.
|
||||
//
|
||||
// +optional
|
||||
Status DeviceTaintRuleStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
}
|
||||
|
||||
// DeviceTaintRuleSpec specifies the selector and one taint.
|
||||
type DeviceTaintRuleSpec struct {
|
||||
// DeviceSelector defines which device(s) the taint is applied to.
|
||||
// All selector criteria must be satified for a device to
|
||||
// All selector criteria must be satisfied for a device to
|
||||
// match. The empty selector matches all devices. Without
|
||||
// a selector, no devices are matches.
|
||||
//
|
||||
|
|
@ -223,7 +234,12 @@ type DeviceTaintSelector struct {
|
|||
// to class.metadata.name.
|
||||
//
|
||||
// +optional
|
||||
DeviceClassName *string `json:"deviceClassName,omitempty" protobuf:"bytes,1,opt,name=deviceClassName"`
|
||||
//
|
||||
// Tombstoned since 1.35 because it turned out that supporting this in all cases
|
||||
// would depend on copying the device attributes into the ResourceClaim allocation
|
||||
// result. Without that the eviction controller cannot evaluate these CEL expressions.
|
||||
//
|
||||
// DeviceClassName *string `json:"deviceClassName,omitempty" protobuf:"bytes,1,opt,name=deviceClassName"`
|
||||
|
||||
// If driver is set, only devices from that driver are selected.
|
||||
// This fields corresponds to slice.spec.driver.
|
||||
|
|
@ -258,9 +274,51 @@ type DeviceTaintSelector struct {
|
|||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
Selectors []DeviceSelector `json:"selectors,omitempty" protobuf:"bytes,5,rep,name=selectors"`
|
||||
//
|
||||
// Tombstoned since 1.35 because it turned out that supporting this in all cases
|
||||
// would depend on copying the device attributes into the ResourceClaim allocation
|
||||
// result. Without that the eviction controller cannot evaluate these CEL expressions.
|
||||
//
|
||||
// Selectors []DeviceSelector `json:"selectors,omitempty" protobuf:"bytes,5,rep,name=selectors"`
|
||||
}
|
||||
|
||||
// DeviceTaintRuleStatus provides information about an on-going pod eviction.
|
||||
type DeviceTaintRuleStatus struct {
|
||||
// Conditions provide information about the state of the DeviceTaintRule
|
||||
// and the cluster at some point in time,
|
||||
// in a machine-readable and human-readable format.
|
||||
//
|
||||
// The following condition is currently defined as part of this API, more may
|
||||
// get added:
|
||||
// - Type: EvictionInProgress
|
||||
// - Status: True if there are currently pods which need to be evicted, False otherwise
|
||||
// (includes the effects which don't cause eviction).
|
||||
// - Reason: not specified, may change
|
||||
// - Message: includes information about number of pending pods and already evicted pods
|
||||
// in a human-readable format, updated periodically, may change
|
||||
//
|
||||
// For `effect: None`, the condition above gets set once for each change to
|
||||
// the spec, with the message containing information about what would happen
|
||||
// if the effect was `NoExecute`. This feedback can be used to decide whether
|
||||
// changing the effect to `NoExecute` will work as intended. It only gets
|
||||
// set once to avoid having to constantly update the status.
|
||||
//
|
||||
// Must have 8 or fewer entries.
|
||||
//
|
||||
// +optional
|
||||
// +listType=map
|
||||
// +listMapKey=type
|
||||
// +patchStrategy=merge
|
||||
// +patchMergeKey=type
|
||||
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`
|
||||
}
|
||||
|
||||
// DeviceTaintRuleStatusMaxConditions is the maximum number of conditions in DeviceTaintRuleStatus.
|
||||
const DeviceTaintRuleStatusMaxConditions = 8
|
||||
|
||||
// DeviceTaintConditionEvictionInProgress is the publicly documented condition type for the DeviceTaintRuleStatus.
|
||||
const DeviceTaintConditionEvictionInProgress = "EvictionInProgress"
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +k8s:prerelease-lifecycle-gen:introduced=1.33
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ var map_DeviceTaint = map[string]string{
|
|||
"": "The device this taint is attached to has the \"effect\" on any claim which does not tolerate the taint and, through the claim, to pods using the claim.",
|
||||
"key": "The taint key to be applied to a device. Must be a label name.",
|
||||
"value": "The taint value corresponding to the taint key. Must be a label value.",
|
||||
"effect": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"effect": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"timeAdded": "TimeAdded represents the time at which the taint was added. Added automatically during create or update if not set.",
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +61,7 @@ var map_DeviceTaintRule = map[string]string{
|
|||
"": "DeviceTaintRule adds one taint to all devices which match the selector. This has the same effect as if the taint was specified directly in the ResourceSlice by the DRA driver.",
|
||||
"metadata": "Standard object metadata",
|
||||
"spec": "Spec specifies the selector and one taint.\n\nChanging the spec automatically increments the metadata.generation number.",
|
||||
"status": "Status provides information about what was requested in the spec.",
|
||||
}
|
||||
|
||||
func (DeviceTaintRule) SwaggerDoc() map[string]string {
|
||||
|
|
@ -79,7 +80,7 @@ func (DeviceTaintRuleList) SwaggerDoc() map[string]string {
|
|||
|
||||
var map_DeviceTaintRuleSpec = map[string]string{
|
||||
"": "DeviceTaintRuleSpec specifies the selector and one taint.",
|
||||
"deviceSelector": "DeviceSelector defines which device(s) the taint is applied to. All selector criteria must be satified for a device to match. The empty selector matches all devices. Without a selector, no devices are matches.",
|
||||
"deviceSelector": "DeviceSelector defines which device(s) the taint is applied to. All selector criteria must be satisfied for a device to match. The empty selector matches all devices. Without a selector, no devices are matches.",
|
||||
"taint": "The taint that gets applied to matching devices.",
|
||||
}
|
||||
|
||||
|
|
@ -87,13 +88,20 @@ func (DeviceTaintRuleSpec) SwaggerDoc() map[string]string {
|
|||
return map_DeviceTaintRuleSpec
|
||||
}
|
||||
|
||||
var map_DeviceTaintRuleStatus = map[string]string{
|
||||
"": "DeviceTaintRuleStatus provides information about an on-going pod eviction.",
|
||||
"conditions": "Conditions provide information about the state of the DeviceTaintRule and the cluster at some point in time, in a machine-readable and human-readable format.\n\nThe following condition is currently defined as part of this API, more may get added: - Type: EvictionInProgress - Status: True if there are currently pods which need to be evicted, False otherwise\n (includes the effects which don't cause eviction).\n- Reason: not specified, may change - Message: includes information about number of pending pods and already evicted pods\n in a human-readable format, updated periodically, may change\n\nFor `effect: None`, the condition above gets set once for each change to the spec, with the message containing information about what would happen if the effect was `NoExecute`. This feedback can be used to decide whether changing the effect to `NoExecute` will work as intended. It only gets set once to avoid having to constantly update the status.\n\nMust have 8 or fewer entries.",
|
||||
}
|
||||
|
||||
func (DeviceTaintRuleStatus) SwaggerDoc() map[string]string {
|
||||
return map_DeviceTaintRuleStatus
|
||||
}
|
||||
|
||||
var map_DeviceTaintSelector = map[string]string{
|
||||
"": "DeviceTaintSelector defines which device(s) a DeviceTaintRule applies to. The empty selector matches all devices. Without a selector, no devices are matched.",
|
||||
"deviceClassName": "If DeviceClassName is set, the selectors defined there must be satisfied by a device to be selected. This field corresponds to class.metadata.name.",
|
||||
"driver": "If driver is set, only devices from that driver are selected. This fields corresponds to slice.spec.driver.",
|
||||
"pool": "If pool is set, only devices in that pool are selected.\n\nAlso setting the driver name may be useful to avoid ambiguity when different drivers use the same pool name, but this is not required because selecting pools from different drivers may also be useful, for example when drivers with node-local devices use the node name as their pool name.",
|
||||
"device": "If device is set, only devices with that name are selected. This field corresponds to slice.spec.devices[].name.\n\nSetting also driver and pool may be required to avoid ambiguity, but is not required.",
|
||||
"selectors": "Selectors contains the same selection criteria as a ResourceClaim. Currently, CEL expressions are supported. All of these selectors must be satisfied.",
|
||||
"": "DeviceTaintSelector defines which device(s) a DeviceTaintRule applies to. The empty selector matches all devices. Without a selector, no devices are matched.",
|
||||
"driver": "If driver is set, only devices from that driver are selected. This fields corresponds to slice.spec.driver.",
|
||||
"pool": "If pool is set, only devices in that pool are selected.\n\nAlso setting the driver name may be useful to avoid ambiguity when different drivers use the same pool name, but this is not required because selecting pools from different drivers may also be useful, for example when drivers with node-local devices use the node name as their pool name.",
|
||||
"device": "If device is set, only devices with that name are selected. This field corresponds to slice.spec.devices[].name.\n\nSetting also driver and pool may be required to avoid ambiguity, but is not required.",
|
||||
}
|
||||
|
||||
func (DeviceTaintSelector) SwaggerDoc() map[string]string {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ limitations under the License.
|
|||
package v1alpha3
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
|
|
@ -88,6 +89,7 @@ func (in *DeviceTaintRule) DeepCopyInto(out *DeviceTaintRule) {
|
|||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -164,14 +166,32 @@ func (in *DeviceTaintRuleSpec) DeepCopy() *DeviceTaintRuleSpec {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeviceTaintRuleStatus) DeepCopyInto(out *DeviceTaintRuleStatus) {
|
||||
*out = *in
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]v1.Condition, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeviceTaintRuleStatus.
|
||||
func (in *DeviceTaintRuleStatus) DeepCopy() *DeviceTaintRuleStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DeviceTaintRuleStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeviceTaintSelector) DeepCopyInto(out *DeviceTaintSelector) {
|
||||
*out = *in
|
||||
if in.DeviceClassName != nil {
|
||||
in, out := &in.DeviceClassName, &out.DeviceClassName
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.Driver != nil {
|
||||
in, out := &in.Driver, &out.Driver
|
||||
*out = new(string)
|
||||
|
|
@ -187,13 +207,6 @@ func (in *DeviceTaintSelector) DeepCopyInto(out *DeviceTaintSelector) {
|
|||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
if in.Selectors != nil {
|
||||
in, out := &in.Selectors, &out.Selectors
|
||||
*out = make([]DeviceSelector, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,11 @@ func (in DeviceTaintRuleSpec) OpenAPIModelName() string {
|
|||
return "io.k8s.api.resource.v1alpha3.DeviceTaintRuleSpec"
|
||||
}
|
||||
|
||||
// OpenAPIModelName returns the OpenAPI model name for this type.
|
||||
func (in DeviceTaintRuleStatus) OpenAPIModelName() string {
|
||||
return "io.k8s.api.resource.v1alpha3.DeviceTaintRuleStatus"
|
||||
}
|
||||
|
||||
// OpenAPIModelName returns the OpenAPI model name for this type.
|
||||
func (in DeviceTaintSelector) OpenAPIModelName() string {
|
||||
return "io.k8s.api.resource.v1alpha3.DeviceTaintSelector"
|
||||
|
|
|
|||
|
|
@ -185,7 +185,9 @@ message BasicDevice {
|
|||
|
||||
// If specified, these are the driver-defined taints.
|
||||
//
|
||||
// The maximum number of taints is 4.
|
||||
// The maximum number of taints is 16. If taints are set for
|
||||
// any device in a ResourceSlice, then the maximum number of
|
||||
// allowed devices per ResourceSlice is 64 instead of 128.
|
||||
//
|
||||
// This is an alpha field and requires enabling the DRADeviceTaints
|
||||
// feature gate.
|
||||
|
|
@ -1241,8 +1243,10 @@ message DeviceTaint {
|
|||
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
//
|
||||
// +required
|
||||
// +k8s:required
|
||||
|
|
@ -1672,7 +1676,7 @@ message ResourceSliceSpec {
|
|||
|
||||
// Devices lists some or all of the devices in this pool.
|
||||
//
|
||||
// Must not have more than 128 entries.
|
||||
// Must not have more than 128 entries. If any device uses taints the limit is 64.
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ type ResourceSliceSpec struct {
|
|||
|
||||
// Devices lists some or all of the devices in this pool.
|
||||
//
|
||||
// Must not have more than 128 entries.
|
||||
// Must not have more than 128 entries. If any device uses taints the limit is 64.
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
|
|
@ -258,6 +258,7 @@ type ResourcePool struct {
|
|||
|
||||
const ResourceSliceMaxSharedCapacity = 128
|
||||
const ResourceSliceMaxDevices = 128
|
||||
const ResourceSliceMaxDevicesWithTaints = 64
|
||||
const PoolNameMaxLength = validation.DNS1123SubdomainMaxLength // Same as for a single node name.
|
||||
const BindingConditionsMaxSize = 4
|
||||
const BindingFailureConditionsMaxSize = 4
|
||||
|
|
@ -345,7 +346,9 @@ type BasicDevice struct {
|
|||
|
||||
// If specified, these are the driver-defined taints.
|
||||
//
|
||||
// The maximum number of taints is 4.
|
||||
// The maximum number of taints is 16. If taints are set for
|
||||
// any device in a ResourceSlice, then the maximum number of
|
||||
// allowed devices per ResourceSlice is 64 instead of 128.
|
||||
//
|
||||
// This is an alpha field and requires enabling the DRADeviceTaints
|
||||
// feature gate.
|
||||
|
|
@ -622,8 +625,8 @@ type DeviceAttribute struct {
|
|||
// DeviceAttributeMaxValueLength is the maximum length of a string or version attribute value.
|
||||
const DeviceAttributeMaxValueLength = 64
|
||||
|
||||
// DeviceTaintsMaxLength is the maximum number of taints per device.
|
||||
const DeviceTaintsMaxLength = 4
|
||||
// DeviceTaintsMaxLength is the maximum number of taints per Device.
|
||||
const DeviceTaintsMaxLength = 16
|
||||
|
||||
// The device this taint is attached to has the "effect" on
|
||||
// any claim which does not tolerate the taint and, through the claim,
|
||||
|
|
@ -645,8 +648,10 @@ type DeviceTaint struct {
|
|||
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
//
|
||||
// +required
|
||||
// +k8s:required
|
||||
|
|
@ -656,6 +661,14 @@ type DeviceTaint struct {
|
|||
//
|
||||
// Implementing PreferNoSchedule would depend on a scoring solution for DRA.
|
||||
// It might get added as part of that.
|
||||
//
|
||||
// A possible future new effect is NoExecuteWithPodDisruptionBudget:
|
||||
// honor the pod disruption budget instead of simply deleting pods.
|
||||
// This is currently undecided, it could also be a separate field.
|
||||
//
|
||||
// Validation must be prepared to allow unknown enums in stored objects,
|
||||
// which will enable adding new enums within a single release without
|
||||
// ratcheting.
|
||||
|
||||
// TimeAdded represents the time at which the taint was added.
|
||||
// Added automatically during create or update if not set.
|
||||
|
|
@ -675,6 +688,9 @@ type DeviceTaint struct {
|
|||
type DeviceTaintEffect string
|
||||
|
||||
const (
|
||||
// No effect, the taint is purely informational.
|
||||
DeviceTaintEffectNone DeviceTaintEffect = "None"
|
||||
|
||||
// Do not allow new pods to schedule which use a tainted device unless they tolerate the taint,
|
||||
// but allow all pods submitted to Kubelet without going through the scheduler
|
||||
// to start, and allow all already-running pods to continue running.
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ var map_BasicDevice = map[string]string{
|
|||
"nodeName": "NodeName identifies the node where the device is available.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set.",
|
||||
"nodeSelector": "NodeSelector defines the nodes where the device is available.\n\nMust use exactly one term.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set.",
|
||||
"allNodes": "AllNodes indicates that all nodes have access to the device.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set.",
|
||||
"taints": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"taints": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"bindsToNode": "BindsToNode indicates if the usage of an allocation involving this device has to be limited to exactly the node that was chosen when allocating the claim. If set to true, the scheduler will set the ResourceClaim.Status.Allocation.NodeSelector to match the node where the allocation was made.\n\nThis is an alpha field and requires enabling the DRADeviceBindingConditions and DRAResourceClaimDeviceStatus feature gates.",
|
||||
"bindingConditions": "BindingConditions defines the conditions for proceeding with binding. All of these conditions must be set in the per-device status conditions with a value of True to proceed with binding the pod to the node while scheduling the pod.\n\nThe maximum number of binding conditions is 4.\n\nThe conditions must be a valid condition type string.\n\nThis is an alpha field and requires enabling the DRADeviceBindingConditions and DRAResourceClaimDeviceStatus feature gates.",
|
||||
"bindingFailureConditions": "BindingFailureConditions defines the conditions for binding failure. They may be set in the per-device status conditions. If any is true, a binding failure occurred.\n\nThe maximum number of binding failure conditions is 4.\n\nThe conditions must be a valid condition type string.\n\nThis is an alpha field and requires enabling the DRADeviceBindingConditions and DRAResourceClaimDeviceStatus feature gates.",
|
||||
|
|
@ -335,7 +335,7 @@ var map_DeviceTaint = map[string]string{
|
|||
"": "The device this taint is attached to has the \"effect\" on any claim which does not tolerate the taint and, through the claim, to pods using the claim.",
|
||||
"key": "The taint key to be applied to a device. Must be a label name.",
|
||||
"value": "The taint value corresponding to the taint key. Must be a label value.",
|
||||
"effect": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"effect": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"timeAdded": "TimeAdded represents the time at which the taint was added. Added automatically during create or update if not set.",
|
||||
}
|
||||
|
||||
|
|
@ -498,7 +498,7 @@ var map_ResourceSliceSpec = map[string]string{
|
|||
"nodeName": "NodeName identifies the node which provides the resources in this pool. A field selector can be used to list only ResourceSlice objects belonging to a certain node.\n\nThis field can be used to limit access from nodes to ResourceSlices with the same node name. It also indicates to autoscalers that adding new nodes of the same type as some old node might also make new resources available.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set. This field is immutable.",
|
||||
"nodeSelector": "NodeSelector defines which nodes have access to the resources in the pool, when that pool is not limited to a single node.\n\nMust use exactly one term.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.",
|
||||
"allNodes": "AllNodes indicates that all nodes have access to the resources in the pool.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.",
|
||||
"devices": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
"devices": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
"perDeviceNodeSelection": "PerDeviceNodeSelection defines whether the access from nodes to resources in the pool is set on the ResourceSlice level or on each device. If it is set to true, every device defined the ResourceSlice must specify this individually.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.",
|
||||
"sharedCounters": "SharedCounters defines a list of counter sets, each of which has a name and a list of counters available.\n\nThe names of the SharedCounters must be unique in the ResourceSlice.\n\nThe maximum number of SharedCounters is 32.",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,7 +395,9 @@ message Device {
|
|||
|
||||
// If specified, these are the driver-defined taints.
|
||||
//
|
||||
// The maximum number of taints is 4.
|
||||
// The maximum number of taints is 16. If taints are set for
|
||||
// any device in a ResourceSlice, then the maximum number of
|
||||
// allowed devices per ResourceSlice is 64 instead of 128.
|
||||
//
|
||||
// This is an alpha field and requires enabling the DRADeviceTaints
|
||||
// feature gate.
|
||||
|
|
@ -1116,8 +1118,10 @@ message DeviceTaint {
|
|||
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
//
|
||||
// +required
|
||||
// +k8s:required
|
||||
|
|
@ -1658,7 +1662,7 @@ message ResourceSliceSpec {
|
|||
|
||||
// Devices lists some or all of the devices in this pool.
|
||||
//
|
||||
// Must not have more than 128 entries.
|
||||
// Must not have more than 128 entries. If any device uses taints the limit is 64.
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ type ResourceSliceSpec struct {
|
|||
|
||||
// Devices lists some or all of the devices in this pool.
|
||||
//
|
||||
// Must not have more than 128 entries.
|
||||
// Must not have more than 128 entries. If any device uses taints the limit is 64.
|
||||
//
|
||||
// +optional
|
||||
// +listType=atomic
|
||||
|
|
@ -250,6 +250,7 @@ type ResourcePool struct {
|
|||
|
||||
const ResourceSliceMaxSharedCapacity = 128
|
||||
const ResourceSliceMaxDevices = 128
|
||||
const ResourceSliceMaxDevicesWithTaints = 64
|
||||
const PoolNameMaxLength = validation.DNS1123SubdomainMaxLength // Same as for a single node name.
|
||||
const BindingConditionsMaxSize = 4
|
||||
const BindingFailureConditionsMaxSize = 4
|
||||
|
|
@ -333,7 +334,9 @@ type Device struct {
|
|||
|
||||
// If specified, these are the driver-defined taints.
|
||||
//
|
||||
// The maximum number of taints is 4.
|
||||
// The maximum number of taints is 16. If taints are set for
|
||||
// any device in a ResourceSlice, then the maximum number of
|
||||
// allowed devices per ResourceSlice is 64 instead of 128.
|
||||
//
|
||||
// This is an alpha field and requires enabling the DRADeviceTaints
|
||||
// feature gate.
|
||||
|
|
@ -618,8 +621,8 @@ type DeviceAttribute struct {
|
|||
// DeviceAttributeMaxValueLength is the maximum length of a string or version attribute value.
|
||||
const DeviceAttributeMaxValueLength = 64
|
||||
|
||||
// DeviceTaintsMaxLength is the maximum number of taints per device.
|
||||
const DeviceTaintsMaxLength = 4
|
||||
// DeviceTaintsMaxLength is the maximum number of taints per Device.
|
||||
const DeviceTaintsMaxLength = 16
|
||||
|
||||
// The device this taint is attached to has the "effect" on
|
||||
// any claim which does not tolerate the taint and, through the claim,
|
||||
|
|
@ -641,8 +644,10 @@ type DeviceTaint struct {
|
|||
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
//
|
||||
// +required
|
||||
// +k8s:required
|
||||
|
|
@ -652,6 +657,14 @@ type DeviceTaint struct {
|
|||
//
|
||||
// Implementing PreferNoSchedule would depend on a scoring solution for DRA.
|
||||
// It might get added as part of that.
|
||||
//
|
||||
// A possible future new effect is NoExecuteWithPodDisruptionBudget:
|
||||
// honor the pod disruption budget instead of simply deleting pods.
|
||||
// This is currently undecided, it could also be a separate field.
|
||||
//
|
||||
// Validation must be prepared to allow unknown enums in stored objects,
|
||||
// which will enable adding new enums within a single release without
|
||||
// ratcheting.
|
||||
|
||||
// TimeAdded represents the time at which the taint was added.
|
||||
// Added automatically during create or update if not set.
|
||||
|
|
@ -671,6 +684,9 @@ type DeviceTaint struct {
|
|||
type DeviceTaintEffect string
|
||||
|
||||
const (
|
||||
// No effect, the taint is purely informational.
|
||||
DeviceTaintEffectNone DeviceTaintEffect = "None"
|
||||
|
||||
// Do not allow new pods to schedule which use a tainted device unless they tolerate the taint,
|
||||
// but allow all pods submitted to Kubelet without going through the scheduler
|
||||
// to start, and allow all already-running pods to continue running.
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ var map_Device = map[string]string{
|
|||
"nodeName": "NodeName identifies the node where the device is available.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set.",
|
||||
"nodeSelector": "NodeSelector defines the nodes where the device is available.\n\nMust use exactly one term.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set.",
|
||||
"allNodes": "AllNodes indicates that all nodes have access to the device.\n\nMust only be set if Spec.PerDeviceNodeSelection is set to true. At most one of NodeName, NodeSelector and AllNodes can be set.",
|
||||
"taints": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 4.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"taints": "If specified, these are the driver-defined taints.\n\nThe maximum number of taints is 16. If taints are set for any device in a ResourceSlice, then the maximum number of allowed devices per ResourceSlice is 64 instead of 128.\n\nThis is an alpha field and requires enabling the DRADeviceTaints feature gate.",
|
||||
"bindsToNode": "BindsToNode indicates if the usage of an allocation involving this device has to be limited to exactly the node that was chosen when allocating the claim. If set to true, the scheduler will set the ResourceClaim.Status.Allocation.NodeSelector to match the node where the allocation was made.\n\nThis is an alpha field and requires enabling the DRADeviceBindingConditions and DRAResourceClaimDeviceStatus feature gates.",
|
||||
"bindingConditions": "BindingConditions defines the conditions for proceeding with binding. All of these conditions must be set in the per-device status conditions with a value of True to proceed with binding the pod to the node while scheduling the pod.\n\nThe maximum number of binding conditions is 4.\n\nThe conditions must be a valid condition type string.\n\nThis is an alpha field and requires enabling the DRADeviceBindingConditions and DRAResourceClaimDeviceStatus feature gates.",
|
||||
"bindingFailureConditions": "BindingFailureConditions defines the conditions for binding failure. They may be set in the per-device status conditions. If any is set to \"True\", a binding failure occurred.\n\nThe maximum number of binding failure conditions is 4.\n\nThe conditions must be a valid condition type string.\n\nThis is an alpha field and requires enabling the DRADeviceBindingConditions and DRAResourceClaimDeviceStatus feature gates.",
|
||||
|
|
@ -320,7 +320,7 @@ var map_DeviceTaint = map[string]string{
|
|||
"": "The device this taint is attached to has the \"effect\" on any claim which does not tolerate the taint and, through the claim, to pods using the claim.",
|
||||
"key": "The taint key to be applied to a device. Must be a label name.",
|
||||
"value": "The taint value corresponding to the taint key. Must be a label value.",
|
||||
"effect": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them. Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here.",
|
||||
"effect": "The effect of the taint on claims that do not tolerate the taint and through such claims on the pods using them.\n\nValid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for nodes is not valid here. More effects may get added in the future. Consumers must treat unknown effects like None.",
|
||||
"timeAdded": "TimeAdded represents the time at which the taint was added. Added automatically during create or update if not set.",
|
||||
}
|
||||
|
||||
|
|
@ -498,7 +498,7 @@ var map_ResourceSliceSpec = map[string]string{
|
|||
"nodeName": "NodeName identifies the node which provides the resources in this pool. A field selector can be used to list only ResourceSlice objects belonging to a certain node.\n\nThis field can be used to limit access from nodes to ResourceSlices with the same node name. It also indicates to autoscalers that adding new nodes of the same type as some old node might also make new resources available.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set. This field is immutable.",
|
||||
"nodeSelector": "NodeSelector defines which nodes have access to the resources in the pool, when that pool is not limited to a single node.\n\nMust use exactly one term.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.",
|
||||
"allNodes": "AllNodes indicates that all nodes have access to the resources in the pool.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.",
|
||||
"devices": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries.",
|
||||
"devices": "Devices lists some or all of the devices in this pool.\n\nMust not have more than 128 entries. If any device uses taints the limit is 64.",
|
||||
"perDeviceNodeSelection": "PerDeviceNodeSelection defines whether the access from nodes to resources in the pool is set on the ResourceSlice level or on each device. If it is set to true, every device defined the ResourceSlice must specify this individually.\n\nExactly one of NodeName, NodeSelector, AllNodes, and PerDeviceNodeSelection must be set.",
|
||||
"sharedCounters": "SharedCounters defines a list of counter sets, each of which has a name and a list of counters available.\n\nThe names of the SharedCounters must be unique in the ResourceSlice.\n\nThe maximum number of counters in all sets is 32.",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,17 +45,9 @@
|
|||
},
|
||||
"spec": {
|
||||
"deviceSelector": {
|
||||
"deviceClassName": "deviceClassNameValue",
|
||||
"driver": "driverValue",
|
||||
"pool": "poolValue",
|
||||
"device": "deviceValue",
|
||||
"selectors": [
|
||||
{
|
||||
"cel": {
|
||||
"expression": "expressionValue"
|
||||
}
|
||||
}
|
||||
]
|
||||
"device": "deviceValue"
|
||||
},
|
||||
"taint": {
|
||||
"key": "keyValue",
|
||||
|
|
@ -63,5 +55,17 @@
|
|||
"effect": "effectValue",
|
||||
"timeAdded": "2004-01-01T01:01:01Z"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"conditions": [
|
||||
{
|
||||
"type": "typeValue",
|
||||
"status": "statusValue",
|
||||
"observedGeneration": 3,
|
||||
"lastTransitionTime": "2004-01-01T01:01:01Z",
|
||||
"reason": "reasonValue",
|
||||
"message": "messageValue"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -35,14 +35,18 @@ metadata:
|
|||
spec:
|
||||
deviceSelector:
|
||||
device: deviceValue
|
||||
deviceClassName: deviceClassNameValue
|
||||
driver: driverValue
|
||||
pool: poolValue
|
||||
selectors:
|
||||
- cel:
|
||||
expression: expressionValue
|
||||
taint:
|
||||
effect: effectValue
|
||||
key: keyValue
|
||||
timeAdded: "2004-01-01T01:01:01Z"
|
||||
value: valueValue
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2004-01-01T01:01:01Z"
|
||||
message: messageValue
|
||||
observedGeneration: 3
|
||||
reason: reasonValue
|
||||
status: statusValue
|
||||
type: typeValue
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"kind": "DeviceTaintRule",
|
||||
"apiVersion": "resource.k8s.io/v1alpha3",
|
||||
"metadata": {
|
||||
"name": "nameValue",
|
||||
"generateName": "generateNameValue",
|
||||
"namespace": "namespaceValue",
|
||||
"selfLink": "selfLinkValue",
|
||||
"uid": "uidValue",
|
||||
"resourceVersion": "resourceVersionValue",
|
||||
"generation": 7,
|
||||
"creationTimestamp": "2008-01-01T01:01:01Z",
|
||||
"deletionTimestamp": "2009-01-01T01:01:01Z",
|
||||
"deletionGracePeriodSeconds": 10,
|
||||
"labels": {
|
||||
"labelsKey": "labelsValue"
|
||||
},
|
||||
"annotations": {
|
||||
"annotationsKey": "annotationsValue"
|
||||
},
|
||||
"ownerReferences": [
|
||||
{
|
||||
"apiVersion": "apiVersionValue",
|
||||
"kind": "kindValue",
|
||||
"name": "nameValue",
|
||||
"uid": "uidValue",
|
||||
"controller": true,
|
||||
"blockOwnerDeletion": true
|
||||
}
|
||||
],
|
||||
"finalizers": [
|
||||
"finalizersValue"
|
||||
],
|
||||
"managedFields": [
|
||||
{
|
||||
"manager": "managerValue",
|
||||
"operation": "operationValue",
|
||||
"apiVersion": "apiVersionValue",
|
||||
"time": "2004-01-01T01:01:01Z",
|
||||
"fieldsType": "fieldsTypeValue",
|
||||
"fieldsV1": {},
|
||||
"subresource": "subresourceValue"
|
||||
}
|
||||
]
|
||||
},
|
||||
"spec": {
|
||||
"deviceSelector": {
|
||||
"driver": "driverValue",
|
||||
"pool": "poolValue",
|
||||
"device": "deviceValue"
|
||||
},
|
||||
"taint": {
|
||||
"key": "keyValue",
|
||||
"value": "valueValue",
|
||||
"effect": "effectValue",
|
||||
"timeAdded": "2004-01-01T01:01:01Z"
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
BIN
staging/src/k8s.io/api/testdata/v1.33.0/resource.k8s.io.v1alpha3.DeviceTaintRule.after_roundtrip.pb
vendored
Normal file
BIN
staging/src/k8s.io/api/testdata/v1.33.0/resource.k8s.io.v1alpha3.DeviceTaintRule.after_roundtrip.pb
vendored
Normal file
Binary file not shown.
|
|
@ -0,0 +1,45 @@
|
|||
apiVersion: resource.k8s.io/v1alpha3
|
||||
kind: DeviceTaintRule
|
||||
metadata:
|
||||
annotations:
|
||||
annotationsKey: annotationsValue
|
||||
creationTimestamp: "2008-01-01T01:01:01Z"
|
||||
deletionGracePeriodSeconds: 10
|
||||
deletionTimestamp: "2009-01-01T01:01:01Z"
|
||||
finalizers:
|
||||
- finalizersValue
|
||||
generateName: generateNameValue
|
||||
generation: 7
|
||||
labels:
|
||||
labelsKey: labelsValue
|
||||
managedFields:
|
||||
- apiVersion: apiVersionValue
|
||||
fieldsType: fieldsTypeValue
|
||||
fieldsV1: {}
|
||||
manager: managerValue
|
||||
operation: operationValue
|
||||
subresource: subresourceValue
|
||||
time: "2004-01-01T01:01:01Z"
|
||||
name: nameValue
|
||||
namespace: namespaceValue
|
||||
ownerReferences:
|
||||
- apiVersion: apiVersionValue
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: kindValue
|
||||
name: nameValue
|
||||
uid: uidValue
|
||||
resourceVersion: resourceVersionValue
|
||||
selfLink: selfLinkValue
|
||||
uid: uidValue
|
||||
spec:
|
||||
deviceSelector:
|
||||
device: deviceValue
|
||||
driver: driverValue
|
||||
pool: poolValue
|
||||
taint:
|
||||
effect: effectValue
|
||||
key: keyValue
|
||||
timeAdded: "2004-01-01T01:01:01Z"
|
||||
value: valueValue
|
||||
status: {}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"kind": "DeviceTaintRule",
|
||||
"apiVersion": "resource.k8s.io/v1alpha3",
|
||||
"metadata": {
|
||||
"name": "nameValue",
|
||||
"generateName": "generateNameValue",
|
||||
"namespace": "namespaceValue",
|
||||
"selfLink": "selfLinkValue",
|
||||
"uid": "uidValue",
|
||||
"resourceVersion": "resourceVersionValue",
|
||||
"generation": 7,
|
||||
"creationTimestamp": "2008-01-01T01:01:01Z",
|
||||
"deletionTimestamp": "2009-01-01T01:01:01Z",
|
||||
"deletionGracePeriodSeconds": 10,
|
||||
"labels": {
|
||||
"labelsKey": "labelsValue"
|
||||
},
|
||||
"annotations": {
|
||||
"annotationsKey": "annotationsValue"
|
||||
},
|
||||
"ownerReferences": [
|
||||
{
|
||||
"apiVersion": "apiVersionValue",
|
||||
"kind": "kindValue",
|
||||
"name": "nameValue",
|
||||
"uid": "uidValue",
|
||||
"controller": true,
|
||||
"blockOwnerDeletion": true
|
||||
}
|
||||
],
|
||||
"finalizers": [
|
||||
"finalizersValue"
|
||||
],
|
||||
"managedFields": [
|
||||
{
|
||||
"manager": "managerValue",
|
||||
"operation": "operationValue",
|
||||
"apiVersion": "apiVersionValue",
|
||||
"time": "2004-01-01T01:01:01Z",
|
||||
"fieldsType": "fieldsTypeValue",
|
||||
"fieldsV1": {},
|
||||
"subresource": "subresourceValue"
|
||||
}
|
||||
]
|
||||
},
|
||||
"spec": {
|
||||
"deviceSelector": {
|
||||
"driver": "driverValue",
|
||||
"pool": "poolValue",
|
||||
"device": "deviceValue"
|
||||
},
|
||||
"taint": {
|
||||
"key": "keyValue",
|
||||
"value": "valueValue",
|
||||
"effect": "effectValue",
|
||||
"timeAdded": "2004-01-01T01:01:01Z"
|
||||
}
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
BIN
staging/src/k8s.io/api/testdata/v1.34.0/resource.k8s.io.v1alpha3.DeviceTaintRule.after_roundtrip.pb
vendored
Normal file
BIN
staging/src/k8s.io/api/testdata/v1.34.0/resource.k8s.io.v1alpha3.DeviceTaintRule.after_roundtrip.pb
vendored
Normal file
Binary file not shown.
|
|
@ -0,0 +1,45 @@
|
|||
apiVersion: resource.k8s.io/v1alpha3
|
||||
kind: DeviceTaintRule
|
||||
metadata:
|
||||
annotations:
|
||||
annotationsKey: annotationsValue
|
||||
creationTimestamp: "2008-01-01T01:01:01Z"
|
||||
deletionGracePeriodSeconds: 10
|
||||
deletionTimestamp: "2009-01-01T01:01:01Z"
|
||||
finalizers:
|
||||
- finalizersValue
|
||||
generateName: generateNameValue
|
||||
generation: 7
|
||||
labels:
|
||||
labelsKey: labelsValue
|
||||
managedFields:
|
||||
- apiVersion: apiVersionValue
|
||||
fieldsType: fieldsTypeValue
|
||||
fieldsV1: {}
|
||||
manager: managerValue
|
||||
operation: operationValue
|
||||
subresource: subresourceValue
|
||||
time: "2004-01-01T01:01:01Z"
|
||||
name: nameValue
|
||||
namespace: namespaceValue
|
||||
ownerReferences:
|
||||
- apiVersion: apiVersionValue
|
||||
blockOwnerDeletion: true
|
||||
controller: true
|
||||
kind: kindValue
|
||||
name: nameValue
|
||||
uid: uidValue
|
||||
resourceVersion: resourceVersionValue
|
||||
selfLink: selfLinkValue
|
||||
uid: uidValue
|
||||
spec:
|
||||
deviceSelector:
|
||||
device: deviceValue
|
||||
driver: driverValue
|
||||
pool: poolValue
|
||||
taint:
|
||||
effect: effectValue
|
||||
key: keyValue
|
||||
timeAdded: "2004-01-01T01:01:01Z"
|
||||
value: valueValue
|
||||
status: {}
|
||||
|
|
@ -13486,19 +13486,6 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||
elementType:
|
||||
namedType: io.k8s.api.resource.v1.CounterSet
|
||||
elementRelationship: atomic
|
||||
- name: io.k8s.api.resource.v1alpha3.CELDeviceSelector
|
||||
map:
|
||||
fields:
|
||||
- name: expression
|
||||
type:
|
||||
scalar: string
|
||||
default: ""
|
||||
- name: io.k8s.api.resource.v1alpha3.DeviceSelector
|
||||
map:
|
||||
fields:
|
||||
- name: cel
|
||||
type:
|
||||
namedType: io.k8s.api.resource.v1alpha3.CELDeviceSelector
|
||||
- name: io.k8s.api.resource.v1alpha3.DeviceTaint
|
||||
map:
|
||||
fields:
|
||||
|
|
@ -13533,6 +13520,10 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||
type:
|
||||
namedType: io.k8s.api.resource.v1alpha3.DeviceTaintRuleSpec
|
||||
default: {}
|
||||
- name: status
|
||||
type:
|
||||
namedType: io.k8s.api.resource.v1alpha3.DeviceTaintRuleStatus
|
||||
default: {}
|
||||
- name: io.k8s.api.resource.v1alpha3.DeviceTaintRuleSpec
|
||||
map:
|
||||
fields:
|
||||
|
|
@ -13543,27 +13534,29 @@ var schemaYAML = typed.YAMLObject(`types:
|
|||
type:
|
||||
namedType: io.k8s.api.resource.v1alpha3.DeviceTaint
|
||||
default: {}
|
||||
- name: io.k8s.api.resource.v1alpha3.DeviceTaintRuleStatus
|
||||
map:
|
||||
fields:
|
||||
- name: conditions
|
||||
type:
|
||||
list:
|
||||
elementType:
|
||||
namedType: io.k8s.apimachinery.pkg.apis.meta.v1.Condition
|
||||
elementRelationship: associative
|
||||
keys:
|
||||
- type
|
||||
- name: io.k8s.api.resource.v1alpha3.DeviceTaintSelector
|
||||
map:
|
||||
fields:
|
||||
- name: device
|
||||
type:
|
||||
scalar: string
|
||||
- name: deviceClassName
|
||||
type:
|
||||
scalar: string
|
||||
- name: driver
|
||||
type:
|
||||
scalar: string
|
||||
- name: pool
|
||||
type:
|
||||
scalar: string
|
||||
- name: selectors
|
||||
type:
|
||||
list:
|
||||
elementType:
|
||||
namedType: io.k8s.api.resource.v1alpha3.DeviceSelector
|
||||
elementRelationship: atomic
|
||||
- name: io.k8s.api.resource.v1beta1.AllocatedDeviceStatus
|
||||
map:
|
||||
fields:
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@ type DeviceApplyConfiguration struct {
|
|||
AllNodes *bool `json:"allNodes,omitempty"`
|
||||
// If specified, these are the driver-defined taints.
|
||||
//
|
||||
// The maximum number of taints is 4.
|
||||
// The maximum number of taints is 16. If taints are set for
|
||||
// any device in a ResourceSlice, then the maximum number of
|
||||
// allowed devices per ResourceSlice is 64 instead of 128.
|
||||
//
|
||||
// This is an alpha field and requires enabling the DRADeviceTaints
|
||||
// feature gate.
|
||||
|
|
|
|||
|
|
@ -38,8 +38,10 @@ type DeviceTaintApplyConfiguration struct {
|
|||
Value *string `json:"value,omitempty"`
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
Effect *resourcev1.DeviceTaintEffect `json:"effect,omitempty"`
|
||||
// TimeAdded represents the time at which the taint was added.
|
||||
// Added automatically during create or update if not set.
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ type ResourceSliceSpecApplyConfiguration struct {
|
|||
AllNodes *bool `json:"allNodes,omitempty"`
|
||||
// Devices lists some or all of the devices in this pool.
|
||||
//
|
||||
// Must not have more than 128 entries.
|
||||
// Must not have more than 128 entries. If any device uses taints the limit is 64.
|
||||
Devices []DeviceApplyConfiguration `json:"devices,omitempty"`
|
||||
// PerDeviceNodeSelection defines whether the access from nodes to
|
||||
// resources in the pool is set on the ResourceSlice level or on each
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha3
|
||||
|
||||
// CELDeviceSelectorApplyConfiguration represents a declarative configuration of the CELDeviceSelector type for use
|
||||
// with apply.
|
||||
//
|
||||
// CELDeviceSelector contains a CEL expression for selecting a device.
|
||||
type CELDeviceSelectorApplyConfiguration struct {
|
||||
// Expression is a CEL expression which evaluates a single device. It
|
||||
// must evaluate to true when the device under consideration satisfies
|
||||
// the desired criteria, and false when it does not. Any other result
|
||||
// is an error and causes allocation of devices to abort.
|
||||
//
|
||||
// The expression's input is an object named "device", which carries
|
||||
// the following properties:
|
||||
// - driver (string): the name of the driver which defines this device.
|
||||
// - attributes (map[string]object): the device's attributes, grouped by prefix
|
||||
// (e.g. device.attributes["dra.example.com"] evaluates to an object with all
|
||||
// of the attributes which were prefixed by "dra.example.com".
|
||||
// - capacity (map[string]object): the device's capacities, grouped by prefix.
|
||||
//
|
||||
// Example: Consider a device with driver="dra.example.com", which exposes
|
||||
// two attributes named "model" and "ext.example.com/family" and which
|
||||
// exposes one capacity named "modules". This input to this expression
|
||||
// would have the following fields:
|
||||
//
|
||||
// device.driver
|
||||
// device.attributes["dra.example.com"].model
|
||||
// device.attributes["ext.example.com"].family
|
||||
// device.capacity["dra.example.com"].modules
|
||||
//
|
||||
// The device.driver field can be used to check for a specific driver,
|
||||
// either as a high-level precondition (i.e. you only want to consider
|
||||
// devices from this driver) or as part of a multi-clause expression
|
||||
// that is meant to consider devices from different drivers.
|
||||
//
|
||||
// The value type of each attribute is defined by the device
|
||||
// definition, and users who write these expressions must consult the
|
||||
// documentation for their specific drivers. The value type of each
|
||||
// capacity is Quantity.
|
||||
//
|
||||
// If an unknown prefix is used as a lookup in either device.attributes
|
||||
// or device.capacity, an empty map will be returned. Any reference to
|
||||
// an unknown field will cause an evaluation error and allocation to
|
||||
// abort.
|
||||
//
|
||||
// A robust expression should check for the existence of attributes
|
||||
// before referencing them.
|
||||
//
|
||||
// For ease of use, the cel.bind() function is enabled, and can be used
|
||||
// to simplify expressions that access multiple attributes with the
|
||||
// same domain. For example:
|
||||
//
|
||||
// cel.bind(dra, device.attributes["dra.example.com"], dra.someBool && dra.anotherBool)
|
||||
//
|
||||
// The length of the expression must be smaller or equal to 10 Ki. The
|
||||
// cost of evaluating it is also limited based on the estimated number
|
||||
// of logical steps.
|
||||
Expression *string `json:"expression,omitempty"`
|
||||
}
|
||||
|
||||
// CELDeviceSelectorApplyConfiguration constructs a declarative configuration of the CELDeviceSelector type for use with
|
||||
// apply.
|
||||
func CELDeviceSelector() *CELDeviceSelectorApplyConfiguration {
|
||||
return &CELDeviceSelectorApplyConfiguration{}
|
||||
}
|
||||
|
||||
// WithExpression sets the Expression field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Expression field is set to the value of the last call.
|
||||
func (b *CELDeviceSelectorApplyConfiguration) WithExpression(value string) *CELDeviceSelectorApplyConfiguration {
|
||||
b.Expression = &value
|
||||
return b
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha3
|
||||
|
||||
// DeviceSelectorApplyConfiguration represents a declarative configuration of the DeviceSelector type for use
|
||||
// with apply.
|
||||
//
|
||||
// DeviceSelector must have exactly one field set.
|
||||
type DeviceSelectorApplyConfiguration struct {
|
||||
// CEL contains a CEL expression for selecting a device.
|
||||
CEL *CELDeviceSelectorApplyConfiguration `json:"cel,omitempty"`
|
||||
}
|
||||
|
||||
// DeviceSelectorApplyConfiguration constructs a declarative configuration of the DeviceSelector type for use with
|
||||
// apply.
|
||||
func DeviceSelector() *DeviceSelectorApplyConfiguration {
|
||||
return &DeviceSelectorApplyConfiguration{}
|
||||
}
|
||||
|
||||
// WithCEL sets the CEL field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the CEL field is set to the value of the last call.
|
||||
func (b *DeviceSelectorApplyConfiguration) WithCEL(value *CELDeviceSelectorApplyConfiguration) *DeviceSelectorApplyConfiguration {
|
||||
b.CEL = value
|
||||
return b
|
||||
}
|
||||
|
|
@ -38,8 +38,10 @@ type DeviceTaintApplyConfiguration struct {
|
|||
Value *string `json:"value,omitempty"`
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
Effect *resourcev1alpha3.DeviceTaintEffect `json:"effect,omitempty"`
|
||||
// TimeAdded represents the time at which the taint was added.
|
||||
// Added automatically during create or update if not set.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ type DeviceTaintRuleApplyConfiguration struct {
|
|||
//
|
||||
// Changing the spec automatically increments the metadata.generation number.
|
||||
Spec *DeviceTaintRuleSpecApplyConfiguration `json:"spec,omitempty"`
|
||||
// Status provides information about what was requested in the spec.
|
||||
Status *DeviceTaintRuleStatusApplyConfiguration `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// DeviceTaintRule constructs a declarative configuration of the DeviceTaintRule type for use with
|
||||
|
|
@ -87,6 +89,12 @@ func ExtractDeviceTaintRule(deviceTaintRule *resourcev1alpha3.DeviceTaintRule, f
|
|||
return ExtractDeviceTaintRuleFrom(deviceTaintRule, fieldManager, "")
|
||||
}
|
||||
|
||||
// ExtractDeviceTaintRuleStatus extracts the applied configuration owned by fieldManager from
|
||||
// deviceTaintRule for the status subresource.
|
||||
func ExtractDeviceTaintRuleStatus(deviceTaintRule *resourcev1alpha3.DeviceTaintRule, fieldManager string) (*DeviceTaintRuleApplyConfiguration, error) {
|
||||
return ExtractDeviceTaintRuleFrom(deviceTaintRule, fieldManager, "status")
|
||||
}
|
||||
|
||||
func (b DeviceTaintRuleApplyConfiguration) IsApplyConfiguration() {}
|
||||
|
||||
// WithKind sets the Kind field in the declarative configuration to the given value
|
||||
|
|
@ -255,6 +263,14 @@ func (b *DeviceTaintRuleApplyConfiguration) WithSpec(value *DeviceTaintRuleSpecA
|
|||
return b
|
||||
}
|
||||
|
||||
// WithStatus sets the Status field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Status field is set to the value of the last call.
|
||||
func (b *DeviceTaintRuleApplyConfiguration) WithStatus(value *DeviceTaintRuleStatusApplyConfiguration) *DeviceTaintRuleApplyConfiguration {
|
||||
b.Status = value
|
||||
return b
|
||||
}
|
||||
|
||||
// GetKind retrieves the value of the Kind field in the declarative configuration.
|
||||
func (b *DeviceTaintRuleApplyConfiguration) GetKind() *string {
|
||||
return b.TypeMetaApplyConfiguration.Kind
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ package v1alpha3
|
|||
// DeviceTaintRuleSpec specifies the selector and one taint.
|
||||
type DeviceTaintRuleSpecApplyConfiguration struct {
|
||||
// DeviceSelector defines which device(s) the taint is applied to.
|
||||
// All selector criteria must be satified for a device to
|
||||
// All selector criteria must be satisfied for a device to
|
||||
// match. The empty selector matches all devices. Without
|
||||
// a selector, no devices are matches.
|
||||
DeviceSelector *DeviceTaintSelectorApplyConfiguration `json:"deviceSelector,omitempty"`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by applyconfiguration-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha3
|
||||
|
||||
import (
|
||||
v1 "k8s.io/client-go/applyconfigurations/meta/v1"
|
||||
)
|
||||
|
||||
// DeviceTaintRuleStatusApplyConfiguration represents a declarative configuration of the DeviceTaintRuleStatus type for use
|
||||
// with apply.
|
||||
//
|
||||
// DeviceTaintRuleStatus provides information about an on-going pod eviction.
|
||||
type DeviceTaintRuleStatusApplyConfiguration struct {
|
||||
// Conditions provide information about the state of the DeviceTaintRule
|
||||
// and the cluster at some point in time,
|
||||
// in a machine-readable and human-readable format.
|
||||
//
|
||||
// The following condition is currently defined as part of this API, more may
|
||||
// get added:
|
||||
// - Type: EvictionInProgress
|
||||
// - Status: True if there are currently pods which need to be evicted, False otherwise
|
||||
// (includes the effects which don't cause eviction).
|
||||
// - Reason: not specified, may change
|
||||
// - Message: includes information about number of pending pods and already evicted pods
|
||||
// in a human-readable format, updated periodically, may change
|
||||
//
|
||||
// For `effect: None`, the condition above gets set once for each change to
|
||||
// the spec, with the message containing information about what would happen
|
||||
// if the effect was `NoExecute`. This feedback can be used to decide whether
|
||||
// changing the effect to `NoExecute` will work as intended. It only gets
|
||||
// set once to avoid having to constantly update the status.
|
||||
//
|
||||
// Must have 8 or fewer entries.
|
||||
Conditions []v1.ConditionApplyConfiguration `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
// DeviceTaintRuleStatusApplyConfiguration constructs a declarative configuration of the DeviceTaintRuleStatus type for use with
|
||||
// apply.
|
||||
func DeviceTaintRuleStatus() *DeviceTaintRuleStatusApplyConfiguration {
|
||||
return &DeviceTaintRuleStatusApplyConfiguration{}
|
||||
}
|
||||
|
||||
// WithConditions adds the given value to the Conditions field in the declarative configuration
|
||||
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||
// If called multiple times, values provided by each call will be appended to the Conditions field.
|
||||
func (b *DeviceTaintRuleStatusApplyConfiguration) WithConditions(values ...*v1.ConditionApplyConfiguration) *DeviceTaintRuleStatusApplyConfiguration {
|
||||
for i := range values {
|
||||
if values[i] == nil {
|
||||
panic("nil value passed to WithConditions")
|
||||
}
|
||||
b.Conditions = append(b.Conditions, *values[i])
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
|
@ -25,10 +25,6 @@ package v1alpha3
|
|||
// The empty selector matches all devices. Without a selector, no devices
|
||||
// are matched.
|
||||
type DeviceTaintSelectorApplyConfiguration struct {
|
||||
// If DeviceClassName is set, the selectors defined there must be
|
||||
// satisfied by a device to be selected. This field corresponds
|
||||
// to class.metadata.name.
|
||||
DeviceClassName *string `json:"deviceClassName,omitempty"`
|
||||
// If driver is set, only devices from that driver are selected.
|
||||
// This fields corresponds to slice.spec.driver.
|
||||
Driver *string `json:"driver,omitempty"`
|
||||
|
|
@ -47,10 +43,6 @@ type DeviceTaintSelectorApplyConfiguration struct {
|
|||
// Setting also driver and pool may be required to avoid ambiguity,
|
||||
// but is not required.
|
||||
Device *string `json:"device,omitempty"`
|
||||
// Selectors contains the same selection criteria as a ResourceClaim.
|
||||
// Currently, CEL expressions are supported. All of these selectors
|
||||
// must be satisfied.
|
||||
Selectors []DeviceSelectorApplyConfiguration `json:"selectors,omitempty"`
|
||||
}
|
||||
|
||||
// DeviceTaintSelectorApplyConfiguration constructs a declarative configuration of the DeviceTaintSelector type for use with
|
||||
|
|
@ -59,14 +51,6 @@ func DeviceTaintSelector() *DeviceTaintSelectorApplyConfiguration {
|
|||
return &DeviceTaintSelectorApplyConfiguration{}
|
||||
}
|
||||
|
||||
// WithDeviceClassName sets the DeviceClassName field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the DeviceClassName field is set to the value of the last call.
|
||||
func (b *DeviceTaintSelectorApplyConfiguration) WithDeviceClassName(value string) *DeviceTaintSelectorApplyConfiguration {
|
||||
b.DeviceClassName = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithDriver sets the Driver field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the Driver field is set to the value of the last call.
|
||||
|
|
@ -90,16 +74,3 @@ func (b *DeviceTaintSelectorApplyConfiguration) WithDevice(value string) *Device
|
|||
b.Device = &value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithSelectors adds the given value to the Selectors field in the declarative configuration
|
||||
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
|
||||
// If called multiple times, values provided by each call will be appended to the Selectors field.
|
||||
func (b *DeviceTaintSelectorApplyConfiguration) WithSelectors(values ...*DeviceSelectorApplyConfiguration) *DeviceTaintSelectorApplyConfiguration {
|
||||
for i := range values {
|
||||
if values[i] == nil {
|
||||
panic("nil value passed to WithSelectors")
|
||||
}
|
||||
b.Selectors = append(b.Selectors, *values[i])
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,9 @@ type BasicDeviceApplyConfiguration struct {
|
|||
AllNodes *bool `json:"allNodes,omitempty"`
|
||||
// If specified, these are the driver-defined taints.
|
||||
//
|
||||
// The maximum number of taints is 4.
|
||||
// The maximum number of taints is 16. If taints are set for
|
||||
// any device in a ResourceSlice, then the maximum number of
|
||||
// allowed devices per ResourceSlice is 64 instead of 128.
|
||||
//
|
||||
// This is an alpha field and requires enabling the DRADeviceTaints
|
||||
// feature gate.
|
||||
|
|
|
|||
|
|
@ -38,8 +38,10 @@ type DeviceTaintApplyConfiguration struct {
|
|||
Value *string `json:"value,omitempty"`
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
Effect *resourcev1beta1.DeviceTaintEffect `json:"effect,omitempty"`
|
||||
// TimeAdded represents the time at which the taint was added.
|
||||
// Added automatically during create or update if not set.
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ type ResourceSliceSpecApplyConfiguration struct {
|
|||
AllNodes *bool `json:"allNodes,omitempty"`
|
||||
// Devices lists some or all of the devices in this pool.
|
||||
//
|
||||
// Must not have more than 128 entries.
|
||||
// Must not have more than 128 entries. If any device uses taints the limit is 64.
|
||||
Devices []DeviceApplyConfiguration `json:"devices,omitempty"`
|
||||
// PerDeviceNodeSelection defines whether the access from nodes to
|
||||
// resources in the pool is set on the ResourceSlice level or on each
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@ type DeviceApplyConfiguration struct {
|
|||
AllNodes *bool `json:"allNodes,omitempty"`
|
||||
// If specified, these are the driver-defined taints.
|
||||
//
|
||||
// The maximum number of taints is 4.
|
||||
// The maximum number of taints is 16. If taints are set for
|
||||
// any device in a ResourceSlice, then the maximum number of
|
||||
// allowed devices per ResourceSlice is 64 instead of 128.
|
||||
//
|
||||
// This is an alpha field and requires enabling the DRADeviceTaints
|
||||
// feature gate.
|
||||
|
|
|
|||
|
|
@ -38,8 +38,10 @@ type DeviceTaintApplyConfiguration struct {
|
|||
Value *string `json:"value,omitempty"`
|
||||
// The effect of the taint on claims that do not tolerate the taint
|
||||
// and through such claims on the pods using them.
|
||||
// Valid effects are NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here.
|
||||
//
|
||||
// Valid effects are None, NoSchedule and NoExecute. PreferNoSchedule as used for
|
||||
// nodes is not valid here. More effects may get added in the future.
|
||||
// Consumers must treat unknown effects like None.
|
||||
Effect *resourcev1beta2.DeviceTaintEffect `json:"effect,omitempty"`
|
||||
// TimeAdded represents the time at which the taint was added.
|
||||
// Added automatically during create or update if not set.
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ type ResourceSliceSpecApplyConfiguration struct {
|
|||
AllNodes *bool `json:"allNodes,omitempty"`
|
||||
// Devices lists some or all of the devices in this pool.
|
||||
//
|
||||
// Must not have more than 128 entries.
|
||||
// Must not have more than 128 entries. If any device uses taints the limit is 64.
|
||||
Devices []DeviceApplyConfiguration `json:"devices,omitempty"`
|
||||
// PerDeviceNodeSelection defines whether the access from nodes to
|
||||
// resources in the pool is set on the ResourceSlice level or on each
|
||||
|
|
|
|||
|
|
@ -1710,16 +1710,14 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
|
|||
return &applyconfigurationsresourcev1.ResourceSliceSpecApplyConfiguration{}
|
||||
|
||||
// Group=resource.k8s.io, Version=v1alpha3
|
||||
case v1alpha3.SchemeGroupVersion.WithKind("CELDeviceSelector"):
|
||||
return &resourcev1alpha3.CELDeviceSelectorApplyConfiguration{}
|
||||
case v1alpha3.SchemeGroupVersion.WithKind("DeviceSelector"):
|
||||
return &resourcev1alpha3.DeviceSelectorApplyConfiguration{}
|
||||
case v1alpha3.SchemeGroupVersion.WithKind("DeviceTaint"):
|
||||
return &resourcev1alpha3.DeviceTaintApplyConfiguration{}
|
||||
case v1alpha3.SchemeGroupVersion.WithKind("DeviceTaintRule"):
|
||||
return &resourcev1alpha3.DeviceTaintRuleApplyConfiguration{}
|
||||
case v1alpha3.SchemeGroupVersion.WithKind("DeviceTaintRuleSpec"):
|
||||
return &resourcev1alpha3.DeviceTaintRuleSpecApplyConfiguration{}
|
||||
case v1alpha3.SchemeGroupVersion.WithKind("DeviceTaintRuleStatus"):
|
||||
return &resourcev1alpha3.DeviceTaintRuleStatusApplyConfiguration{}
|
||||
case v1alpha3.SchemeGroupVersion.WithKind("DeviceTaintSelector"):
|
||||
return &resourcev1alpha3.DeviceTaintSelectorApplyConfiguration{}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ type DeviceTaintRulesGetter interface {
|
|||
type DeviceTaintRuleInterface interface {
|
||||
Create(ctx context.Context, deviceTaintRule *resourcev1alpha3.DeviceTaintRule, opts v1.CreateOptions) (*resourcev1alpha3.DeviceTaintRule, error)
|
||||
Update(ctx context.Context, deviceTaintRule *resourcev1alpha3.DeviceTaintRule, opts v1.UpdateOptions) (*resourcev1alpha3.DeviceTaintRule, error)
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
UpdateStatus(ctx context.Context, deviceTaintRule *resourcev1alpha3.DeviceTaintRule, opts v1.UpdateOptions) (*resourcev1alpha3.DeviceTaintRule, error)
|
||||
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*resourcev1alpha3.DeviceTaintRule, error)
|
||||
|
|
@ -47,6 +49,8 @@ type DeviceTaintRuleInterface interface {
|
|||
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *resourcev1alpha3.DeviceTaintRule, err error)
|
||||
Apply(ctx context.Context, deviceTaintRule *applyconfigurationsresourcev1alpha3.DeviceTaintRuleApplyConfiguration, opts v1.ApplyOptions) (result *resourcev1alpha3.DeviceTaintRule, err error)
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus().
|
||||
ApplyStatus(ctx context.Context, deviceTaintRule *applyconfigurationsresourcev1alpha3.DeviceTaintRuleApplyConfiguration, opts v1.ApplyOptions) (result *resourcev1alpha3.DeviceTaintRule, err error)
|
||||
DeviceTaintRuleExpansion
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -216,6 +216,16 @@ func (m *Mock[T]) AddAfter(item T, duration time.Duration) {
|
|||
m.state.Later = append(m.state.Later, MockDelayedItem[T]{Item: item, Duration: duration})
|
||||
}
|
||||
|
||||
// CancelAfter is an extension of the TypedDelayingInterface: it allows a test to remove an item that may or may not have been added before via AddAfter.
|
||||
func (m *Mock[T]) CancelAfter(item T) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
m.state.Later = slices.DeleteFunc(m.state.Later, func(later MockDelayedItem[T]) bool {
|
||||
return later.Item == item
|
||||
})
|
||||
}
|
||||
|
||||
// AddRateLimited implements [TypedRateLimitingInterface.AddRateLimited].
|
||||
func (m *Mock[T]) AddRateLimited(item T) {
|
||||
m.mutex.Lock()
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ import (
|
|||
// 3. Empty toleration.key means to match all taint keys.
|
||||
// If toleration.key is empty, toleration.operator must be 'Exists';
|
||||
// this combination means to match all taint values and all taint keys.
|
||||
//
|
||||
// Callers must check separately what the effect is and only react to
|
||||
// known effects. Unknown effects and the None effect must be ignored.
|
||||
func ToleratesTaint(toleration resourceapi.DeviceToleration, taint resourceapi.DeviceTaint) bool {
|
||||
// This code was copied from https://github.com/kubernetes/kubernetes/blob/f007012f5fe49e40ae0596cf463a8e7b247b3357/staging/src/k8s.io/api/core/v1/toleration.go#L39-L56.
|
||||
// It wasn't placed in the resourceapi package because code related to logic
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import (
|
|||
resourcelisters "k8s.io/client-go/listers/resource/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/dynamic-resource-allocation/cel"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/utils/buffer"
|
||||
"k8s.io/utils/ptr"
|
||||
|
|
@ -65,7 +64,6 @@ type Tracker struct {
|
|||
deviceTaintsHandle cache.ResourceEventHandlerRegistration
|
||||
deviceClasses cache.SharedIndexInformer
|
||||
deviceClassesHandle cache.ResourceEventHandlerRegistration
|
||||
celCache *cel.Cache
|
||||
patchedResourceSlices cache.Store
|
||||
broadcaster record.EventBroadcaster
|
||||
recorder record.EventRecorder
|
||||
|
|
@ -155,7 +153,6 @@ func newTracker(ctx context.Context, opts Options) (finalT *Tracker, finalErr er
|
|||
resourceSlices: opts.SliceInformer.Informer(),
|
||||
deviceTaints: opts.TaintInformer.Informer(),
|
||||
deviceClasses: opts.ClassInformer.Informer(),
|
||||
celCache: cel.NewCache(10, cel.Features{EnableConsumableCapacity: opts.EnableConsumableCapacity}),
|
||||
patchedResourceSlices: cache.NewStore(cache.MetaNamespaceKeyFunc),
|
||||
handleError: utilruntime.HandleErrorWithContext,
|
||||
eventQueue: *buffer.NewRing[func()](buffer.RingOptions{InitialSize: 0, NormalSize: 4}),
|
||||
|
|
@ -644,8 +641,6 @@ func (t *Tracker) applyPatches(ctx context.Context, slice *resourceapi.ResourceS
|
|||
logger.V(6).Info("processing DeviceTaintRule")
|
||||
|
||||
deviceSelector := taintRule.Spec.DeviceSelector
|
||||
var deviceClassExprs []cel.CompilationResult
|
||||
var selectorExprs []cel.CompilationResult
|
||||
var deviceName *string
|
||||
if deviceSelector != nil {
|
||||
if deviceSelector.Driver != nil && *deviceSelector.Driver != slice.Spec.Driver {
|
||||
|
|
@ -657,32 +652,7 @@ func (t *Tracker) applyPatches(ctx context.Context, slice *resourceapi.ResourceS
|
|||
continue
|
||||
}
|
||||
deviceName = deviceSelector.Device
|
||||
if deviceSelector.DeviceClassName != nil {
|
||||
logger := logger.WithValues("deviceClassName", *deviceSelector.DeviceClassName)
|
||||
classObj, exists, err := t.deviceClasses.GetIndexer().GetByKey(*deviceSelector.DeviceClassName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get device class %s for DeviceTaintRule %s", *deviceSelector.DeviceClassName, taintRule.Name)
|
||||
}
|
||||
if !exists {
|
||||
logger.V(7).Info("DeviceTaintRule does not apply, DeviceClass does not exist")
|
||||
continue
|
||||
}
|
||||
class := classObj.(*resourceapi.DeviceClass)
|
||||
for _, selector := range class.Spec.Selectors {
|
||||
if selector.CEL != nil {
|
||||
expr := t.celCache.GetOrCompile(selector.CEL.Expression)
|
||||
deviceClassExprs = append(deviceClassExprs, expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, selector := range deviceSelector.Selectors {
|
||||
if selector.CEL != nil {
|
||||
expr := t.celCache.GetOrCompile(selector.CEL.Expression)
|
||||
selectorExprs = append(selectorExprs, expr)
|
||||
}
|
||||
}
|
||||
}
|
||||
devices:
|
||||
for dIndex, device := range slice.Spec.Devices {
|
||||
deviceID := deviceID(slice.Spec.Driver, slice.Spec.Pool.Name, device.Name)
|
||||
logger := logger.WithValues("device", deviceID)
|
||||
|
|
@ -692,47 +662,6 @@ func (t *Tracker) applyPatches(ctx context.Context, slice *resourceapi.ResourceS
|
|||
continue
|
||||
}
|
||||
|
||||
for i, expr := range deviceClassExprs {
|
||||
if expr.Error != nil {
|
||||
// Could happen if some future apiserver accepted some
|
||||
// future expression and then got downgraded. Normally
|
||||
// the "stored expression" mechanism prevents that, but
|
||||
// this code here might be more than one release older
|
||||
// than the cluster it runs in.
|
||||
return nil, fmt.Errorf("DeviceTaintRule %s: class %s: selector #%d: CEL compile error: %w", taintRule.Name, *deviceSelector.DeviceClassName, i, expr.Error)
|
||||
}
|
||||
matches, details, err := expr.DeviceMatches(ctx, cel.Device{Driver: slice.Spec.Driver, Attributes: device.Attributes, Capacity: device.Capacity})
|
||||
logger.V(7).Info("CEL result", "class", *deviceSelector.DeviceClassName, "selector", i, "expression", expr.Expression, "matches", matches, "actualCost", ptr.Deref(details.ActualCost(), 0), "err", err)
|
||||
if err != nil {
|
||||
continue devices
|
||||
}
|
||||
if !matches {
|
||||
continue devices
|
||||
}
|
||||
}
|
||||
|
||||
for i, expr := range selectorExprs {
|
||||
if expr.Error != nil {
|
||||
// Could happen if some future apiserver accepted some
|
||||
// future expression and then got downgraded. Normally
|
||||
// the "stored expression" mechanism prevents that, but
|
||||
// this code here might be more than one release older
|
||||
// than the cluster it runs in.
|
||||
return nil, fmt.Errorf("DeviceTaintRule %s: selector #%d: CEL compile error: %w", taintRule.Name, i, expr.Error)
|
||||
}
|
||||
matches, details, err := expr.DeviceMatches(ctx, cel.Device{Driver: slice.Spec.Driver, Attributes: device.Attributes, Capacity: device.Capacity})
|
||||
logger.V(7).Info("CEL result", "selector", i, "expression", expr.Expression, "matches", matches, "actualCost", ptr.Deref(details.ActualCost(), 0), "err", err)
|
||||
if err != nil {
|
||||
if t.recorder != nil {
|
||||
t.recorder.Eventf(taintRule, v1.EventTypeWarning, "CELRuntimeError", "selector #%d: runtime error: %v", i, err)
|
||||
}
|
||||
continue devices
|
||||
}
|
||||
if !matches {
|
||||
continue devices
|
||||
}
|
||||
}
|
||||
|
||||
logger.V(6).Info("applying matching DeviceTaintRule")
|
||||
|
||||
// TODO: remove conversion once taint is already in the right API package.
|
||||
|
|
|
|||
|
|
@ -316,37 +316,10 @@ var (
|
|||
}
|
||||
return rule
|
||||
}
|
||||
taintCELSelectedDevicesRule = func(rule *resourcealphaapi.DeviceTaintRule, exprs ...string) *resourcealphaapi.DeviceTaintRule {
|
||||
rule = rule.DeepCopy()
|
||||
var selectors []resourcealphaapi.DeviceSelector
|
||||
for _, expr := range exprs {
|
||||
selectors = append(selectors, resourcealphaapi.DeviceSelector{
|
||||
CEL: &resourcealphaapi.CELDeviceSelector{
|
||||
Expression: expr,
|
||||
},
|
||||
})
|
||||
}
|
||||
rule.Spec.DeviceSelector = &resourcealphaapi.DeviceTaintSelector{
|
||||
Selectors: selectors,
|
||||
}
|
||||
return rule
|
||||
}
|
||||
taintDeviceClassRule = func(rule *resourcealphaapi.DeviceTaintRule, deviceClassName string) *resourcealphaapi.DeviceTaintRule {
|
||||
rule = rule.DeepCopy()
|
||||
rule.Spec.DeviceSelector = &resourcealphaapi.DeviceTaintSelector{
|
||||
DeviceClassName: &deviceClassName,
|
||||
}
|
||||
return rule
|
||||
}
|
||||
taintPool1DevicesRule = taintPoolDevicesRule(taintAllDevicesRule, pool1)
|
||||
taintPool2DevicesRule = taintPoolDevicesRule(taintAllDevicesRule, pool2)
|
||||
taintDriver1DevicesRule = taintDriverDevicesRule(taintAllDevicesRule, driver1)
|
||||
taintDevice1Rule = taintNamedDevicesRule(taintAllDevicesRule, device1Name)
|
||||
taintDriver1DevicesCELRule = taintCELSelectedDevicesRule(taintAllDevicesRule, `device.driver == "`+driver1+`"`)
|
||||
taintNoDevicesCELRule = taintCELSelectedDevicesRule(taintAllDevicesRule, `true`, `false`, `true`)
|
||||
taintNoDevicesCELRuntimeErrorRule = taintCELSelectedDevicesRule(taintAllDevicesRule, `device.attributes["test.example.com"].deviceAttr`)
|
||||
taintNoDevicesInvalidCELRule = taintCELSelectedDevicesRule(taintAllDevicesRule, `invalid`)
|
||||
taintDeviceClass1Rule = taintDeviceClassRule(taintAllDevicesRule, deviceClass1.Name)
|
||||
taintPool1DevicesRule = taintPoolDevicesRule(taintAllDevicesRule, pool1)
|
||||
taintPool2DevicesRule = taintPoolDevicesRule(taintAllDevicesRule, pool2)
|
||||
taintDriver1DevicesRule = taintDriverDevicesRule(taintAllDevicesRule, driver1)
|
||||
taintDevice1Rule = taintNamedDevicesRule(taintAllDevicesRule, device1Name)
|
||||
)
|
||||
|
||||
func TestListPatchedResourceSlices(t *testing.T) {
|
||||
|
|
@ -519,102 +492,19 @@ func TestListPatchedResourceSlices(t *testing.T) {
|
|||
{event: handlerEventAdd, newObj: slice2},
|
||||
},
|
||||
},
|
||||
"add-attribute-for-selector": {
|
||||
events: []any{
|
||||
add(taintDriver1DevicesCELRule),
|
||||
add(slice1),
|
||||
add(slice2),
|
||||
},
|
||||
expectedPatchedSlices: []*resourceapi.ResourceSlice{
|
||||
slice1Tainted,
|
||||
slice2,
|
||||
},
|
||||
expectedHandlerEvents: []handlerEvent{
|
||||
{event: handlerEventAdd, newObj: slice1Tainted},
|
||||
{event: handlerEventAdd, newObj: slice2},
|
||||
},
|
||||
},
|
||||
"selector-does-not-match": {
|
||||
events: []any{
|
||||
add(taintNoDevicesCELRule),
|
||||
add(slice1),
|
||||
},
|
||||
expectedPatchedSlices: []*resourceapi.ResourceSlice{
|
||||
slice1,
|
||||
},
|
||||
expectedHandlerEvents: []handlerEvent{
|
||||
{event: handlerEventAdd, newObj: slice1},
|
||||
},
|
||||
},
|
||||
"runtime-CEL-errors-skip-devices": {
|
||||
events: []any{
|
||||
add(taintNoDevicesCELRuntimeErrorRule),
|
||||
add(slice1),
|
||||
},
|
||||
expectedPatchedSlices: []*resourceapi.ResourceSlice{
|
||||
slice1,
|
||||
},
|
||||
expectEvents: func(t *assert.CollectT, events *v1.EventList) {
|
||||
if !assert.Len(t, events.Items, 1) {
|
||||
return
|
||||
}
|
||||
assert.Equal(t, taintNoDevicesCELRuntimeErrorRule.Name, events.Items[0].InvolvedObject.Name)
|
||||
assert.Equal(t, "CELRuntimeError", events.Items[0].Reason)
|
||||
},
|
||||
expectedHandlerEvents: []handlerEvent{
|
||||
{event: handlerEventAdd, newObj: slice1},
|
||||
},
|
||||
},
|
||||
"invalid-CEL-expression-throws-error": {
|
||||
events: []any{
|
||||
[]any{
|
||||
add(taintNoDevicesInvalidCELRule),
|
||||
add(slice1),
|
||||
},
|
||||
},
|
||||
expectedPatchedSlices: []*resourceapi.ResourceSlice{},
|
||||
expectUnhandledErrors: func(t *testing.T, errs []error) {
|
||||
if !assert.Len(t, errs, 1) {
|
||||
return
|
||||
}
|
||||
assert.ErrorContains(t, errs[0], "CEL compile error")
|
||||
},
|
||||
},
|
||||
"add-taint-for-device-class": {
|
||||
events: []any{
|
||||
add(deviceClass1),
|
||||
add(taintDeviceClass1Rule),
|
||||
add(slice1),
|
||||
add(slice2),
|
||||
},
|
||||
expectedPatchedSlices: []*resourceapi.ResourceSlice{
|
||||
slice1Tainted,
|
||||
slice2,
|
||||
},
|
||||
expectedHandlerEvents: []handlerEvent{
|
||||
{event: handlerEventAdd, newObj: slice1Tainted},
|
||||
{event: handlerEventAdd, newObj: slice2},
|
||||
},
|
||||
},
|
||||
"filter-all-criteria": {
|
||||
events: []any{
|
||||
add(deviceClass1),
|
||||
add(
|
||||
taintDeviceClassRule(
|
||||
taintDriverDevicesRule(
|
||||
taintPoolDevicesRule(
|
||||
taintNamedDevicesRule(
|
||||
taintCELSelectedDevicesRule(
|
||||
taintAllDevicesRule,
|
||||
`true`,
|
||||
),
|
||||
device1Name,
|
||||
),
|
||||
pool1,
|
||||
taintDriverDevicesRule(
|
||||
taintPoolDevicesRule(
|
||||
taintNamedDevicesRule(
|
||||
taintAllDevicesRule,
|
||||
device1Name,
|
||||
),
|
||||
driver1,
|
||||
pool1,
|
||||
),
|
||||
deviceClass1.Name,
|
||||
driver1,
|
||||
),
|
||||
),
|
||||
add(slice1),
|
||||
|
|
|
|||
|
|
@ -869,6 +869,11 @@ func TestAllocator(t *testing.T,
|
|||
taintKey := "taint-key"
|
||||
taintValue := "taint-value"
|
||||
taintValue2 := "taint-value-2"
|
||||
taintNone := resourceapi.DeviceTaint{
|
||||
Key: taintKey,
|
||||
Value: taintValue,
|
||||
Effect: resourceapi.DeviceTaintEffectNone,
|
||||
}
|
||||
taintNoSchedule := resourceapi.DeviceTaint{
|
||||
Key: taintKey,
|
||||
Value: taintValue,
|
||||
|
|
@ -3565,6 +3570,21 @@ func TestAllocator(t *testing.T,
|
|||
deviceAllocationResult(req0SubReq1, driverA, pool1, device2, false, tolerationNoExecute), // Only second device's taints are tolerated.
|
||||
)},
|
||||
},
|
||||
"tainted-no-effect": {
|
||||
features: Features{
|
||||
DeviceTaints: true,
|
||||
},
|
||||
claimsToAllocate: objects(claimWithRequest(claim0, req0, classA)),
|
||||
classes: objects(class(classA, driverA)),
|
||||
slices: unwrap(slice(slice1, node1, pool1, driverA,
|
||||
device(device1, nil, nil).withTaints(taintNone),
|
||||
)),
|
||||
node: node(node1, region1),
|
||||
expectResults: []any{allocationResult(
|
||||
localNodeSelector(node1),
|
||||
deviceAllocationResult(req0, driverA, pool1, device1, false),
|
||||
)},
|
||||
},
|
||||
"tainted-one-device-two-taints-both-tolerated": {
|
||||
features: Features{
|
||||
DeviceTaints: true,
|
||||
|
|
|
|||
|
|
@ -1291,7 +1291,7 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus
|
|||
|
||||
// Might be tainted, in which case the taint has to be tolerated.
|
||||
// The check is skipped if the feature is disabled.
|
||||
if alloc.features.DeviceTaints && !allTaintsTolerated(device.Device, request) {
|
||||
if alloc.features.DeviceTaints && taintPreventsAllocation(device.Device, request) {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
|
|
@ -1387,13 +1387,17 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus
|
|||
}, nil
|
||||
}
|
||||
|
||||
func allTaintsTolerated(device *draapi.Device, request requestAccessor) bool {
|
||||
func taintPreventsAllocation(device *draapi.Device, request requestAccessor) bool {
|
||||
for _, taint := range device.Taints {
|
||||
if !taintTolerated(taint, request) {
|
||||
return false
|
||||
switch taint.Effect {
|
||||
// Only known effects prevent allocation, others (including None) are ignored.
|
||||
case resourceapi.DeviceTaintEffectNoExecute, resourceapi.DeviceTaintEffectNoSchedule:
|
||||
if !taintTolerated(taint, request) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
func taintTolerated(taint resourceapi.DeviceTaint, request requestAccessor) bool {
|
||||
|
|
|
|||
|
|
@ -1134,7 +1134,7 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus
|
|||
|
||||
// Might be tainted, in which case the taint has to be tolerated.
|
||||
// The check is skipped if the feature is disabled.
|
||||
if alloc.features.DeviceTaints && !allTaintsTolerated(device.Device, request) {
|
||||
if alloc.features.DeviceTaints && taintPreventsAllocation(device.Device, request) {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
|
|
@ -1192,13 +1192,17 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device deviceWithID, mus
|
|||
}, nil
|
||||
}
|
||||
|
||||
func allTaintsTolerated(device *draapi.Device, request requestAccessor) bool {
|
||||
func taintPreventsAllocation(device *draapi.Device, request requestAccessor) bool {
|
||||
for _, taint := range device.Taints {
|
||||
if !taintTolerated(taint, request) {
|
||||
return false
|
||||
switch taint.Effect {
|
||||
// Only known effects prevent allocation, others (including None) are ignored.
|
||||
case resourceapi.DeviceTaintEffectNoExecute, resourceapi.DeviceTaintEffectNoSchedule:
|
||||
if !taintTolerated(taint, request) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
func taintTolerated(taint resourceapi.DeviceTaint, request requestAccessor) bool {
|
||||
|
|
|
|||
|
|
@ -168,6 +168,8 @@ type KubeControllerManagerConfiguration struct {
|
|||
// ValidatingAdmissionPolicyStatusControllerConfiguration holds configuration for
|
||||
// ValidatingAdmissionPolicyStatusController related features.
|
||||
ValidatingAdmissionPolicyStatusController ValidatingAdmissionPolicyStatusControllerConfiguration
|
||||
// DeviceTaintEvictionControllerConfiguration contains elements configuring the device taint eviction controller.
|
||||
DeviceTaintEvictionController DeviceTaintEvictionControllerConfiguration
|
||||
}
|
||||
|
||||
// AttachDetachControllerConfiguration contains elements describing AttachDetachController.
|
||||
|
|
@ -488,3 +490,12 @@ type ValidatingAdmissionPolicyStatusControllerConfiguration struct {
|
|||
// The default value is 5.
|
||||
ConcurrentPolicySyncs int32
|
||||
}
|
||||
|
||||
// DeviceTaintEvictionControllerConfiguration contains elements configuring the device taint eviction controller.
|
||||
type DeviceTaintEvictionControllerConfiguration struct {
|
||||
// ConcurrentSyncs is the number of operations (deleting a pod, updating a ResourcClaim status, etc.)
|
||||
// that will be done concurrently. Larger number = processing, but more CPU (and network) load.
|
||||
//
|
||||
// The default is 10.
|
||||
ConcurrentSyncs int32
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue