DRA API: AdminAccess in DeviceRequestAllocationResult

Drivers need to know that because admin access may also grant additional
permissions. The allocator needs to ignore such results when determining which
devices are considered as allocated.

In both cases it is conceptually cleaner to not rely on the content of the
ClaimSpec.
This commit is contained in:
Patrick Ohly 2024-09-04 08:03:22 +02:00
parent 66b3dc1a38
commit f3fef01e79
24 changed files with 495 additions and 208 deletions

View File

@ -15562,6 +15562,10 @@
"io.k8s.api.resource.v1alpha3.DeviceRequestAllocationResult": {
"description": "DeviceRequestAllocationResult contains the allocation result for one request.",
"properties": {
"adminAccess": {
"description": "AdminAccess is a copy of the AdminAccess value in the request which caused this device to be allocated.\n\nNew allocations are required to have this set. Old allocations made by Kubernetes 1.31 do not have it yet. Clients which want to support Kubernetes 1.31 need to look up the request and retrieve the value from there if this field is not set.",
"type": "boolean"
},
"device": {
"description": "Device references one device instance via its name in the driver's resource pool. It must be a DNS label.",
"type": "string"
@ -15583,7 +15587,8 @@
"request",
"driver",
"pool",
"device"
"device",
"adminAccess"
],
"type": "object"
},

View File

@ -526,6 +526,10 @@
"io.k8s.api.resource.v1alpha3.DeviceRequestAllocationResult": {
"description": "DeviceRequestAllocationResult contains the allocation result for one request.",
"properties": {
"adminAccess": {
"description": "AdminAccess is a copy of the AdminAccess value in the request which caused this device to be allocated.\n\nNew allocations are required to have this set. Old allocations made by Kubernetes 1.31 do not have it yet. Clients which want to support Kubernetes 1.31 need to look up the request and retrieve the value from there if this field is not set.",
"type": "boolean"
},
"device": {
"default": "",
"description": "Device references one device instance via its name in the driver's resource pool. It must be a DNS label.",
@ -551,7 +555,8 @@
"request",
"driver",
"pool",
"device"
"device",
"adminAccess"
],
"type": "object"
},

View File

@ -782,6 +782,17 @@ type DeviceRequestAllocationResult struct {
//
// +required
Device string
// AdminAccess is a copy of the AdminAccess value in the
// request which caused this device to be allocated.
//
// New allocations are required to have this set. Old allocations made
// by Kubernetes 1.31 do not have it yet. Clients which want to
// support Kubernetes 1.31 need to look up the request and retrieve
// the value from there if this field is not set.
//
// +required
AdminAccess *bool
}
// DeviceAllocationConfiguration gets embedded in an AllocationResult.

View File

@ -741,6 +741,7 @@ func autoConvert_v1alpha3_DeviceRequestAllocationResult_To_resource_DeviceReques
out.Driver = in.Driver
out.Pool = in.Pool
out.Device = in.Device
out.AdminAccess = (*bool)(unsafe.Pointer(in.AdminAccess))
return nil
}
@ -754,6 +755,7 @@ func autoConvert_resource_DeviceRequestAllocationResult_To_v1alpha3_DeviceReques
out.Driver = in.Driver
out.Pool = in.Pool
out.Device = in.Device
out.AdminAccess = (*bool)(unsafe.Pointer(in.AdminAccess))
return nil
}

View File

@ -261,7 +261,6 @@ func validateOpaqueConfiguration(config resource.OpaqueDeviceConfiguration, fldP
func validateResourceClaimStatusUpdate(status, oldStatus *resource.ResourceClaimStatus, claimDeleted bool, requestNames sets.Set[string], fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList
allErrs = append(allErrs, validateAllocationResult(status.Allocation, fldPath.Child("allocation"), requestNames)...)
allErrs = append(allErrs, validateSet(status.ReservedFor, resource.ResourceClaimReservedForMaxSize,
validateResourceClaimUserReference,
func(consumer resource.ResourceClaimConsumerReference) (types.UID, string) { return consumer.UID, "uid" },
@ -285,9 +284,14 @@ func validateResourceClaimStatusUpdate(status, oldStatus *resource.ResourceClaim
}
}
// Updates to a populated status.Allocation are not allowed
// Updates to a populated status.Allocation are not allowed.
// Unmodified fields don't need to be validated again and,
// in this particular case, must not be validated again because
// validation for new results is tighter than it was before.
if oldStatus.Allocation != nil && status.Allocation != nil {
allErrs = append(allErrs, apimachineryvalidation.ValidateImmutableField(status.Allocation, oldStatus.Allocation, fldPath.Child("allocation"))...)
} else if status.Allocation != nil {
allErrs = append(allErrs, validateAllocationResult(status.Allocation, fldPath.Child("allocation"), requestNames)...)
}
return allErrs
@ -307,11 +311,10 @@ func validateResourceClaimUserReference(ref resource.ResourceClaimConsumerRefere
return allErrs
}
// validateAllocationResult enforces constraints for *new* results, which in at
// least one case (admin access) are more strict than before. Therefore it
// may not be called to re-validate results which were stored earlier.
func validateAllocationResult(allocation *resource.AllocationResult, fldPath *field.Path, requestNames sets.Set[string]) field.ErrorList {
if allocation == nil {
return nil
}
var allErrs field.ErrorList
allErrs = append(allErrs, validateDeviceAllocationResult(allocation.Devices, fldPath.Child("devices"), requestNames)...)
if allocation.NodeSelector != nil {
@ -340,6 +343,9 @@ func validateDeviceRequestAllocationResult(result resource.DeviceRequestAllocati
allErrs = append(allErrs, validateDriverName(result.Driver, fldPath.Child("driver"))...)
allErrs = append(allErrs, validatePoolName(result.Pool, fldPath.Child("pool"))...)
allErrs = append(allErrs, validateDeviceName(result.Device, fldPath.Child("device"))...)
if result.AdminAccess == nil {
allErrs = append(allErrs, field.Required(fldPath.Child("adminAccess"), ""))
}
return allErrs
}

View File

@ -408,14 +408,17 @@ func TestValidateClaimStatusUpdate(t *testing.T) {
Allocation: &resource.AllocationResult{
Devices: resource.DeviceAllocationResult{
Results: []resource.DeviceRequestAllocationResult{{
Request: goodName,
Driver: goodName,
Pool: goodName,
Device: goodName,
Request: goodName,
Driver: goodName,
Pool: goodName,
Device: goodName,
AdminAccess: ptr.To(false), // Required for new allocations.
}},
},
},
}
validAllocatedClaimOld := validAllocatedClaim.DeepCopy()
validAllocatedClaimOld.Status.Allocation.Devices.Results[0].AdminAccess = nil // Not required in 1.31.
scenarios := map[string]struct {
oldClaim *resource.ResourceClaim
@ -439,10 +442,11 @@ func TestValidateClaimStatusUpdate(t *testing.T) {
claim.Status.Allocation = &resource.AllocationResult{
Devices: resource.DeviceAllocationResult{
Results: []resource.DeviceRequestAllocationResult{{
Request: goodName,
Driver: goodName,
Pool: goodName,
Device: goodName,
Request: goodName,
Driver: goodName,
Pool: goodName,
Device: goodName,
AdminAccess: ptr.To(false),
}},
},
}
@ -459,10 +463,31 @@ func TestValidateClaimStatusUpdate(t *testing.T) {
claim.Status.Allocation = &resource.AllocationResult{
Devices: resource.DeviceAllocationResult{
Results: []resource.DeviceRequestAllocationResult{{
Request: badName,
Driver: goodName,
Pool: goodName,
Device: goodName,
Request: badName,
Driver: goodName,
Pool: goodName,
Device: goodName,
AdminAccess: ptr.To(false),
}},
},
}
return claim
},
},
"invalid-add-allocation-missing-admin-access": {
wantFailures: field.ErrorList{
field.Required(field.NewPath("status", "allocation", "devices", "results").Index(0).Child("adminAccess"), ""),
},
oldClaim: validClaim,
update: func(claim *resource.ResourceClaim) *resource.ResourceClaim {
claim.Status.Allocation = &resource.AllocationResult{
Devices: resource.DeviceAllocationResult{
Results: []resource.DeviceRequestAllocationResult{{
Request: goodName,
Driver: goodName,
Pool: goodName,
Device: goodName,
AdminAccess: nil, // Intentionally not set.
}},
},
}
@ -495,6 +520,20 @@ func TestValidateClaimStatusUpdate(t *testing.T) {
return claim
},
},
"add-reservation-old-claim": {
oldClaim: validAllocatedClaimOld,
update: func(claim *resource.ResourceClaim) *resource.ResourceClaim {
for i := 0; i < resource.ResourceClaimReservedForMaxSize; i++ {
claim.Status.ReservedFor = append(claim.Status.ReservedFor,
resource.ResourceClaimConsumerReference{
Resource: "pods",
Name: fmt.Sprintf("foo-%d", i),
UID: types.UID(fmt.Sprintf("%d", i)),
})
}
return claim
},
},
"add-reservation-and-allocation": {
oldClaim: validClaim,
update: func(claim *resource.ResourceClaim) *resource.ResourceClaim {

View File

@ -144,7 +144,9 @@ func (in *DeviceAllocationResult) DeepCopyInto(out *DeviceAllocationResult) {
if in.Results != nil {
in, out := &in.Results, &out.Results
*out = make([]DeviceRequestAllocationResult, len(*in))
copy(*out, *in)
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Config != nil {
in, out := &in.Config, &out.Config
@ -441,6 +443,11 @@ func (in *DeviceRequest) DeepCopy() *DeviceRequest {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeviceRequestAllocationResult) DeepCopyInto(out *DeviceRequestAllocationResult) {
*out = *in
if in.AdminAccess != nil {
in, out := &in.AdminAccess, &out.AdminAccess
*out = new(bool)
**out = **in
}
return
}

View File

@ -46558,8 +46558,15 @@ func schema_k8sio_api_resource_v1alpha3_DeviceRequestAllocationResult(ref common
Format: "",
},
},
"adminAccess": {
SchemaProps: spec.SchemaProps{
Description: "AdminAccess is a copy of the AdminAccess value in the request which caused this device to be allocated.\n\nNew allocations are required to have this set. Old allocations made by Kubernetes 1.31 do not have it yet. Clients which want to support Kubernetes 1.31 need to look up the request and retrieve the value from there if this field is not set.",
Type: []string{"boolean"},
Format: "",
},
},
},
Required: []string{"request", "driver", "pool", "device"},
Required: []string{"request", "driver", "pool", "device", "adminAccess"},
},
},
}

View File

@ -135,10 +135,11 @@ var (
allocationResult = &resourceapi.AllocationResult{
Devices: resourceapi.DeviceAllocationResult{
Results: []resourceapi.DeviceRequestAllocationResult{{
Driver: driver,
Pool: nodeName,
Device: "instance-1",
Request: "req-1",
Driver: driver,
Pool: nodeName,
Device: "instance-1",
Request: "req-1",
AdminAccess: ptr.To(false),
}},
},
NodeSelector: func() *v1.NodeSelector {
@ -178,6 +179,19 @@ func reserve(claim *resourceapi.ResourceClaim, pod *v1.Pod) *resourceapi.Resourc
Obj()
}
func adminAccess(claim *resourceapi.ResourceClaim) *resourceapi.ResourceClaim {
claim = claim.DeepCopy()
for i := range claim.Spec.Devices.Requests {
claim.Spec.Devices.Requests[i].AdminAccess = true
}
if claim.Status.Allocation != nil {
for i := range claim.Status.Allocation.Devices.Results {
claim.Status.Allocation.Devices.Results[i].AdminAccess = ptr.To(true)
}
}
return claim
}
func breakCELInClaim(claim *resourceapi.ResourceClaim) *resourceapi.ResourceClaim {
claim = claim.DeepCopy()
for i := range claim.Spec.Devices.Requests {
@ -556,6 +570,66 @@ func TestPlugin(t *testing.T) {
},
},
"request-admin-access": {
// Because the pending claim asks for admin access, allocation succeeds despite resources
// being exhausted.
pod: podWithClaimName,
claims: []*resourceapi.ResourceClaim{adminAccess(pendingClaim), otherAllocatedClaim},
classes: []*resourceapi.DeviceClass{deviceClass},
objs: []apiruntime.Object{workerNodeSlice},
want: want{
reserve: result{
inFlightClaim: adminAccess(allocatedClaim),
},
prebind: result{
assumedClaim: reserve(adminAccess(allocatedClaim), podWithClaimName),
changes: change{
claim: func(claim *resourceapi.ResourceClaim) *resourceapi.ResourceClaim {
if claim.Name == claimName {
claim = claim.DeepCopy()
claim.Finalizers = allocatedClaim.Finalizers
claim.Status = adminAccess(inUseClaim).Status
}
return claim
},
},
},
postbind: result{
assumedClaim: reserve(adminAccess(allocatedClaim), podWithClaimName),
},
},
},
"structured-ignore-allocated-admin-access": {
// The allocated claim uses admin access, so a second claim may use
// the same device.
pod: podWithClaimName,
claims: []*resourceapi.ResourceClaim{pendingClaim, adminAccess(otherAllocatedClaim)},
classes: []*resourceapi.DeviceClass{deviceClass},
objs: []apiruntime.Object{workerNodeSlice},
want: want{
reserve: result{
inFlightClaim: allocatedClaim,
},
prebind: result{
assumedClaim: reserve(allocatedClaim, podWithClaimName),
changes: change{
claim: func(claim *resourceapi.ResourceClaim) *resourceapi.ResourceClaim {
if claim.Name == claimName {
claim = claim.DeepCopy()
claim.Finalizers = allocatedClaim.Finalizers
claim.Status = inUseClaim.Status
}
return claim
},
},
},
postbind: result{
assumedClaim: reserve(allocatedClaim, podWithClaimName),
},
},
},
"claim-parameters-CEL-runtime-error": {
pod: podWithClaimName,
claims: []*resourceapi.ResourceClaim{breakCELInClaim(pendingClaim)},

View File

@ -957,122 +957,122 @@ func init() {
}
var fileDescriptor_66649ee9bbcd89d2 = []byte{
// 1832 bytes of a gzipped FileDescriptorProto
// 1840 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x19, 0xcd, 0x6f, 0xe4, 0x56,
0x3d, 0x1e, 0x27, 0x93, 0xc9, 0x6f, 0xf2, 0xb5, 0x6f, 0xa1, 0x64, 0x43, 0x99, 0xd9, 0x75, 0x11,
0x64, 0xdb, 0xad, 0xa7, 0xbb, 0x2d, 0x6d, 0xa1, 0x1c, 0x88, 0x93, 0x74, 0x95, 0xd5, 0x7e, 0x64,
0x5f, 0xda, 0x15, 0x0b, 0xa5, 0xf0, 0xe2, 0x79, 0x99, 0x98, 0x78, 0x6c, 0xd7, 0xef, 0x79, 0x68,
0x2e, 0xa8, 0xe2, 0xc2, 0x6d, 0xc5, 0x3f, 0x80, 0xb8, 0x21, 0x71, 0x82, 0x3f, 0x00, 0x09, 0x24,
0x90, 0x58, 0x89, 0xcb, 0x4a, 0x70, 0xe8, 0x69, 0xe8, 0x0e, 0xe2, 0xc2, 0x9f, 0x90, 0x13, 0xf2,
0xf3, 0xf3, 0xe7, 0x8c, 0xb3, 0x9e, 0xaa, 0x44, 0xed, 0x6d, 0xfc, 0xfb, 0xfe, 0xfe, 0xfd, 0xec,
0x81, 0x6b, 0xc7, 0x6f, 0x32, 0xdd, 0x72, 0x3b, 0xc4, 0xb3, 0x3a, 0x3e, 0x65, 0x6e, 0xe0, 0x9b,
0xb4, 0x33, 0xb8, 0x4e, 0x6c, 0xef, 0x88, 0xbc, 0xda, 0xe9, 0x51, 0x87, 0xfa, 0x84, 0xd3, 0xae,
0xee, 0xf9, 0x2e, 0x77, 0xd1, 0xf3, 0x11, 0xb5, 0x4e, 0x3c, 0x4b, 0x8f, 0xa9, 0xf5, 0x98, 0x7a,
0xfd, 0xe5, 0x9e, 0xc5, 0x8f, 0x82, 0x03, 0xdd, 0x74, 0xfb, 0x9d, 0x9e, 0xdb, 0x73, 0x3b, 0x82,
0xe9, 0x20, 0x38, 0x14, 0x4f, 0xe2, 0x41, 0xfc, 0x8a, 0x84, 0xad, 0x6b, 0x19, 0xd5, 0xa6, 0xeb,
0x87, 0x6a, 0x8b, 0x0a, 0xd7, 0x5f, 0x4b, 0x69, 0xfa, 0xc4, 0x3c, 0xb2, 0x1c, 0xea, 0x9f, 0x74,
0xbc, 0xe3, 0x5e, 0xde, 0xde, 0x69, 0xb8, 0x58, 0xa7, 0x4f, 0x39, 0x99, 0xa4, 0xab, 0x53, 0xc6,
0xe5, 0x07, 0x0e, 0xb7, 0xfa, 0xe3, 0x6a, 0x5e, 0x7f, 0x16, 0x03, 0x33, 0x8f, 0x68, 0x9f, 0x14,
0xf9, 0xb4, 0xbf, 0x2b, 0xb0, 0xba, 0x69, 0xdb, 0xae, 0x49, 0xb8, 0xe5, 0x3a, 0x98, 0xb2, 0xc0,
0xe6, 0xe8, 0xc7, 0x30, 0xdf, 0xa5, 0x03, 0xcb, 0xa4, 0x6c, 0x4d, 0xb9, 0xac, 0x6c, 0x34, 0x6f,
0xbc, 0xa6, 0x9f, 0x15, 0x6c, 0x7d, 0x5b, 0x10, 0x17, 0xc5, 0x18, 0x2b, 0x8f, 0x87, 0xed, 0x99,
0xd1, 0xb0, 0x3d, 0x1f, 0xe1, 0x19, 0x8e, 0xa5, 0xa2, 0x07, 0xb0, 0xe8, 0xb8, 0x5d, 0xba, 0x4f,
0x6d, 0x6a, 0x72, 0xd7, 0x5f, 0x53, 0x85, 0x96, 0xcb, 0x59, 0x2d, 0x61, 0x16, 0xf4, 0xc1, 0x75,
0xfd, 0x6e, 0x86, 0xce, 0x58, 0x1d, 0x0d, 0xdb, 0x8b, 0x59, 0x08, 0xce, 0xc9, 0xd1, 0x3e, 0x51,
0xa1, 0x69, 0x10, 0x66, 0x99, 0x91, 0x46, 0xf4, 0x73, 0x00, 0xc2, 0xb9, 0x6f, 0x1d, 0x04, 0x5c,
0xf8, 0xa2, 0x6e, 0x34, 0x6f, 0x7c, 0xfb, 0x6c, 0x5f, 0x32, 0xec, 0xfa, 0x66, 0xc2, 0xbb, 0xe3,
0x70, 0xff, 0xc4, 0x78, 0x41, 0x3a, 0x04, 0x29, 0xe2, 0x17, 0xff, 0x6a, 0x2f, 0xdd, 0x0f, 0x88,
0x6d, 0x1d, 0x5a, 0xb4, 0x7b, 0x97, 0xf4, 0x29, 0xce, 0x68, 0x44, 0x03, 0x68, 0x98, 0xc4, 0x23,
0xa6, 0xc5, 0x4f, 0xd6, 0x6a, 0x42, 0xfb, 0x1b, 0xd5, 0xb5, 0x6f, 0x49, 0xce, 0x48, 0xf7, 0x15,
0xa9, 0xbb, 0x11, 0x83, 0xc7, 0x35, 0x27, 0xba, 0xd6, 0x6d, 0x58, 0x29, 0xd8, 0x8e, 0x56, 0x41,
0x3d, 0xa6, 0x27, 0x22, 0x9f, 0x0b, 0x38, 0xfc, 0x89, 0xb6, 0x60, 0x6e, 0x40, 0xec, 0x80, 0xae,
0xd5, 0x44, 0xf4, 0x5f, 0xae, 0x94, 0xe3, 0x58, 0x2a, 0x8e, 0x78, 0xbf, 0x53, 0x7b, 0x53, 0x59,
0x3f, 0x86, 0xa5, 0x9c, 0xad, 0x13, 0x74, 0x6d, 0xe7, 0x75, 0xe9, 0x19, 0x5d, 0x49, 0xb9, 0xea,
0xde, 0x71, 0x2f, 0xaf, 0xfc, 0x7e, 0x40, 0x1c, 0x6e, 0xf1, 0x93, 0x8c, 0x32, 0xed, 0x26, 0x5c,
0xd8, 0xda, 0xb9, 0x1d, 0x59, 0x13, 0xe7, 0x1d, 0xdd, 0x00, 0xa0, 0x1f, 0x7a, 0x3e, 0x65, 0xcc,
0x72, 0x9d, 0x48, 0xaf, 0x81, 0xe2, 0x64, 0xed, 0x24, 0x18, 0x9c, 0xa1, 0xd2, 0x06, 0x50, 0x97,
0x55, 0x72, 0x19, 0x66, 0x1d, 0xd2, 0xa7, 0x92, 0x6f, 0x51, 0xf2, 0xcd, 0x8a, 0x98, 0x0a, 0x0c,
0xba, 0x05, 0x73, 0x07, 0x61, 0x66, 0xa4, 0xf9, 0x57, 0x2b, 0x27, 0xd1, 0x58, 0x18, 0x0d, 0xdb,
0x73, 0x02, 0x80, 0x23, 0x11, 0xda, 0xa3, 0x1a, 0x7c, 0xad, 0xd8, 0x30, 0x5b, 0xae, 0x73, 0x68,
0xf5, 0x02, 0x5f, 0x3c, 0xa0, 0xef, 0x41, 0x3d, 0x12, 0x29, 0x2d, 0xda, 0x90, 0x16, 0xd5, 0xf7,
0x05, 0xf4, 0x74, 0xd8, 0x7e, 0xae, 0xc8, 0x1a, 0x61, 0xb0, 0xe4, 0x43, 0x1b, 0xd0, 0xf0, 0xe9,
0x07, 0x01, 0x65, 0x9c, 0x89, 0xba, 0x5b, 0x30, 0x16, 0xc3, 0xd2, 0xc1, 0x12, 0x86, 0x13, 0x2c,
0xfa, 0x48, 0x81, 0x8b, 0x51, 0x57, 0xe6, 0x6c, 0x90, 0x1d, 0x79, 0xbd, 0x4a, 0x4d, 0xe4, 0x18,
0x8d, 0xaf, 0x4a, 0x63, 0x2f, 0x4e, 0x40, 0xe2, 0x49, 0xaa, 0xb4, 0xff, 0x28, 0xf0, 0xdc, 0xe4,
0x09, 0x82, 0x0e, 0x61, 0xde, 0x17, 0xbf, 0xe2, 0xe6, 0x7d, 0xab, 0x8a, 0x41, 0xd2, 0xcd, 0xf2,
0x79, 0x14, 0x3d, 0x33, 0x1c, 0x0b, 0x47, 0x26, 0xd4, 0x4d, 0x61, 0x93, 0xec, 0xd2, 0xb7, 0xa6,
0x9b, 0x77, 0xf9, 0x08, 0x2c, 0xc7, 0xe9, 0x8a, 0xc0, 0x58, 0x8a, 0xd6, 0x7e, 0xa7, 0xc0, 0x4a,
0xa1, 0x8b, 0x50, 0x0b, 0x54, 0xcb, 0xe1, 0xa2, 0xac, 0xd4, 0x28, 0x47, 0xbb, 0x0e, 0x7f, 0x10,
0x16, 0x3b, 0x0e, 0x11, 0xe8, 0x0a, 0xcc, 0x1e, 0xb8, 0xae, 0x2d, 0xd2, 0xd1, 0x30, 0x96, 0x46,
0xc3, 0xf6, 0x82, 0xe1, 0xba, 0x76, 0x44, 0x21, 0x50, 0xe8, 0x9b, 0x50, 0x67, 0xdc, 0xb7, 0x9c,
0xde, 0xda, 0xac, 0xa8, 0x96, 0x95, 0xd1, 0xb0, 0xdd, 0xdc, 0x17, 0x90, 0x88, 0x4c, 0xa2, 0xd1,
0x8b, 0x30, 0x3f, 0xa0, 0xbe, 0xe8, 0x90, 0x39, 0x41, 0x29, 0xa6, 0xe9, 0x83, 0x08, 0x14, 0x91,
0xc6, 0x04, 0xda, 0xef, 0x6b, 0xd0, 0x94, 0x09, 0xb4, 0x89, 0xd5, 0x47, 0x0f, 0x33, 0x05, 0x15,
0x65, 0xe2, 0xa5, 0x29, 0x32, 0x61, 0xac, 0xc6, 0xc3, 0x6b, 0x42, 0x05, 0x52, 0x68, 0x9a, 0xae,
0xc3, 0xb8, 0x4f, 0x2c, 0x47, 0x96, 0x6b, 0x7e, 0x40, 0x9c, 0x55, 0x78, 0x92, 0xcd, 0xb8, 0x28,
0x15, 0x34, 0x53, 0x18, 0xc3, 0x59, 0xb9, 0xe8, 0xfd, 0x24, 0xc5, 0xaa, 0xd0, 0xf0, 0x7a, 0x25,
0x0d, 0xa1, 0xf3, 0xd5, 0xb2, 0xfb, 0x37, 0x05, 0xd6, 0xca, 0x98, 0x72, 0xfd, 0xa8, 0x7c, 0xaa,
0x7e, 0xac, 0x9d, 0x5f, 0x3f, 0xfe, 0x59, 0xc9, 0xe4, 0x9e, 0x31, 0xf4, 0x13, 0x68, 0x84, 0x67,
0x4a, 0x97, 0x70, 0x22, 0xcf, 0x81, 0x57, 0xce, 0x1a, 0xdf, 0x4c, 0x0f, 0xa9, 0xc3, 0xd5, 0x7d,
0xef, 0xe0, 0xa7, 0xd4, 0xe4, 0x77, 0x28, 0x27, 0xe9, 0x30, 0x4e, 0x61, 0x38, 0x91, 0x8a, 0xee,
0xc1, 0x2c, 0xf3, 0xa8, 0x39, 0xcd, 0x22, 0x12, 0xa6, 0xed, 0x7b, 0xd4, 0x4c, 0xe7, 0x75, 0xf8,
0x84, 0x85, 0x20, 0xed, 0xd7, 0xd9, 0x64, 0x30, 0x96, 0x4f, 0x46, 0x59, 0x88, 0x95, 0xf3, 0x0b,
0xf1, 0x9f, 0x92, 0x51, 0x20, 0xec, 0xbb, 0x6d, 0x31, 0x8e, 0xde, 0x1b, 0x0b, 0xb3, 0x5e, 0x2d,
0xcc, 0x21, 0xb7, 0x08, 0x72, 0xd2, 0x65, 0x31, 0x24, 0x13, 0xe2, 0xbb, 0x30, 0x67, 0x71, 0xda,
0x8f, 0xfb, 0xeb, 0x6a, 0xe5, 0x18, 0x1b, 0x4b, 0x52, 0xea, 0xdc, 0x6e, 0xc8, 0x8f, 0x23, 0x31,
0xda, 0x93, 0xbc, 0x07, 0x61, 0xec, 0xd1, 0x8f, 0x60, 0x81, 0xc9, 0x8d, 0x1c, 0x4f, 0x89, 0x6b,
0x55, 0xf4, 0x24, 0xe7, 0xdd, 0x05, 0xa9, 0x6a, 0x21, 0x86, 0x30, 0x9c, 0x4a, 0xcc, 0x74, 0x70,
0x6d, 0xaa, 0x0e, 0x2e, 0xe4, 0xbf, 0xb4, 0x83, 0x7d, 0x98, 0x94, 0x40, 0xf4, 0x43, 0xa8, 0xbb,
0x1e, 0xf9, 0x20, 0xa0, 0x32, 0x2b, 0xcf, 0xb8, 0xe0, 0xee, 0x09, 0xda, 0x49, 0x65, 0x02, 0xa1,
0xce, 0x08, 0x8d, 0xa5, 0x48, 0xed, 0x91, 0x02, 0xab, 0xc5, 0x61, 0x36, 0xc5, 0xb4, 0xd8, 0x83,
0xe5, 0x3e, 0xe1, 0xe6, 0x51, 0xb2, 0x50, 0x44, 0x0b, 0x2d, 0x18, 0x1b, 0xa3, 0x61, 0x7b, 0xf9,
0x4e, 0x0e, 0x73, 0x3a, 0x6c, 0xa3, 0xb7, 0x03, 0xdb, 0x3e, 0xc9, 0xdf, 0x8c, 0x05, 0x7e, 0xed,
0x97, 0x2a, 0x2c, 0xe5, 0x66, 0x77, 0x85, 0xeb, 0x68, 0x13, 0x56, 0xba, 0x69, 0xb0, 0x43, 0x84,
0x34, 0xe3, 0x2b, 0x92, 0x38, 0x5b, 0x29, 0x82, 0xaf, 0x48, 0x9f, 0x2f, 0x1d, 0xf5, 0x33, 0x2f,
0x9d, 0x07, 0xb0, 0x4c, 0x92, 0x6d, 0x7d, 0xc7, 0xed, 0x52, 0xb9, 0x2b, 0x75, 0xc9, 0xb5, 0xbc,
0x99, 0xc3, 0x9e, 0x0e, 0xdb, 0x5f, 0x2a, 0xee, 0xf8, 0x10, 0x8e, 0x0b, 0x52, 0xd0, 0x0b, 0x30,
0x67, 0xba, 0x81, 0xc3, 0xc5, 0x42, 0x55, 0xd3, 0x56, 0xd9, 0x0a, 0x81, 0x38, 0xc2, 0xa1, 0x6f,
0x41, 0x93, 0x74, 0xfb, 0x96, 0xb3, 0x69, 0x9a, 0x94, 0xb1, 0xb5, 0xba, 0x58, 0xe5, 0xc9, 0xc2,
0xda, 0x4c, 0x51, 0x38, 0x4b, 0xa7, 0xfd, 0x51, 0x89, 0xef, 0xc4, 0x92, 0x7b, 0x06, 0x5d, 0x0d,
0xaf, 0x23, 0x81, 0x92, 0xc9, 0xc9, 0x1c, 0x38, 0x02, 0x8c, 0x63, 0x3c, 0xfa, 0x06, 0xd4, 0xbb,
0xbe, 0x35, 0xa0, 0xbe, 0xcc, 0x4c, 0xd2, 0x03, 0xdb, 0x02, 0x8a, 0x25, 0x36, 0x4c, 0xb6, 0x17,
0xdf, 0x1b, 0x99, 0x64, 0xef, 0xb9, 0xae, 0x8d, 0x05, 0x46, 0x48, 0x12, 0x56, 0xc9, 0x10, 0xa6,
0x92, 0x22, 0x5b, 0x25, 0x56, 0x7b, 0x0f, 0x96, 0x0b, 0x47, 0xfa, 0x2d, 0x50, 0x4d, 0x6a, 0xcb,
0x2e, 0xea, 0x9c, 0x9d, 0xdd, 0xb1, 0x13, 0xdf, 0x98, 0x1f, 0x0d, 0xdb, 0xea, 0xd6, 0xce, 0x6d,
0x1c, 0x0a, 0xd1, 0x7e, 0xab, 0xc0, 0xa5, 0xd2, 0x4e, 0xcb, 0x78, 0xab, 0x9c, 0xe9, 0x2d, 0x01,
0xf0, 0x88, 0x4f, 0xfa, 0x94, 0x53, 0x9f, 0x4d, 0xd8, 0x3e, 0xf9, 0xa1, 0x2b, 0xdf, 0xa4, 0x75,
0x4c, 0x7e, 0xb6, 0xf3, 0x21, 0xa7, 0x4e, 0x78, 0x28, 0xa5, 0x8b, 0x6d, 0x2f, 0x11, 0x84, 0x33,
0x42, 0xb5, 0xdf, 0xd4, 0x60, 0x09, 0x4b, 0xf7, 0xa2, 0x53, 0xea, 0xff, 0xbf, 0x4e, 0xef, 0xe7,
0xd6, 0xe9, 0x33, 0x22, 0x9d, 0x33, 0xae, 0x6c, 0xa1, 0xa2, 0x87, 0xe1, 0x91, 0x49, 0x78, 0xc0,
0xaa, 0xbd, 0x18, 0xe4, 0x85, 0x0a, 0xc6, 0x34, 0x09, 0xd1, 0x33, 0x96, 0x02, 0xb5, 0x91, 0x02,
0xad, 0x1c, 0x7d, 0x38, 0x09, 0x83, 0x3e, 0xf5, 0x31, 0x3d, 0xa4, 0x3e, 0x75, 0x4c, 0x8a, 0xae,
0x41, 0x83, 0x78, 0xd6, 0x4d, 0xdf, 0x0d, 0x3c, 0x99, 0xd1, 0x64, 0xd5, 0x6d, 0xee, 0xed, 0x0a,
0x38, 0x4e, 0x28, 0x42, 0xea, 0xd8, 0x22, 0x59, 0xc7, 0x99, 0xf3, 0x33, 0x82, 0xe3, 0x84, 0x22,
0x19, 0x6f, 0xb3, 0xa5, 0xe3, 0xcd, 0x00, 0x35, 0xb0, 0xba, 0xf2, 0x66, 0x7e, 0x45, 0x12, 0xa8,
0xef, 0xee, 0x6e, 0x9f, 0x0e, 0xdb, 0x57, 0xca, 0x3e, 0xbb, 0xf0, 0x13, 0x8f, 0x32, 0xfd, 0xdd,
0xdd, 0x6d, 0x1c, 0x32, 0x6b, 0x7f, 0x51, 0xe0, 0x42, 0xce, 0xc9, 0x73, 0x58, 0xf9, 0x7b, 0xf9,
0x95, 0xff, 0xd2, 0x14, 0x29, 0x2b, 0x59, 0xfa, 0x56, 0xc1, 0x09, 0xb1, 0xf5, 0xdf, 0x29, 0x7e,
0x2c, 0xba, 0x5a, 0xf9, 0xb2, 0x2e, 0xff, 0x42, 0xa4, 0xfd, 0x57, 0x81, 0x8b, 0x13, 0xaa, 0x08,
0xbd, 0x0f, 0x90, 0xce, 0xe0, 0x09, 0x41, 0x9b, 0xa0, 0x70, 0xec, 0x3d, 0x70, 0x59, 0x7c, 0xc2,
0x49, 0xa1, 0x19, 0x89, 0x88, 0x41, 0xd3, 0xa7, 0x8c, 0xfa, 0x03, 0xda, 0x7d, 0xdb, 0xf5, 0x65,
0xe8, 0xbe, 0x3b, 0x45, 0xe8, 0xc6, 0xaa, 0x37, 0x1d, 0xf5, 0x38, 0x15, 0x8c, 0xb3, 0x5a, 0xb4,
0x7f, 0x2a, 0xf0, 0xe5, 0x9c, 0x90, 0x77, 0x68, 0xdf, 0xb3, 0x09, 0xa7, 0xe7, 0x30, 0x2c, 0x1e,
0xe6, 0x86, 0xc5, 0x1b, 0x53, 0x78, 0x1a, 0x1b, 0x59, 0x7a, 0x85, 0xff, 0x43, 0x81, 0x4b, 0x13,
0x39, 0xce, 0xa1, 0xf8, 0xbf, 0x9f, 0x2f, 0xfe, 0x57, 0x3f, 0x85, 0x5f, 0xe5, 0x97, 0xef, 0xa5,
0xd2, 0x38, 0x7c, 0x21, 0xa7, 0xbb, 0xf6, 0x07, 0x05, 0x16, 0x63, 0xca, 0x70, 0xd5, 0x57, 0xb8,
0xf9, 0x6e, 0x00, 0xc8, 0x4f, 0xc9, 0xf1, 0xdb, 0xa9, 0x9a, 0xda, 0x7d, 0x33, 0xc1, 0xe0, 0x0c,
0x15, 0xba, 0x05, 0x28, 0xb6, 0x70, 0xdf, 0x16, 0x4b, 0x3b, 0x3c, 0x9d, 0x54, 0xc1, 0xbb, 0x2e,
0x79, 0x11, 0x1e, 0xa3, 0xc0, 0x13, 0xb8, 0xb4, 0xbf, 0x2a, 0xe9, 0x5e, 0x15, 0xe0, 0xcf, 0x6b,
0xe4, 0x85, 0x71, 0xa5, 0x91, 0xcf, 0xee, 0x05, 0x41, 0xf9, 0xb9, 0xdd, 0x0b, 0xc2, 0xba, 0x92,
0x96, 0x78, 0xa4, 0x16, 0xbc, 0x10, 0xad, 0x50, 0xf5, 0x0a, 0xbb, 0x2d, 0x6f, 0xce, 0x28, 0xac,
0x2f, 0x56, 0x33, 0x27, 0x2c, 0xd3, 0x89, 0xf7, 0xe9, 0x35, 0x68, 0x38, 0x6e, 0x97, 0x8a, 0xb7,
0x90, 0xc2, 0xf6, 0xbf, 0x2b, 0xe1, 0x38, 0xa1, 0x18, 0xfb, 0x23, 0x62, 0xf6, 0xb3, 0xf9, 0x23,
0x42, 0x5c, 0x2c, 0xb6, 0x1d, 0x12, 0x30, 0x71, 0x38, 0x34, 0x32, 0x17, 0x8b, 0x84, 0xe3, 0x84,
0x02, 0xdd, 0x4b, 0x57, 0x68, 0x5d, 0xe4, 0xe4, 0xeb, 0x55, 0x56, 0x68, 0xf9, 0xf6, 0x34, 0x8c,
0xc7, 0x4f, 0x5b, 0x33, 0x4f, 0x9e, 0xb6, 0x66, 0x3e, 0x7e, 0xda, 0x9a, 0xf9, 0x68, 0xd4, 0x52,
0x1e, 0x8f, 0x5a, 0xca, 0x93, 0x51, 0x4b, 0xf9, 0x78, 0xd4, 0x52, 0x3e, 0x19, 0xb5, 0x94, 0x5f,
0xfd, 0xbb, 0x35, 0xf3, 0x83, 0xe7, 0xcf, 0xfa, 0xbf, 0xed, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff,
0xaa, 0x59, 0xd2, 0xe3, 0x8e, 0x1b, 0x00, 0x00,
0x3d, 0x8e, 0x33, 0x93, 0xe4, 0x37, 0xf9, 0xda, 0xb7, 0x50, 0xb2, 0xa1, 0xcc, 0xec, 0xba, 0x08,
0xb2, 0xed, 0xd6, 0xd3, 0xdd, 0x96, 0xb6, 0x50, 0x0e, 0xc4, 0x49, 0xba, 0xca, 0x6a, 0x3f, 0xb2,
0x2f, 0xed, 0x8a, 0x85, 0x52, 0x78, 0xf1, 0xbc, 0x4c, 0x4c, 0x3c, 0xb6, 0xeb, 0xf7, 0x3c, 0x34,
0x17, 0x54, 0x71, 0xe1, 0xb6, 0xe2, 0x1f, 0x40, 0xdc, 0x90, 0x38, 0xc1, 0x7f, 0x00, 0x12, 0x48,
0xac, 0xc4, 0x65, 0x25, 0x38, 0xf4, 0x34, 0x74, 0x07, 0x71, 0xe1, 0xc2, 0x3d, 0x27, 0xe4, 0xe7,
0xe7, 0xcf, 0x19, 0xcf, 0x7a, 0xaa, 0x12, 0xb5, 0xb7, 0xf1, 0xef, 0xfb, 0xfb, 0xf7, 0xb3, 0x07,
0xae, 0x9d, 0xbc, 0xc9, 0x74, 0xcb, 0x6d, 0x13, 0xcf, 0x6a, 0xfb, 0x94, 0xb9, 0x81, 0x6f, 0xd2,
0x76, 0xff, 0x3a, 0xb1, 0xbd, 0x63, 0xf2, 0x6a, 0xbb, 0x4b, 0x1d, 0xea, 0x13, 0x4e, 0x3b, 0xba,
0xe7, 0xbb, 0xdc, 0x45, 0xcf, 0x47, 0xd4, 0x3a, 0xf1, 0x2c, 0x3d, 0xa6, 0xd6, 0x63, 0xea, 0x8d,
0x97, 0xbb, 0x16, 0x3f, 0x0e, 0x0e, 0x75, 0xd3, 0xed, 0xb5, 0xbb, 0x6e, 0xd7, 0x6d, 0x0b, 0xa6,
0xc3, 0xe0, 0x48, 0x3c, 0x89, 0x07, 0xf1, 0x2b, 0x12, 0xb6, 0xa1, 0x65, 0x54, 0x9b, 0xae, 0x1f,
0xaa, 0x2d, 0x2a, 0xdc, 0x78, 0x2d, 0xa5, 0xe9, 0x11, 0xf3, 0xd8, 0x72, 0xa8, 0x7f, 0xda, 0xf6,
0x4e, 0xba, 0x79, 0x7b, 0xa7, 0xe1, 0x62, 0xed, 0x1e, 0xe5, 0x64, 0x9c, 0xae, 0x76, 0x19, 0x97,
0x1f, 0x38, 0xdc, 0xea, 0x8d, 0xaa, 0x79, 0xfd, 0x59, 0x0c, 0xcc, 0x3c, 0xa6, 0x3d, 0x52, 0xe4,
0xd3, 0xfe, 0xa6, 0xc0, 0xda, 0x96, 0x6d, 0xbb, 0x26, 0xe1, 0x96, 0xeb, 0x60, 0xca, 0x02, 0x9b,
0xa3, 0x1f, 0xc3, 0x7c, 0x87, 0xf6, 0x2d, 0x93, 0xb2, 0x75, 0xe5, 0xb2, 0xb2, 0xd9, 0xb8, 0xf1,
0x9a, 0x3e, 0x29, 0xd8, 0xfa, 0x8e, 0x20, 0x2e, 0x8a, 0x31, 0x56, 0x1f, 0x0f, 0x5a, 0x33, 0xc3,
0x41, 0x6b, 0x3e, 0xc2, 0x33, 0x1c, 0x4b, 0x45, 0x0f, 0x60, 0xc9, 0x71, 0x3b, 0xf4, 0x80, 0xda,
0xd4, 0xe4, 0xae, 0xbf, 0xae, 0x0a, 0x2d, 0x97, 0xb3, 0x5a, 0xc2, 0x2c, 0xe8, 0xfd, 0xeb, 0xfa,
0xdd, 0x0c, 0x9d, 0xb1, 0x36, 0x1c, 0xb4, 0x96, 0xb2, 0x10, 0x9c, 0x93, 0xa3, 0x7d, 0xa2, 0x42,
0xc3, 0x20, 0xcc, 0x32, 0x23, 0x8d, 0xe8, 0xe7, 0x00, 0x84, 0x73, 0xdf, 0x3a, 0x0c, 0xb8, 0xf0,
0x45, 0xdd, 0x6c, 0xdc, 0xf8, 0xf6, 0x64, 0x5f, 0x32, 0xec, 0xfa, 0x56, 0xc2, 0xbb, 0xeb, 0x70,
0xff, 0xd4, 0x78, 0x41, 0x3a, 0x04, 0x29, 0xe2, 0x17, 0xff, 0x6c, 0x2d, 0xdf, 0x0f, 0x88, 0x6d,
0x1d, 0x59, 0xb4, 0x73, 0x97, 0xf4, 0x28, 0xce, 0x68, 0x44, 0x7d, 0x58, 0x30, 0x89, 0x47, 0x4c,
0x8b, 0x9f, 0xae, 0xcf, 0x0a, 0xed, 0x6f, 0x54, 0xd7, 0xbe, 0x2d, 0x39, 0x23, 0xdd, 0x57, 0xa4,
0xee, 0x85, 0x18, 0x3c, 0xaa, 0x39, 0xd1, 0xb5, 0x61, 0xc3, 0x6a, 0xc1, 0x76, 0xb4, 0x06, 0xea,
0x09, 0x3d, 0x15, 0xf9, 0x5c, 0xc4, 0xe1, 0x4f, 0xb4, 0x0d, 0xb5, 0x3e, 0xb1, 0x03, 0xba, 0x3e,
0x2b, 0xa2, 0xff, 0x72, 0xa5, 0x1c, 0xc7, 0x52, 0x71, 0xc4, 0xfb, 0x9d, 0xd9, 0x37, 0x95, 0x8d,
0x13, 0x58, 0xce, 0xd9, 0x3a, 0x46, 0xd7, 0x4e, 0x5e, 0x97, 0x9e, 0xd1, 0x95, 0x94, 0xab, 0xee,
0x9d, 0x74, 0xf3, 0xca, 0xef, 0x07, 0xc4, 0xe1, 0x16, 0x3f, 0xcd, 0x28, 0xd3, 0x6e, 0xc2, 0x85,
0xed, 0xdd, 0xdb, 0x91, 0x35, 0x71, 0xde, 0xd1, 0x0d, 0x00, 0xfa, 0xa1, 0xe7, 0x53, 0xc6, 0x2c,
0xd7, 0x89, 0xf4, 0x1a, 0x28, 0x4e, 0xd6, 0x6e, 0x82, 0xc1, 0x19, 0x2a, 0xad, 0x0f, 0x75, 0x59,
0x25, 0x97, 0x61, 0xce, 0x21, 0x3d, 0x2a, 0xf9, 0x96, 0x24, 0xdf, 0x9c, 0x88, 0xa9, 0xc0, 0xa0,
0x5b, 0x50, 0x3b, 0x0c, 0x33, 0x23, 0xcd, 0xbf, 0x5a, 0x39, 0x89, 0xc6, 0xe2, 0x70, 0xd0, 0xaa,
0x09, 0x00, 0x8e, 0x44, 0x68, 0x8f, 0x66, 0xe1, 0x6b, 0xc5, 0x86, 0xd9, 0x76, 0x9d, 0x23, 0xab,
0x1b, 0xf8, 0xe2, 0x01, 0x7d, 0x0f, 0xea, 0x91, 0x48, 0x69, 0xd1, 0xa6, 0xb4, 0xa8, 0x7e, 0x20,
0xa0, 0x67, 0x83, 0xd6, 0x73, 0x45, 0xd6, 0x08, 0x83, 0x25, 0x1f, 0xda, 0x84, 0x05, 0x9f, 0x7e,
0x10, 0x50, 0xc6, 0x99, 0xa8, 0xbb, 0x45, 0x63, 0x29, 0x2c, 0x1d, 0x2c, 0x61, 0x38, 0xc1, 0xa2,
0x8f, 0x14, 0xb8, 0x18, 0x75, 0x65, 0xce, 0x06, 0xd9, 0x91, 0xd7, 0xab, 0xd4, 0x44, 0x8e, 0xd1,
0xf8, 0xaa, 0x34, 0xf6, 0xe2, 0x18, 0x24, 0x1e, 0xa7, 0x4a, 0xfb, 0xb7, 0x02, 0xcf, 0x8d, 0x9f,
0x20, 0xe8, 0x08, 0xe6, 0x7d, 0xf1, 0x2b, 0x6e, 0xde, 0xb7, 0xaa, 0x18, 0x24, 0xdd, 0x2c, 0x9f,
0x47, 0xd1, 0x33, 0xc3, 0xb1, 0x70, 0x64, 0x42, 0xdd, 0x14, 0x36, 0xc9, 0x2e, 0x7d, 0x6b, 0xba,
0x79, 0x97, 0x8f, 0xc0, 0x4a, 0x9c, 0xae, 0x08, 0x8c, 0xa5, 0x68, 0xed, 0x77, 0x0a, 0xac, 0x16,
0xba, 0x08, 0x35, 0x41, 0xb5, 0x1c, 0x2e, 0xca, 0x4a, 0x8d, 0x72, 0xb4, 0xe7, 0xf0, 0x07, 0x61,
0xb1, 0xe3, 0x10, 0x81, 0xae, 0xc0, 0xdc, 0xa1, 0xeb, 0xda, 0x22, 0x1d, 0x0b, 0xc6, 0xf2, 0x70,
0xd0, 0x5a, 0x34, 0x5c, 0xd7, 0x8e, 0x28, 0x04, 0x0a, 0x7d, 0x13, 0xea, 0x8c, 0xfb, 0x96, 0xd3,
0x5d, 0x9f, 0x13, 0xd5, 0xb2, 0x3a, 0x1c, 0xb4, 0x1a, 0x07, 0x02, 0x12, 0x91, 0x49, 0x34, 0x7a,
0x11, 0xe6, 0xfb, 0xd4, 0x17, 0x1d, 0x52, 0x13, 0x94, 0x62, 0x9a, 0x3e, 0x88, 0x40, 0x11, 0x69,
0x4c, 0xa0, 0xfd, 0x7e, 0x16, 0x1a, 0x32, 0x81, 0x36, 0xb1, 0x7a, 0xe8, 0x61, 0xa6, 0xa0, 0xa2,
0x4c, 0xbc, 0x34, 0x45, 0x26, 0x8c, 0xb5, 0x78, 0x78, 0x8d, 0xa9, 0x40, 0x0a, 0x0d, 0xd3, 0x75,
0x18, 0xf7, 0x89, 0xe5, 0xc8, 0x72, 0xcd, 0x0f, 0x88, 0x49, 0x85, 0x27, 0xd9, 0x8c, 0x8b, 0x52,
0x41, 0x23, 0x85, 0x31, 0x9c, 0x95, 0x8b, 0xde, 0x4f, 0x52, 0xac, 0x0a, 0x0d, 0xaf, 0x57, 0xd2,
0x10, 0x3a, 0x5f, 0x2d, 0xbb, 0x7f, 0x55, 0x60, 0xbd, 0x8c, 0x29, 0xd7, 0x8f, 0xca, 0xa7, 0xea,
0xc7, 0xd9, 0xf3, 0xeb, 0xc7, 0x3f, 0x29, 0x99, 0xdc, 0x33, 0x86, 0x7e, 0x02, 0x0b, 0xe1, 0x99,
0xd2, 0x21, 0x9c, 0xc8, 0x73, 0xe0, 0x95, 0x49, 0xe3, 0x9b, 0xe9, 0x21, 0x75, 0xb8, 0xba, 0xef,
0x1d, 0xfe, 0x94, 0x9a, 0xfc, 0x0e, 0xe5, 0x24, 0x1d, 0xc6, 0x29, 0x0c, 0x27, 0x52, 0xd1, 0x3d,
0x98, 0x63, 0x1e, 0x35, 0xa7, 0x59, 0x44, 0xc2, 0xb4, 0x03, 0x8f, 0x9a, 0xe9, 0xbc, 0x0e, 0x9f,
0xb0, 0x10, 0xa4, 0xfd, 0x3a, 0x9b, 0x0c, 0xc6, 0xf2, 0xc9, 0x28, 0x0b, 0xb1, 0x72, 0x7e, 0x21,
0xfe, 0x63, 0x32, 0x0a, 0x84, 0x7d, 0xb7, 0x2d, 0xc6, 0xd1, 0x7b, 0x23, 0x61, 0xd6, 0xab, 0x85,
0x39, 0xe4, 0x16, 0x41, 0x4e, 0xba, 0x2c, 0x86, 0x64, 0x42, 0x7c, 0x17, 0x6a, 0x16, 0xa7, 0xbd,
0xb8, 0xbf, 0xae, 0x56, 0x8e, 0xb1, 0xb1, 0x2c, 0xa5, 0xd6, 0xf6, 0x42, 0x7e, 0x1c, 0x89, 0xd1,
0x9e, 0xe4, 0x3d, 0x08, 0x63, 0x8f, 0x7e, 0x04, 0x8b, 0x4c, 0x6e, 0xe4, 0x78, 0x4a, 0x5c, 0xab,
0xa2, 0x27, 0x39, 0xef, 0x2e, 0x48, 0x55, 0x8b, 0x31, 0x84, 0xe1, 0x54, 0x62, 0xa6, 0x83, 0x67,
0xa7, 0xea, 0xe0, 0x42, 0xfe, 0x4b, 0x3b, 0xd8, 0x87, 0x71, 0x09, 0x44, 0x3f, 0x84, 0xba, 0xeb,
0x91, 0x0f, 0x02, 0x2a, 0xb3, 0xf2, 0x8c, 0x0b, 0xee, 0x9e, 0xa0, 0x1d, 0x57, 0x26, 0x10, 0xea,
0x8c, 0xd0, 0x58, 0x8a, 0xd4, 0x1e, 0x29, 0xb0, 0x56, 0x1c, 0x66, 0x53, 0x4c, 0x8b, 0x7d, 0x58,
0xe9, 0x11, 0x6e, 0x1e, 0x27, 0x0b, 0x45, 0xb4, 0xd0, 0xa2, 0xb1, 0x39, 0x1c, 0xb4, 0x56, 0xee,
0xe4, 0x30, 0x67, 0x83, 0x16, 0x7a, 0x3b, 0xb0, 0xed, 0xd3, 0xfc, 0xcd, 0x58, 0xe0, 0xd7, 0x7e,
0xa9, 0xc2, 0x72, 0x6e, 0x76, 0x57, 0xb8, 0x8e, 0xb6, 0x60, 0xb5, 0x93, 0x06, 0x3b, 0x44, 0x48,
0x33, 0xbe, 0x22, 0x89, 0xb3, 0x95, 0x22, 0xf8, 0x8a, 0xf4, 0xf9, 0xd2, 0x51, 0x3f, 0xf3, 0xd2,
0x79, 0x00, 0x2b, 0x24, 0xd9, 0xd6, 0x77, 0xdc, 0x0e, 0x95, 0xbb, 0x52, 0x97, 0x5c, 0x2b, 0x5b,
0x39, 0xec, 0xd9, 0xa0, 0xf5, 0xa5, 0xe2, 0x8e, 0x0f, 0xe1, 0xb8, 0x20, 0x05, 0xbd, 0x00, 0x35,
0xd3, 0x0d, 0x1c, 0x2e, 0x16, 0xaa, 0x9a, 0xb6, 0xca, 0x76, 0x08, 0xc4, 0x11, 0x0e, 0x7d, 0x0b,
0x1a, 0xa4, 0xd3, 0xb3, 0x9c, 0x2d, 0xd3, 0xa4, 0x8c, 0xad, 0xd7, 0xc5, 0x2a, 0x4f, 0x16, 0xd6,
0x56, 0x8a, 0xc2, 0x59, 0x3a, 0xed, 0xbf, 0x4a, 0x7c, 0x27, 0x96, 0xdc, 0x33, 0xe8, 0x6a, 0x78,
0x1d, 0x09, 0x94, 0x4c, 0x4e, 0xe6, 0xc0, 0x11, 0x60, 0x1c, 0xe3, 0xd1, 0x37, 0xa0, 0xde, 0xf1,
0xad, 0x3e, 0xf5, 0x65, 0x66, 0x92, 0x1e, 0xd8, 0x11, 0x50, 0x2c, 0xb1, 0x61, 0xb2, 0xbd, 0xf8,
0xde, 0xc8, 0x24, 0x7b, 0xdf, 0x75, 0x6d, 0x2c, 0x30, 0x42, 0x92, 0xb0, 0x4a, 0x86, 0x30, 0x95,
0x14, 0xd9, 0x2a, 0xb1, 0xe8, 0x7a, 0xde, 0xeb, 0x9a, 0xf0, 0x7a, 0x75, 0xa2, 0xc7, 0xef, 0xc1,
0x4a, 0xe1, 0xae, 0xbf, 0x05, 0xaa, 0x49, 0x6d, 0xd9, 0x78, 0xed, 0xc9, 0x05, 0x31, 0xf2, 0x56,
0x60, 0xcc, 0x0f, 0x07, 0x2d, 0x75, 0x7b, 0xf7, 0x36, 0x0e, 0x85, 0x68, 0xbf, 0x55, 0xe0, 0x52,
0x69, 0x73, 0x66, 0x02, 0xa4, 0x4c, 0x0c, 0x10, 0x01, 0xf0, 0x88, 0x4f, 0x7a, 0x94, 0x53, 0x9f,
0x8d, 0x59, 0x58, 0xf9, 0x39, 0x2d, 0x5f, 0xbe, 0x75, 0x4c, 0x7e, 0xb6, 0xfb, 0x21, 0xa7, 0x4e,
0x78, 0x5b, 0xa5, 0xbb, 0x70, 0x3f, 0x11, 0x84, 0x33, 0x42, 0xb5, 0xdf, 0xcc, 0xc2, 0x32, 0x96,
0xee, 0x45, 0xd7, 0xd7, 0xff, 0x7f, 0x03, 0xdf, 0xcf, 0x6d, 0xe0, 0x67, 0x44, 0x3a, 0x67, 0x5c,
0xd9, 0x0e, 0x46, 0x0f, 0xc3, 0xbb, 0x94, 0xf0, 0x80, 0x55, 0x7b, 0x97, 0xc8, 0x0b, 0x15, 0x8c,
0x69, 0x12, 0xa2, 0x67, 0x2c, 0x05, 0x6a, 0x43, 0x05, 0x9a, 0x39, 0xfa, 0x70, 0x78, 0x06, 0x3d,
0xea, 0x63, 0x7a, 0x44, 0x7d, 0xea, 0x98, 0x14, 0x5d, 0x83, 0x05, 0xe2, 0x59, 0x37, 0x7d, 0x37,
0xf0, 0x64, 0x46, 0x93, 0xed, 0xb8, 0xb5, 0xbf, 0x27, 0xe0, 0x38, 0xa1, 0x08, 0xa9, 0x63, 0x8b,
0x64, 0xe9, 0x67, 0x2e, 0xd6, 0x08, 0x8e, 0x13, 0x8a, 0x64, 0x22, 0xce, 0x95, 0x4e, 0x44, 0x03,
0xd4, 0xc0, 0xea, 0xc8, 0x33, 0xfb, 0x15, 0x49, 0xa0, 0xbe, 0xbb, 0xb7, 0x73, 0x36, 0x68, 0x5d,
0x29, 0xfb, 0x52, 0xc3, 0x4f, 0x3d, 0xca, 0xf4, 0x77, 0xf7, 0x76, 0x70, 0xc8, 0xac, 0xfd, 0x59,
0x81, 0x0b, 0x39, 0x27, 0xcf, 0xe1, 0x4a, 0xd8, 0xcf, 0x5f, 0x09, 0x2f, 0x4d, 0x91, 0xb2, 0x92,
0x3b, 0xc1, 0x2a, 0x38, 0x21, 0x0e, 0x85, 0x77, 0x8a, 0xdf, 0x97, 0xae, 0x56, 0x3e, 0xc6, 0xcb,
0x3f, 0x2a, 0x69, 0xff, 0x51, 0xe0, 0xe2, 0x98, 0x2a, 0x42, 0xef, 0x03, 0xa4, 0x63, 0x7b, 0x4c,
0xd0, 0xc6, 0x28, 0x1c, 0x79, 0x75, 0x5c, 0x11, 0x5f, 0x7d, 0x52, 0x68, 0x46, 0x22, 0x62, 0xd0,
0xf0, 0x29, 0xa3, 0x7e, 0x9f, 0x76, 0xde, 0x76, 0x7d, 0x19, 0xba, 0xef, 0x4e, 0x11, 0xba, 0x91,
0xea, 0x4d, 0xb7, 0x03, 0x4e, 0x05, 0xe3, 0xac, 0x16, 0xed, 0x1f, 0x0a, 0x7c, 0x39, 0x27, 0xe4,
0x1d, 0xda, 0xf3, 0x6c, 0xc2, 0xe9, 0x39, 0x0c, 0x8b, 0x87, 0xb9, 0x61, 0xf1, 0xc6, 0x14, 0x9e,
0xc6, 0x46, 0x96, 0x1e, 0xee, 0x7f, 0x57, 0xe0, 0xd2, 0x58, 0x8e, 0x73, 0x28, 0xfe, 0xef, 0xe7,
0x8b, 0xff, 0xd5, 0x4f, 0xe1, 0x57, 0xf9, 0xb1, 0x7c, 0xa9, 0x34, 0x0e, 0x5f, 0xc8, 0xe9, 0xae,
0xfd, 0x41, 0x81, 0xa5, 0x98, 0x32, 0xbc, 0x0e, 0x2a, 0x9c, 0x89, 0x37, 0x00, 0xe4, 0xd7, 0xe7,
0xf8, 0x85, 0x56, 0x4d, 0xed, 0xbe, 0x99, 0x60, 0x70, 0x86, 0x0a, 0xdd, 0x02, 0x14, 0x5b, 0x78,
0x60, 0x8b, 0xa5, 0x1d, 0x5e, 0x5b, 0xaa, 0xe0, 0xdd, 0x90, 0xbc, 0x08, 0x8f, 0x50, 0xe0, 0x31,
0x5c, 0xda, 0x5f, 0x94, 0x74, 0xaf, 0x0a, 0xf0, 0xe7, 0x35, 0xf2, 0xc2, 0xb8, 0xd2, 0xc8, 0x67,
0xf7, 0x82, 0xa0, 0xfc, 0xdc, 0xee, 0x05, 0x61, 0x5d, 0x49, 0x4b, 0x3c, 0x52, 0x0b, 0x5e, 0x88,
0x56, 0xa8, 0x7a, 0x85, 0xdd, 0x96, 0x67, 0x6a, 0x14, 0xd6, 0x17, 0xab, 0x99, 0x13, 0x96, 0xe9,
0xd8, 0x93, 0xf6, 0x1a, 0x2c, 0x38, 0x6e, 0x87, 0x8a, 0x17, 0x97, 0xc2, 0xf6, 0xbf, 0x2b, 0xe1,
0x38, 0xa1, 0x18, 0xf9, 0xef, 0x62, 0xee, 0xb3, 0xf9, 0xef, 0x42, 0x5c, 0x2c, 0xb6, 0x1d, 0x12,
0xc4, 0xd7, 0x72, 0x7a, 0xb1, 0x48, 0x38, 0x4e, 0x28, 0xd0, 0xbd, 0x74, 0x85, 0xd6, 0x45, 0x4e,
0xbe, 0x5e, 0x65, 0x85, 0x96, 0x6f, 0x4f, 0xc3, 0x78, 0xfc, 0xb4, 0x39, 0xf3, 0xe4, 0x69, 0x73,
0xe6, 0xe3, 0xa7, 0xcd, 0x99, 0x8f, 0x86, 0x4d, 0xe5, 0xf1, 0xb0, 0xa9, 0x3c, 0x19, 0x36, 0x95,
0x8f, 0x87, 0x4d, 0xe5, 0x93, 0x61, 0x53, 0xf9, 0xd5, 0xbf, 0x9a, 0x33, 0x3f, 0x78, 0x7e, 0xd2,
0x5f, 0x74, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x1a, 0xa5, 0x7d, 0xad, 0xc1, 0x1b, 0x00, 0x00,
}
func (m *AllocationResult) Marshal() (dAtA []byte, err error) {
@ -1857,6 +1857,16 @@ func (m *DeviceRequestAllocationResult) MarshalToSizedBuffer(dAtA []byte) (int,
_ = i
var l int
_ = l
if m.AdminAccess != nil {
i--
if *m.AdminAccess {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x28
}
i -= len(m.Device)
copy(dAtA[i:], m.Device)
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Device)))
@ -2829,6 +2839,9 @@ func (m *DeviceRequestAllocationResult) Size() (n int) {
n += 1 + l + sovGenerated(uint64(l))
l = len(m.Device)
n += 1 + l + sovGenerated(uint64(l))
if m.AdminAccess != nil {
n += 2
}
return n
}
@ -3310,6 +3323,7 @@ func (this *DeviceRequestAllocationResult) String() string {
`Driver:` + fmt.Sprintf("%v", this.Driver) + `,`,
`Pool:` + fmt.Sprintf("%v", this.Pool) + `,`,
`Device:` + fmt.Sprintf("%v", this.Device) + `,`,
`AdminAccess:` + valueToStringGenerated(this.AdminAccess) + `,`,
`}`,
}, "")
return s
@ -5834,6 +5848,27 @@ func (m *DeviceRequestAllocationResult) Unmarshal(dAtA []byte) error {
}
m.Device = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field AdminAccess", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
b := bool(v != 0)
m.AdminAccess = &b
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])

View File

@ -453,6 +453,17 @@ message DeviceRequestAllocationResult {
//
// +required
optional string device = 4;
// AdminAccess is a copy of the AdminAccess value in the
// request which caused this device to be allocated.
//
// New allocations are required to have this set. Old allocations made
// by Kubernetes 1.31 do not have it yet. Clients which want to
// support Kubernetes 1.31 need to look up the request and retrieve
// the value from there if this field is not set.
//
// +required
optional bool adminAccess = 5;
}
// DeviceSelector must have exactly one field set.

View File

@ -788,6 +788,17 @@ type DeviceRequestAllocationResult struct {
//
// +required
Device string `json:"device" protobuf:"bytes,4,name=device"`
// AdminAccess is a copy of the AdminAccess value in the
// request which caused this device to be allocated.
//
// New allocations are required to have this set. Old allocations made
// by Kubernetes 1.31 do not have it yet. Clients which want to
// support Kubernetes 1.31 need to look up the request and retrieve
// the value from there if this field is not set.
//
// +required
AdminAccess *bool `json:"adminAccess" protobuf:"bytes,5,name=adminAccess"`
}
// DeviceAllocationConfiguration gets embedded in an AllocationResult.

View File

@ -190,11 +190,12 @@ func (DeviceRequest) SwaggerDoc() map[string]string {
}
var map_DeviceRequestAllocationResult = map[string]string{
"": "DeviceRequestAllocationResult contains the allocation result for one request.",
"request": "Request is the name of the request in the claim which caused this device to be allocated. Multiple devices may have been allocated per request.",
"driver": "Driver specifies the name of the DRA driver whose kubelet plugin should be invoked to process the allocation once the claim is needed on a node.\n\nMust be a DNS subdomain and should end with a DNS domain owned by the vendor of the driver.",
"pool": "This name together with the driver name and the device name field identify which device was allocated (`<driver name>/<pool name>/<device name>`).\n\nMust not be longer than 253 characters and may contain one or more DNS sub-domains separated by slashes.",
"device": "Device references one device instance via its name in the driver's resource pool. It must be a DNS label.",
"": "DeviceRequestAllocationResult contains the allocation result for one request.",
"request": "Request is the name of the request in the claim which caused this device to be allocated. Multiple devices may have been allocated per request.",
"driver": "Driver specifies the name of the DRA driver whose kubelet plugin should be invoked to process the allocation once the claim is needed on a node.\n\nMust be a DNS subdomain and should end with a DNS domain owned by the vendor of the driver.",
"pool": "This name together with the driver name and the device name field identify which device was allocated (`<driver name>/<pool name>/<device name>`).\n\nMust not be longer than 253 characters and may contain one or more DNS sub-domains separated by slashes.",
"device": "Device references one device instance via its name in the driver's resource pool. It must be a DNS label.",
"adminAccess": "AdminAccess is a copy of the AdminAccess value in the request which caused this device to be allocated.\n\nNew allocations are required to have this set. Old allocations made by Kubernetes 1.31 do not have it yet. Clients which want to support Kubernetes 1.31 need to look up the request and retrieve the value from there if this field is not set.",
}
func (DeviceRequestAllocationResult) SwaggerDoc() map[string]string {

View File

@ -144,7 +144,9 @@ func (in *DeviceAllocationResult) DeepCopyInto(out *DeviceAllocationResult) {
if in.Results != nil {
in, out := &in.Results, &out.Results
*out = make([]DeviceRequestAllocationResult, len(*in))
copy(*out, *in)
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.Config != nil {
in, out := &in.Config, &out.Config
@ -441,6 +443,11 @@ func (in *DeviceRequest) DeepCopy() *DeviceRequest {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeviceRequestAllocationResult) DeepCopyInto(out *DeviceRequestAllocationResult) {
*out = *in
if in.AdminAccess != nil {
in, out := &in.AdminAccess, &out.AdminAccess
*out = new(bool)
**out = **in
}
return
}

View File

@ -99,7 +99,8 @@
"request": "requestValue",
"driver": "driverValue",
"pool": "poolValue",
"device": "deviceValue"
"device": "deviceValue",
"adminAccess": true
}
],
"config": [

View File

@ -76,7 +76,8 @@ status:
- requestsValue
source: sourceValue
results:
- device: deviceValue
- adminAccess: true
device: deviceValue
driver: driverValue
pool: poolValue
request: requestValue

View File

@ -99,7 +99,8 @@
"request": "requestValue",
"driver": "driverValue",
"pool": "poolValue",
"device": "deviceValue"
"device": "deviceValue",
"adminAccess": null
}
],
"config": [

View File

@ -76,7 +76,8 @@ status:
- requestsValue
source: sourceValue
results:
- device: deviceValue
- adminAccess: null
device: deviceValue
driver: driverValue
pool: poolValue
request: requestValue

View File

@ -12443,6 +12443,9 @@ var schemaYAML = typed.YAMLObject(`types:
- name: io.k8s.api.resource.v1alpha3.DeviceRequestAllocationResult
map:
fields:
- name: adminAccess
type:
scalar: boolean
- name: device
type:
scalar: string

View File

@ -21,10 +21,11 @@ package v1alpha3
// DeviceRequestAllocationResultApplyConfiguration represents a declarative configuration of the DeviceRequestAllocationResult type for use
// with apply.
type DeviceRequestAllocationResultApplyConfiguration struct {
Request *string `json:"request,omitempty"`
Driver *string `json:"driver,omitempty"`
Pool *string `json:"pool,omitempty"`
Device *string `json:"device,omitempty"`
Request *string `json:"request,omitempty"`
Driver *string `json:"driver,omitempty"`
Pool *string `json:"pool,omitempty"`
Device *string `json:"device,omitempty"`
AdminAccess *bool `json:"adminAccess,omitempty"`
}
// DeviceRequestAllocationResultApplyConfiguration constructs a declarative configuration of the DeviceRequestAllocationResult type for use with
@ -64,3 +65,11 @@ func (b *DeviceRequestAllocationResultApplyConfiguration) WithDevice(value strin
b.Device = &value
return b
}
// WithAdminAccess sets the AdminAccess 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 AdminAccess field is set to the value of the last call.
func (b *DeviceRequestAllocationResultApplyConfiguration) WithAdminAccess(value bool) *DeviceRequestAllocationResultApplyConfiguration {
b.AdminAccess = &value
return b
}

View File

@ -273,6 +273,15 @@ func (a *Allocator) Allocate(ctx context.Context, node *v1.Node) (finalResult []
continue
}
for _, result := range claim.Status.Allocation.Devices.Results {
// Kubernetes 1.31 did not set this, 1.32 always does.
// Supporting 1.31 is not worth the additional code that
// would have to be written (= looking up in request) because
// it is extremely unlikely that there really is a result
// that still exists in a cluster from 1.31 where this matters.
if ptr.Deref(result.AdminAccess, false) {
// Ignore, it's not considered allocated.
continue
}
deviceID := DeviceID{Driver: result.Driver, Pool: result.Pool, Device: result.Device}
alloc.allocated[deviceID] = true
numAllocated++
@ -735,10 +744,11 @@ func (alloc *allocator) allocateDevice(r deviceIndices, device *resourceapi.Basi
alloc.allocated[deviceID] = true
}
result := resourceapi.DeviceRequestAllocationResult{
Request: request.Name,
Driver: deviceID.Driver,
Pool: deviceID.Pool,
Device: deviceID.Device,
Request: request.Name,
Driver: deviceID.Driver,
Pool: deviceID.Pool,
Device: deviceID.Device,
AdminAccess: &request.AdminAccess,
}
previousNumResults := len(alloc.result[r.claimIndex].Devices.Results)
alloc.result[r.claimIndex].Devices.Results = append(alloc.result[r.claimIndex].Devices.Results, result)

View File

@ -241,13 +241,15 @@ func slice(name string, nodeSelection any, pool, driver string, devices ...resou
return slice
}
func deviceAllocationResult(request, driver, pool, device string) resourceapi.DeviceRequestAllocationResult {
return resourceapi.DeviceRequestAllocationResult{
func deviceAllocationResult(request, driver, pool, device string, adminAccess bool) resourceapi.DeviceRequestAllocationResult {
r := resourceapi.DeviceRequestAllocationResult{
Request: request,
Driver: driver,
Pool: pool,
Device: device,
}
r.AdminAccess = &adminAccess
return r
}
// nodeLabelSelector creates a node selector with a label match for "key" in "values".
@ -375,7 +377,7 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
)},
},
"other-node": {
@ -389,7 +391,7 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node2),
deviceAllocationResult(req0, driverA, pool2, device1),
deviceAllocationResult(req0, driverA, pool2, device1, false),
)},
},
"small-and-large": {
@ -418,8 +420,8 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req1, driverA, pool1, device2),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req1, driverA, pool1, device2, false),
)},
},
"small-and-large-backtrack-requests": {
@ -451,8 +453,8 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req1, driverA, pool1, device2),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req1, driverA, pool1, device2, false),
)},
},
"small-and-large-backtrack-claims": {
@ -487,8 +489,8 @@ func TestAllocator(t *testing.T) {
node: node(node1, region1),
expectResults: []any{
allocationResult(localNodeSelector(node1), deviceAllocationResult(req0, driverA, pool1, device1)),
allocationResult(localNodeSelector(node1), deviceAllocationResult(req1, driverA, pool1, device2)),
allocationResult(localNodeSelector(node1), deviceAllocationResult(req0, driverA, pool1, device1, false)),
allocationResult(localNodeSelector(node1), deviceAllocationResult(req1, driverA, pool1, device2, false)),
},
},
"devices-split-across-different-slices": {
@ -507,8 +509,8 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool2, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req0, driverA, pool2, device1, false),
)},
},
"obsolete-slice": {
@ -527,7 +529,7 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
)},
},
"no-slices": {
@ -594,7 +596,7 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
)},
},
"all-devices-many": {
@ -612,8 +614,8 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool2, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req0, driverA, pool2, device1, false),
)},
},
"all-devices-of-the-incomplete-pool": {
@ -664,11 +666,11 @@ func TestAllocator(t *testing.T) {
expectResults: []any{
allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
),
allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverB, pool1, device1),
deviceAllocationResult(req0, driverB, pool1, device1, false),
),
},
},
@ -699,11 +701,11 @@ func TestAllocator(t *testing.T) {
expectResults: []any{
allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverB, pool1, device1),
deviceAllocationResult(req0, driverB, pool1, device1, false),
),
allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
),
},
},
@ -737,12 +739,12 @@ func TestAllocator(t *testing.T) {
expectResults: []any{
allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool1, device2),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req0, driverA, pool1, device2, false),
),
allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverB, pool1, device1),
deviceAllocationResult(req0, driverB, pool1, device1, false),
),
},
},
@ -776,12 +778,12 @@ func TestAllocator(t *testing.T) {
expectResults: []any{
allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverB, pool1, device1),
deviceAllocationResult(req0, driverB, pool1, device1, false),
),
allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool1, device2),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req0, driverA, pool1, device2, false),
),
},
},
@ -839,7 +841,7 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
nodeLabelSelector(regionKey, region1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
)},
},
"unsuccessful-allocation-network-attached-device": {
@ -875,10 +877,10 @@ func TestAllocator(t *testing.T) {
},
}},
},
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool2, device1),
deviceAllocationResult(req0, driverA, pool3, device1),
deviceAllocationResult(req0, driverA, pool4, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req0, driverA, pool2, device1, false),
deviceAllocationResult(req0, driverA, pool3, device1, false),
deviceAllocationResult(req0, driverA, pool4, device1, false),
)},
},
"local-and-network-attached-devices": {
@ -893,8 +895,8 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
// Once there is any node-local device, the selector is for that node.
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool2, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req0, driverA, pool2, device1, false),
)},
},
"several-different-drivers": {
@ -910,16 +912,16 @@ func TestAllocator(t *testing.T) {
node: node(node1, region1),
expectResults: []any{
allocationResult(localNodeSelector(node1), deviceAllocationResult(req0, driverA, pool1, device1)),
allocationResult(localNodeSelector(node1), deviceAllocationResult(req0, driverB, pool1, device1)),
allocationResult(localNodeSelector(node1), deviceAllocationResult(req0, driverA, pool1, device1, false)),
allocationResult(localNodeSelector(node1), deviceAllocationResult(req0, driverB, pool1, device1, false)),
},
},
"already-allocated-devices": {
claimsToAllocate: objects(claim(claim0, req0, classA)),
allocatedClaims: objects(
allocatedClaim(claim0, req0, classA,
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req1, driverA, pool1, device2),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req1, driverA, pool1, device2, false),
),
),
classes: objects(class(classA, driverA)),
@ -928,6 +930,42 @@ func TestAllocator(t *testing.T) {
expectResults: nil,
},
"admin-access": {
claimsToAllocate: func() []*resourceapi.ResourceClaim {
c := claim(claim0, req0, classA)
c.Spec.Devices.Requests[0].AdminAccess = true
return []*resourceapi.ResourceClaim{c}
}(),
allocatedClaims: objects(
allocatedClaim(claim0, req0, classA,
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req1, driverA, pool1, device2, false),
),
),
classes: objects(class(classA, driverA)),
slices: objects(sliceWithOneDevice(slice1, node1, pool1, driverA)),
node: node(node1, region1),
expectResults: []any{
allocationResult(localNodeSelector(node1), deviceAllocationResult(req0, driverA, pool1, device1, true)),
},
},
"already-allocated-for-admin-access": {
claimsToAllocate: objects(claim(claim0, req0, classA)),
allocatedClaims: objects(
allocatedClaim(claim0, req0, classA,
deviceAllocationResult(req0, driverA, pool1, device1, true),
deviceAllocationResult(req1, driverA, pool1, device2, true),
),
),
classes: objects(class(classA, driverA)),
slices: objects(sliceWithOneDevice(slice1, node1, pool1, driverA)),
node: node(node1, region1),
expectResults: []any{
allocationResult(localNodeSelector(node1), deviceAllocationResult(req0, driverA, pool1, device1, false)),
},
},
"with-constraint": {
claimsToAllocate: objects(claimWithRequests(
claim0,
@ -960,8 +998,8 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req1, driverA, pool1, device2),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req1, driverA, pool1, device2, false),
)},
},
"with-constraint-non-existent-attribute": {
@ -1100,8 +1138,8 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req1, driverA, pool1, device2),
deviceAllocationResult(req0, driverA, pool1, device1, false),
deviceAllocationResult(req1, driverA, pool1, device2, false),
)},
},
"with-constraint-for-request-retry": {
@ -1141,8 +1179,8 @@ func TestAllocator(t *testing.T) {
expectResults: []any{allocationResult(
localNodeSelector(node1),
deviceAllocationResult(req0, driverA, pool1, device2),
deviceAllocationResult(req1, driverA, pool1, device3),
deviceAllocationResult(req0, driverA, pool1, device2, false),
deviceAllocationResult(req1, driverA, pool1, device3, false),
)},
},
"with-class-device-config": {
@ -1157,7 +1195,7 @@ func TestAllocator(t *testing.T) {
driverA,
resourceapi.AllocationConfigSourceClass,
"classAttribute",
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
),
},
},
@ -1173,7 +1211,7 @@ func TestAllocator(t *testing.T) {
driverA,
resourceapi.AllocationConfigSourceClaim,
"deviceAttribute",
deviceAllocationResult(req0, driverA, pool1, device1),
deviceAllocationResult(req0, driverA, pool1, device1, false),
),
},
},

View File

@ -47,6 +47,7 @@ import (
"k8s.io/client-go/kubernetes"
"k8s.io/klog/v2"
admissionapi "k8s.io/pod-security-admission/api"
"k8s.io/utils/ptr"
"k8s.io/kubernetes/test/e2e/feature"
"k8s.io/kubernetes/test/e2e/framework"
@ -673,10 +674,11 @@ func createTestObjects(ctx context.Context, clientSet kubernetes.Interface, node
config := make([]resourceapi.DeviceAllocationConfiguration, len(driverNames))
for i, driverName := range driverNames {
results[i] = resourceapi.DeviceRequestAllocationResult{
Driver: driverName,
Pool: "some-pool",
Device: "some-device",
Request: claim.Spec.Devices.Requests[0].Name,
Driver: driverName,
Pool: "some-pool",
Device: "some-device",
Request: claim.Spec.Devices.Requests[0].Name,
AdminAccess: ptr.To(false),
}
config[i] = resourceapi.DeviceAllocationConfiguration{
Source: resourceapi.AllocationConfigSourceClaim,