Skip to content

Commit dcc427d

Browse files
Merge pull request #136619 from pohly/dra-allocator-promotion
DRA allocator: promote experimental -> incubating -> stable Kubernetes-commit: a841d1142058555c2e55c591a22e8fa31cdea88e
2 parents 83ef310 + eb47921 commit dcc427d

File tree

13 files changed

+1495
-214
lines changed

13 files changed

+1495
-214
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ require (
1717
google.golang.org/grpc v1.78.0
1818
k8s.io/api v0.0.0-20260129214002-fd489ea10e70
1919
k8s.io/apimachinery v0.0.0-20260128173627-f88bdbffa260
20-
k8s.io/apiserver v0.0.0-20260130024220-0537f975530b
20+
k8s.io/apiserver v0.0.0-20260130180051-e4d99a6c5b80
2121
k8s.io/client-go v0.0.0-20260129214457-f651faf89451
2222
k8s.io/component-helpers v0.0.0-20260128015658-baa7b3dc5627
2323
k8s.io/klog/v2 v2.130.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ k8s.io/api v0.0.0-20260129214002-fd489ea10e70 h1:oKt9ikPa/z/jLAxSv4F+cwfa3WLiyQX
180180
k8s.io/api v0.0.0-20260129214002-fd489ea10e70/go.mod h1:kmox4M8MjlL/4SpMhp2HrQgan1jeduoD/KYtqzzYA30=
181181
k8s.io/apimachinery v0.0.0-20260128173627-f88bdbffa260 h1:/RfOFZrz3KFB9FDYG/qXiUkhXf9rHVvIjbewjKq6m6Q=
182182
k8s.io/apimachinery v0.0.0-20260128173627-f88bdbffa260/go.mod h1:jKPXtIDekKDF0eReuF8PvlfpbZPv+VYHZ3uWDh4REOE=
183-
k8s.io/apiserver v0.0.0-20260130024220-0537f975530b h1:/tGWp+tsLZprbyeE7UrixXIINnLcj9avgO72e/OcDwo=
184-
k8s.io/apiserver v0.0.0-20260130024220-0537f975530b/go.mod h1:G+93TtX7nRboAp1f+n8FGku0LP5WJUyrBAALgZ/I6lk=
183+
k8s.io/apiserver v0.0.0-20260130180051-e4d99a6c5b80 h1:pNP0g6XOHXUmyx2tNURp3DwLHmTWA/M8vGGY/ekZPnI=
184+
k8s.io/apiserver v0.0.0-20260130180051-e4d99a6c5b80/go.mod h1:G+93TtX7nRboAp1f+n8FGku0LP5WJUyrBAALgZ/I6lk=
185185
k8s.io/client-go v0.0.0-20260129214457-f651faf89451 h1:M1XQ6NX81PlMe8LhYh96Uptc6+V7vW/B5dtSi02OqLI=
186186
k8s.io/client-go v0.0.0-20260129214457-f651faf89451/go.mod h1:v9ovW0rkeX+D9rPqnc5xA98xG5xTNCtym7uoYRvw+J8=
187187
k8s.io/component-base v0.0.0-20260128015519-0f92b4617f0b h1:h73rHltEG5YdcAzF3cKKgqA8nljmqcUqd+Ea6Jlyvnw=

structured/allocator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ var availableAllocators = []struct {
227227
slices []*resourceapi.ResourceSlice,
228228
celCache *cel.Cache,
229229
) (Allocator, error) {
230-
return incubating.NewAllocator(ctx, features, allocatedState.AllocatedDevices, classLister, slices, celCache)
230+
return incubating.NewAllocator(ctx, features, allocatedState, classLister, slices, celCache)
231231
},
232232
nodeMatches: incubating.NodeMatches,
233233
},

structured/internal/allocatortesting/allocator_testing.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ type DeviceClassLister = internal.DeviceClassLister
5050
type Features = internal.Features
5151
type DeviceID = internal.DeviceID
5252

53-
// types_experimental
5453
type SharedDeviceID = internal.SharedDeviceID
5554
type ConsumedCapacityCollection = internal.ConsumedCapacityCollection
5655
type ConsumedCapacity = internal.ConsumedCapacity

structured/internal/experimental/allocator_experimental.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ func MakeDeviceID(driver, pool, device string) DeviceID {
4848
return internal.MakeDeviceID(driver, pool, device)
4949
}
5050

51-
// types_experimental
5251
type SharedDeviceID = internal.SharedDeviceID
5352
type DeviceConsumedCapacity = internal.DeviceConsumedCapacity
5453
type ConsumedCapacityCollection = internal.ConsumedCapacityCollection

structured/internal/incubating/allocator_incubating.go

Lines changed: 308 additions & 53 deletions
Large diffs are not rendered by default.

structured/internal/incubating/allocator_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ func TestAllocator(t *testing.T) {
3232
func(
3333
ctx context.Context,
3434
features Features,
35-
allocatedState internal.AllocatedState,
35+
allocatedState AllocatedState,
3636
classLister DeviceClassLister,
3737
slices []*resourceapi.ResourceSlice,
3838
celCache *cel.Cache,
3939
) (internal.Allocator, error) {
40-
return NewAllocator(ctx, features, allocatedState.AllocatedDevices, classLister, slices, celCache)
40+
return NewAllocator(ctx, features, allocatedState, classLister, slices, celCache)
4141
},
4242
)
4343
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package incubating
18+
19+
import (
20+
"fmt"
21+
22+
resourceapi "k8s.io/api/resource/v1"
23+
"k8s.io/apimachinery/pkg/util/sets"
24+
draapi "k8s.io/dynamic-resource-allocation/api"
25+
"k8s.io/klog/v2"
26+
)
27+
28+
// distinctAttributeConstraint compares an attribute value across devices.
29+
// All devices must share the same value. When the set of devices is
30+
// empty, any device that has the attribute can be added. After that,
31+
// only matching devices can be added.
32+
//
33+
// We don't need to track *which* devices are part of the set, only
34+
// how many.
35+
type distinctAttributeConstraint struct {
36+
logger klog.Logger // Includes name and attribute name, so no need to repeat in log messages.
37+
requestNames sets.Set[string]
38+
attributeName resourceapi.FullyQualifiedName
39+
40+
attributes map[string]resourceapi.DeviceAttribute
41+
numDevices int
42+
}
43+
44+
func (m *distinctAttributeConstraint) add(requestName, subRequestName string, device *draapi.Device, deviceID DeviceID) bool {
45+
if m.requestNames.Len() > 0 && !m.matches(requestName, subRequestName) {
46+
// Device not affected by constraint.
47+
return true
48+
}
49+
50+
attribute := lookupAttribute(device, deviceID, m.attributeName)
51+
if attribute == nil {
52+
// Doesn't have the attribute.
53+
m.logger.V(7).Info("Constraint not satisfied, attribute not set")
54+
return false
55+
}
56+
57+
if m.numDevices == 0 {
58+
// The first device can always get picked.
59+
m.attributes[requestName] = *attribute
60+
m.numDevices = 1
61+
m.logger.V(7).Info("First attribute added")
62+
return true
63+
}
64+
65+
if !m.matchesAttribute(*attribute) {
66+
m.logger.V(7).Info("Constraint not satisfied, has some duplicated attributes")
67+
return false
68+
}
69+
m.attributes[requestName] = *attribute
70+
m.numDevices++
71+
m.logger.V(7).Info("Constraint satisfied by device", "device", deviceID, "numDevices", m.numDevices)
72+
return true
73+
74+
}
75+
76+
func (m *distinctAttributeConstraint) remove(requestName, subRequestName string, device *draapi.Device, deviceID DeviceID) {
77+
if m.requestNames.Len() > 0 && !m.matches(requestName, subRequestName) {
78+
// Device not affected by constraint.
79+
return
80+
}
81+
delete(m.attributes, requestName)
82+
m.numDevices--
83+
m.logger.V(7).Info("Device removed from constraint set", "device", deviceID, "numDevices", m.numDevices)
84+
}
85+
86+
func (m *distinctAttributeConstraint) matches(requestName, subRequestName string) bool {
87+
if subRequestName == "" {
88+
return m.requestNames.Has(requestName)
89+
} else {
90+
fullSubRequestName := fmt.Sprintf("%s/%s", requestName, subRequestName)
91+
return m.requestNames.Has(requestName) || m.requestNames.Has(fullSubRequestName)
92+
}
93+
}
94+
95+
func (m *distinctAttributeConstraint) matchesAttribute(attribute resourceapi.DeviceAttribute) bool {
96+
for _, attr := range m.attributes {
97+
switch {
98+
case attribute.StringValue != nil:
99+
if attr.StringValue != nil && *attribute.StringValue == *attr.StringValue {
100+
m.logger.V(7).Info("String values duplicated")
101+
return false
102+
}
103+
case attribute.IntValue != nil:
104+
if attr.IntValue != nil && *attribute.IntValue == *attr.IntValue {
105+
m.logger.V(7).Info("Int values duplicated")
106+
return false
107+
}
108+
case attribute.BoolValue != nil:
109+
if attr.BoolValue != nil && *attribute.BoolValue == *attr.BoolValue {
110+
m.logger.V(7).Info("Bool values duplicated")
111+
return false
112+
}
113+
case attribute.VersionValue != nil:
114+
// semver 2.0.0 requires that version strings are in their
115+
// minimal form (in particular, no leading zeros). Therefore a
116+
// strict "exact equal" check can do a string comparison.
117+
if attr.VersionValue != nil && *attribute.VersionValue == *attr.VersionValue {
118+
m.logger.V(7).Info("Version values duplicated")
119+
return false
120+
}
121+
default:
122+
// Unknown value type, cannot match.
123+
// This condition should not be reached
124+
// as the unknown value type should be failed on CEL compile (getAttributeValue).
125+
m.logger.V(7).Info("Distinct attribute type unknown")
126+
return false
127+
}
128+
}
129+
// All distinct
130+
return true
131+
}

0 commit comments

Comments
 (0)