Merge pull request #103072 from ikeeip/scheduler_volumebinding

Remove "pkg/controller/volume/scheduling" dependency from "pkg/scheduler/framework/plugins"
This commit is contained in:
Kubernetes Prow Robot 2021-08-13 08:20:22 -07:00 committed by GitHub
commit b6d83f0ba3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 573 additions and 474 deletions

View File

@ -1,9 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- msau42
- cofyc
reviewers:
- msau42
- cofyc
- lichuqiang

View File

@ -1,6 +1,11 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- sig-storage-approvers
- cofyc
reviewers:
- sig-storage-reviewers
- cofyc
- lichuqiang
labels:
- sig/storage

View File

@ -14,11 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package scheduling
package volumebinding
import (
"fmt"
storagehelpers "k8s.io/component-helpers/storage/volume"
"strconv"
"sync"
@ -27,6 +26,7 @@ import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/client-go/tools/cache"
storagehelpers "k8s.io/component-helpers/storage/volume"
)
// AssumeCache is a cache on top of the informer that allows for updating

View File

@ -14,29 +14,17 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package scheduling
package volumebinding
import (
"fmt"
"testing"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
)
func makePV(name, version, storageClass string) *v1.PersistentVolume {
return &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: name,
ResourceVersion: version,
},
Spec: v1.PersistentVolumeSpec{
StorageClassName: storageClass,
},
}
}
func verifyListPVs(t *testing.T, cache PVAssumeCache, expectedPVs map[string]*v1.PersistentVolume, storageClassName string) {
pvList := cache.ListPVs(storageClassName)
if len(pvList) != len(expectedPVs) {
@ -71,38 +59,38 @@ func TestAssumePV(t *testing.T) {
shouldSucceed bool
}{
"success-same-version": {
oldPV: makePV("pv1", "5", ""),
newPV: makePV("pv1", "5", ""),
oldPV: makePV("pv1", "").withVersion("5").PersistentVolume,
newPV: makePV("pv1", "").withVersion("5").PersistentVolume,
shouldSucceed: true,
},
"success-storageclass-same-version": {
oldPV: makePV("pv1", "5", "class1"),
newPV: makePV("pv1", "5", "class1"),
oldPV: makePV("pv1", "class1").withVersion("5").PersistentVolume,
newPV: makePV("pv1", "class1").withVersion("5").PersistentVolume,
shouldSucceed: true,
},
"success-new-higher-version": {
oldPV: makePV("pv1", "5", ""),
newPV: makePV("pv1", "6", ""),
oldPV: makePV("pv1", "").withVersion("5").PersistentVolume,
newPV: makePV("pv1", "").withVersion("6").PersistentVolume,
shouldSucceed: true,
},
"fail-old-not-found": {
oldPV: makePV("pv2", "5", ""),
newPV: makePV("pv1", "5", ""),
oldPV: makePV("pv2", "").withVersion("5").PersistentVolume,
newPV: makePV("pv1", "").withVersion("5").PersistentVolume,
shouldSucceed: false,
},
"fail-new-lower-version": {
oldPV: makePV("pv1", "5", ""),
newPV: makePV("pv1", "4", ""),
oldPV: makePV("pv1", "").withVersion("5").PersistentVolume,
newPV: makePV("pv1", "").withVersion("4").PersistentVolume,
shouldSucceed: false,
},
"fail-new-bad-version": {
oldPV: makePV("pv1", "5", ""),
newPV: makePV("pv1", "a", ""),
oldPV: makePV("pv1", "").withVersion("5").PersistentVolume,
newPV: makePV("pv1", "").withVersion("a").PersistentVolume,
shouldSucceed: false,
},
"fail-old-bad-version": {
oldPV: makePV("pv1", "a", ""),
newPV: makePV("pv1", "5", ""),
oldPV: makePV("pv1", "").withVersion("a").PersistentVolume,
newPV: makePV("pv1", "").withVersion("5").PersistentVolume,
shouldSucceed: false,
},
}
@ -148,8 +136,8 @@ func TestRestorePV(t *testing.T) {
t.Fatalf("Failed to get internal cache")
}
oldPV := makePV("pv1", "5", "")
newPV := makePV("pv1", "5", "")
oldPV := makePV("pv1", "").withVersion("5").PersistentVolume
newPV := makePV("pv1", "").withVersion("5").PersistentVolume
// Restore PV that doesn't exist
cache.Restore("nothing")
@ -200,7 +188,7 @@ func TestBasicPVCache(t *testing.T) {
// Add a bunch of PVs
pvs := map[string]*v1.PersistentVolume{}
for i := 0; i < 10; i++ {
pv := makePV(fmt.Sprintf("test-pv%v", i), "1", "")
pv := makePV(fmt.Sprintf("test-pv%v", i), "").withVersion("1").PersistentVolume
pvs[pv.Name] = pv
internalCache.add(pv)
}
@ -209,7 +197,7 @@ func TestBasicPVCache(t *testing.T) {
verifyListPVs(t, cache, pvs, "")
// Update a PV
updatedPV := makePV("test-pv3", "2", "")
updatedPV := makePV("test-pv3", "").withVersion("2").PersistentVolume
pvs[updatedPV.Name] = updatedPV
internalCache.update(nil, updatedPV)
@ -235,7 +223,7 @@ func TestPVCacheWithStorageClasses(t *testing.T) {
// Add a bunch of PVs
pvs1 := map[string]*v1.PersistentVolume{}
for i := 0; i < 10; i++ {
pv := makePV(fmt.Sprintf("test-pv%v", i), "1", "class1")
pv := makePV(fmt.Sprintf("test-pv%v", i), "class1").withVersion("1").PersistentVolume
pvs1[pv.Name] = pv
internalCache.add(pv)
}
@ -243,7 +231,7 @@ func TestPVCacheWithStorageClasses(t *testing.T) {
// Add a bunch of PVs
pvs2 := map[string]*v1.PersistentVolume{}
for i := 0; i < 10; i++ {
pv := makePV(fmt.Sprintf("test2-pv%v", i), "1", "class2")
pv := makePV(fmt.Sprintf("test2-pv%v", i), "class2").withVersion("1").PersistentVolume
pvs2[pv.Name] = pv
internalCache.add(pv)
}
@ -253,7 +241,7 @@ func TestPVCacheWithStorageClasses(t *testing.T) {
verifyListPVs(t, cache, pvs2, "class2")
// Update a PV
updatedPV := makePV("test-pv3", "2", "class1")
updatedPV := makePV("test-pv3", "class1").withVersion("2").PersistentVolume
pvs1[updatedPV.Name] = updatedPV
internalCache.update(nil, updatedPV)
@ -281,7 +269,7 @@ func TestAssumeUpdatePVCache(t *testing.T) {
pvName := "test-pv0"
// Add a PV
pv := makePV(pvName, "1", "")
pv := makePV(pvName, "").withVersion("1").PersistentVolume
internalCache.add(pv)
if err := verifyPV(cache, pvName, pv); err != nil {
t.Fatalf("failed to get PV: %v", err)

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package scheduling
package volumebinding
import (
"context"
@ -46,8 +46,8 @@ import (
"k8s.io/klog/v2"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
"k8s.io/kubernetes/pkg/controller/volume/scheduling/metrics"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/metrics"
volumeutil "k8s.io/kubernetes/pkg/volume/util"
)

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package scheduling
package volumebinding
import (
"context"
@ -105,11 +105,11 @@ var (
topoMismatchClass = "topoMismatchClass"
// nodes objects
node1 = makeNode("node1", map[string]string{nodeLabelKey: "node1"})
node2 = makeNode("node2", map[string]string{nodeLabelKey: "node2"})
node1NoLabels = makeNode("node1", nil)
node1Zone1 = makeNode("node1", map[string]string{"topology.gke.io/zone": "us-east-1"})
node1Zone2 = makeNode("node1", map[string]string{"topology.gke.io/zone": "us-east-2"})
node1 = makeNode("node1").withLabel(nodeLabelKey, "node1").Node
node2 = makeNode("node2").withLabel(nodeLabelKey, "node2").Node
node1NoLabels = makeNode("node1").Node
node1Zone1 = makeNode("node1").withLabel("topology.gke.io/zone", "us-east-1").Node
node1Zone2 = makeNode("node1").withLabel("topology.gke.io/zone", "us-east-2").Node
// csiNode objects
csiNode1Migrated = makeCSINode("node1", "kubernetes.io/gce-pd")
@ -589,7 +589,11 @@ const (
)
func makeGenericEphemeralPVC(volumeName string, owned bool) *v1.PersistentVolumeClaim {
pod := makePodWithGenericEphemeral()
pod := makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withGenericEphemeralVolume("").Pod
pvc := makeTestPVC(pod.Name+"-"+volumeName, "1G", "", pvcBound, "pv-bound", "1", &immediateClass)
if owned {
controller := true
@ -712,15 +716,6 @@ func pvRemoveClaimUID(pv *v1.PersistentVolume) *v1.PersistentVolume {
return newPV
}
func makeNode(name string, labels map[string]string) *v1.Node {
return &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: labels,
},
}
}
func makeCSINode(name, migratedPlugin string) *storagev1.CSINode {
return &storagev1.CSINode{
ObjectMeta: metav1.ObjectMeta{
@ -765,63 +760,6 @@ func makeCapacity(name, storageClassName string, node *v1.Node, capacityStr, max
return c
}
func makePod(pvcs []*v1.PersistentVolumeClaim) *v1.Pod {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test-pod",
Namespace: "testns",
},
}
volumes := []v1.Volume{}
for i, pvc := range pvcs {
pvcVol := v1.Volume{
Name: fmt.Sprintf("vol%v", i),
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: pvc.Name,
},
},
}
volumes = append(volumes, pvcVol)
}
pod.Spec.Volumes = volumes
pod.Spec.NodeName = "node1"
return pod
}
func makePodWithoutPVC() *v1.Pod {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test-pod",
Namespace: "testns",
},
Spec: v1.PodSpec{
Volumes: []v1.Volume{
{
VolumeSource: v1.VolumeSource{
EmptyDir: &v1.EmptyDirVolumeSource{},
},
},
},
},
}
return pod
}
func makePodWithGenericEphemeral(volumeNames ...string) *v1.Pod {
pod := makePod(nil)
for _, volumeName := range volumeNames {
pod.Spec.Volumes = append(pod.Spec.Volumes, v1.Volume{
Name: volumeName,
VolumeSource: v1.VolumeSource{
Ephemeral: &v1.EphemeralVolumeSource{},
},
})
}
return pod
}
func makeBinding(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume) *BindingInfo {
return &BindingInfo{pvc: pvc.DeepCopy(), pv: pv.DeepCopy()}
}
@ -907,10 +845,15 @@ func TestFindPodVolumesWithoutProvisioning(t *testing.T) {
}
scenarios := map[string]scenarioType{
"no-volumes": {
pod: makePod(nil),
pod: makePod("test-pod").
withNamespace("testns").
withNodeName("node1").Pod,
},
"no-pvcs": {
pod: makePodWithoutPVC(),
pod: makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withEmptyDirVolume().Pod,
},
"pvc-not-found": {
cachePVCs: []*v1.PersistentVolumeClaim{},
@ -995,25 +938,37 @@ func TestFindPodVolumesWithoutProvisioning(t *testing.T) {
shouldFail: true,
},
"generic-ephemeral,no-pvc": {
pod: makePodWithGenericEphemeral("no-such-pvc"),
pod: makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withGenericEphemeralVolume("no-such-pvc").Pod,
ephemeral: true,
shouldFail: true,
},
"generic-ephemeral,with-pvc": {
pod: makePodWithGenericEphemeral("test-volume"),
pod: makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withGenericEphemeralVolume("test-volume").Pod,
cachePVCs: []*v1.PersistentVolumeClaim{correctGenericPVC},
pvs: []*v1.PersistentVolume{pvBoundGeneric},
ephemeral: true,
},
"generic-ephemeral,wrong-pvc": {
pod: makePodWithGenericEphemeral("test-volume"),
pod: makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withGenericEphemeralVolume("test-volume").Pod,
cachePVCs: []*v1.PersistentVolumeClaim{conflictingGenericPVC},
pvs: []*v1.PersistentVolume{pvBoundGeneric},
ephemeral: true,
shouldFail: true,
},
"generic-ephemeral,disabled": {
pod: makePodWithGenericEphemeral("test-volume"),
pod: makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withGenericEphemeralVolume("test-volume").Pod,
cachePVCs: []*v1.PersistentVolumeClaim{correctGenericPVC},
pvs: []*v1.PersistentVolume{pvBoundGeneric},
ephemeral: false,
@ -1051,7 +1006,10 @@ func TestFindPodVolumesWithoutProvisioning(t *testing.T) {
// b. Generate pod with given claims
if scenario.pod == nil {
scenario.pod = makePod(scenario.podPVCs)
scenario.pod = makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withPVCSVolume(scenario.podPVCs).Pod
}
// Execute
@ -1179,7 +1137,10 @@ func TestFindPodVolumesWithProvisioning(t *testing.T) {
// b. Generate pod with given claims
if scenario.pod == nil {
scenario.pod = makePod(scenario.podPVCs)
scenario.pod = makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withPVCSVolume(scenario.podPVCs).Pod
}
// Execute
@ -1299,7 +1260,10 @@ func TestFindPodVolumesWithCSIMigration(t *testing.T) {
// b. Generate pod with given claims
if scenario.pod == nil {
scenario.pod = makePod(scenario.podPVCs)
scenario.pod = makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withPVCSVolume(scenario.podPVCs).Pod
}
// Execute
@ -1392,7 +1356,10 @@ func TestAssumePodVolumes(t *testing.T) {
// Setup
testEnv := newTestBinder(t, ctx.Done())
testEnv.initClaims(scenario.podPVCs, scenario.podPVCs)
pod := makePod(scenario.podPVCs)
pod := makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withPVCSVolume(scenario.podPVCs).Pod
podVolumes := &PodVolumes{
StaticBindings: scenario.bindings,
DynamicProvisions: scenario.provisionedPVCs,
@ -1445,7 +1412,10 @@ func TestRevertAssumedPodVolumes(t *testing.T) {
// Setup
testEnv := newTestBinder(t, ctx.Done())
testEnv.initClaims(podPVCs, podPVCs)
pod := makePod(podPVCs)
pod := makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withPVCSVolume(podPVCs).Pod
podVolumes := &PodVolumes{
StaticBindings: bindings,
DynamicProvisions: provisionedPVCs,
@ -1562,7 +1532,9 @@ func TestBindAPIUpdate(t *testing.T) {
// Setup
testEnv := newTestBinder(t, ctx.Done())
pod := makePod(nil)
pod := makePod("test-pod").
withNamespace("testns").
withNodeName("node1").Pod
if scenario.apiPVs == nil {
scenario.apiPVs = scenario.cachedPVs
}
@ -1757,7 +1729,9 @@ func TestCheckBindings(t *testing.T) {
defer cancel()
// Setup
pod := makePod(nil)
pod := makePod("test-pod").
withNamespace("testns").
withNodeName("node1").Pod
testEnv := newTestBinder(t, ctx.Done())
testEnv.internalPodInformer.Informer().GetIndexer().Add(pod)
testEnv.initNodes([]*v1.Node{node1})
@ -1886,7 +1860,9 @@ func TestCheckBindingsWithCSIMigration(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CSIMigrationGCE, scenario.migrationEnabled)()
// Setup
pod := makePod(nil)
pod := makePod("test-pod").
withNamespace("testns").
withNodeName("node1").Pod
testEnv := newTestBinder(t, ctx.Done())
testEnv.internalPodInformer.Informer().GetIndexer().Add(pod)
testEnv.initNodes(scenario.initNodes)
@ -2070,7 +2046,9 @@ func TestBindPodVolumes(t *testing.T) {
defer cancel()
// Setup
pod := makePod(nil)
pod := makePod("test-pod").
withNamespace("testns").
withNodeName("node1").Pod
testEnv := newTestBinder(t, ctx.Done())
testEnv.internalPodInformer.Informer().GetIndexer().Add(pod)
if scenario.nodes == nil {
@ -2150,7 +2128,10 @@ func TestFindAssumeVolumes(t *testing.T) {
testEnv := newTestBinder(t, ctx.Done())
testEnv.initVolumes(pvs, pvs)
testEnv.initClaims(podPVCs, podPVCs)
pod := makePod(podPVCs)
pod := makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withPVCSVolume(podPVCs).Pod
testNode := &v1.Node{
ObjectMeta: metav1.ObjectMeta{
@ -2311,7 +2292,10 @@ func TestCapacity(t *testing.T) {
testEnv.initClaims(scenario.pvcs, scenario.pvcs)
// b. Generate pod with given claims
pod := makePod(scenario.pvcs)
pod := makePod("test-pod").
withNamespace("testns").
withNodeName("node1").
withPVCSVolume(scenario.pvcs).Pod
// Execute
podVolumes, reasons, err := findPodVolumes(testEnv.binder, pod, testNode)

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package scheduling
package volumebinding
import v1 "k8s.io/api/core/v1"

View File

@ -19,12 +19,11 @@ package volumebinding
import (
"math"
"k8s.io/kubernetes/pkg/controller/volume/scheduling"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper"
)
// classResourceMap holds a map of storage class to resource.
type classResourceMap map[string]*scheduling.StorageResource
type classResourceMap map[string]*StorageResource
// volumeCapacityScorer calculates the score based on class storage resource information.
type volumeCapacityScorer func(classResourceMap) int64

View File

@ -19,7 +19,6 @@ package volumebinding
import (
"testing"
"k8s.io/kubernetes/pkg/controller/volume/scheduling"
"k8s.io/kubernetes/pkg/scheduler/apis/config"
"k8s.io/kubernetes/pkg/scheduler/framework"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper"
@ -53,7 +52,7 @@ func TestScore(t *testing.T) {
cases: []scoreCase{
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 0,
Capacity: 100,
},
@ -62,7 +61,7 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 30,
Capacity: 100,
},
@ -71,7 +70,7 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 50,
Capacity: 100,
},
@ -80,7 +79,7 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 100,
Capacity: 100,
},
@ -95,11 +94,11 @@ func TestScore(t *testing.T) {
cases: []scoreCase{
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 0,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 0,
Capacity: 100,
},
@ -108,11 +107,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 0,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 30,
Capacity: 100,
},
@ -121,11 +120,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 30,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 30,
Capacity: 100,
},
@ -134,11 +133,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 30,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 60,
Capacity: 100,
},
@ -147,11 +146,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 50,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 50,
Capacity: 100,
},
@ -160,11 +159,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 50,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 100,
Capacity: 100,
},
@ -173,11 +172,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 100,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 100,
Capacity: 100,
},
@ -205,11 +204,11 @@ func TestScore(t *testing.T) {
cases: []scoreCase{
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 0,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 0,
Capacity: 100,
},
@ -218,11 +217,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 0,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 30,
Capacity: 100,
},
@ -231,11 +230,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 30,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 30,
Capacity: 100,
},
@ -244,11 +243,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 30,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 60,
Capacity: 100,
},
@ -257,11 +256,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 50,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 100,
Capacity: 100,
},
@ -270,11 +269,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 90,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 90,
Capacity: 100,
},
@ -283,11 +282,11 @@ func TestScore(t *testing.T) {
},
{
classResourceMap{
classHDD: &scheduling.StorageResource{
classHDD: &StorageResource{
Requested: 100,
Capacity: 100,
},
classSSD: &scheduling.StorageResource{
classSSD: &StorageResource{
Requested: 100,
Capacity: 100,
},

View File

@ -0,0 +1,199 @@
/*
Copyright 2021 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 volumebinding
import (
"fmt"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
"k8s.io/utils/pointer"
)
type nodeBuilder struct {
*v1.Node
}
func makeNode(name string) nodeBuilder {
return nodeBuilder{Node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: map[string]string{
v1.LabelHostname: name,
},
},
}}
}
func (nb nodeBuilder) withLabel(key, value string) nodeBuilder {
if nb.Node.ObjectMeta.Labels == nil {
nb.Node.ObjectMeta.Labels = map[string]string{}
}
nb.Node.ObjectMeta.Labels[key] = value
return nb
}
type pvBuilder struct {
*v1.PersistentVolume
}
func makePV(name, className string) pvBuilder {
return pvBuilder{PersistentVolume: &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1.PersistentVolumeSpec{
StorageClassName: className,
},
}}
}
func (pvb pvBuilder) withNodeAffinity(keyValues map[string][]string) pvBuilder {
matchExpressions := make([]v1.NodeSelectorRequirement, 0)
for key, values := range keyValues {
matchExpressions = append(matchExpressions, v1.NodeSelectorRequirement{
Key: key,
Operator: v1.NodeSelectorOpIn,
Values: values,
})
}
pvb.PersistentVolume.Spec.NodeAffinity = &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: matchExpressions,
},
},
},
}
return pvb
}
func (pvb pvBuilder) withVersion(version string) pvBuilder {
pvb.PersistentVolume.ObjectMeta.ResourceVersion = version
return pvb
}
func (pvb pvBuilder) withCapacity(capacity resource.Quantity) pvBuilder {
pvb.PersistentVolume.Spec.Capacity = v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): capacity,
}
return pvb
}
func (pvb pvBuilder) withPhase(phase v1.PersistentVolumePhase) pvBuilder {
pvb.PersistentVolume.Status = v1.PersistentVolumeStatus{
Phase: phase,
}
return pvb
}
type pvcBuilder struct {
*v1.PersistentVolumeClaim
}
func makePVC(name string, storageClassName string) pvcBuilder {
return pvcBuilder{PersistentVolumeClaim: &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: v1.NamespaceDefault,
},
Spec: v1.PersistentVolumeClaimSpec{
StorageClassName: pointer.StringPtr(storageClassName),
},
}}
}
func (pvcb pvcBuilder) withBoundPV(pvName string) pvcBuilder {
pvcb.PersistentVolumeClaim.Spec.VolumeName = pvName
metav1.SetMetaDataAnnotation(&pvcb.PersistentVolumeClaim.ObjectMeta, pvutil.AnnBindCompleted, "true")
return pvcb
}
func (pvcb pvcBuilder) withRequestStorage(request resource.Quantity) pvcBuilder {
pvcb.PersistentVolumeClaim.Spec.Resources = v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): request,
},
}
return pvcb
}
type podBuilder struct {
*v1.Pod
}
func makePod(name string) podBuilder {
pb := podBuilder{Pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: v1.NamespaceDefault,
},
}}
pb.Pod.Spec.Volumes = make([]v1.Volume, 0)
return pb
}
func (pb podBuilder) withNodeName(name string) podBuilder {
pb.Pod.Spec.NodeName = name
return pb
}
func (pb podBuilder) withNamespace(name string) podBuilder {
pb.Pod.ObjectMeta.Namespace = name
return pb
}
func (pb podBuilder) withPVCVolume(pvcName, name string) podBuilder {
pb.Pod.Spec.Volumes = append(pb.Pod.Spec.Volumes, v1.Volume{
Name: name,
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: pvcName,
},
},
})
return pb
}
func (pb podBuilder) withPVCSVolume(pvcs []*v1.PersistentVolumeClaim) podBuilder {
for i, pvc := range pvcs {
pb.withPVCVolume(pvc.Name, fmt.Sprintf("vol%v", i))
}
return pb
}
func (pb podBuilder) withEmptyDirVolume() podBuilder {
pb.Pod.Spec.Volumes = append(pb.Pod.Spec.Volumes, v1.Volume{
VolumeSource: v1.VolumeSource{
EmptyDir: &v1.EmptyDirVolumeSource{},
},
})
return pb
}
func (pb podBuilder) withGenericEphemeralVolume(name string) podBuilder {
pb.Pod.Spec.Volumes = append(pb.Pod.Spec.Volumes, v1.Volume{
Name: name,
VolumeSource: v1.VolumeSource{
Ephemeral: &v1.EphemeralVolumeSource{},
},
})
return pb
}

View File

@ -29,7 +29,6 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature"
corelisters "k8s.io/client-go/listers/core/v1"
"k8s.io/klog/v2"
"k8s.io/kubernetes/pkg/controller/volume/scheduling"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/scheduler/apis/config"
"k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
@ -58,7 +57,7 @@ type stateData struct {
// podVolumesByNode holds the pod's volume information found in the Filter
// phase for each node
// it's initialized in the PreFilter phase
podVolumesByNode map[string]*scheduling.PodVolumes
podVolumesByNode map[string]*PodVolumes
sync.Mutex
}
@ -70,7 +69,7 @@ func (d *stateData) Clone() framework.StateData {
// In the Filter phase, pod binding cache is created for the pod and used in
// Reserve and PreBind phases.
type VolumeBinding struct {
Binder scheduling.SchedulerVolumeBinder
Binder SchedulerVolumeBinder
PVCLister corelisters.PersistentVolumeClaimLister
GenericEphemeralVolumeFeatureEnabled bool
scorer volumeCapacityScorer
@ -179,7 +178,7 @@ func (pl *VolumeBinding) PreFilter(ctx context.Context, state *framework.CycleSt
status.AppendReason("pod has unbound immediate PersistentVolumeClaims")
return status
}
state.Write(stateKey, &stateData{boundClaims: boundClaims, claimsToBind: claimsToBind, podVolumesByNode: make(map[string]*scheduling.PodVolumes)})
state.Write(stateKey, &stateData{boundClaims: boundClaims, claimsToBind: claimsToBind, podVolumesByNode: make(map[string]*PodVolumes)})
return nil
}
@ -270,7 +269,7 @@ func (pl *VolumeBinding) Score(ctx context.Context, cs *framework.CycleState, po
class := staticBinding.StorageClassName()
storageResource := staticBinding.StorageResource()
if _, ok := classResources[class]; !ok {
classResources[class] = &scheduling.StorageResource{
classResources[class] = &StorageResource{
Requested: 0,
Capacity: 0,
}
@ -367,14 +366,14 @@ func New(plArgs runtime.Object, fh framework.Handle) (framework.Plugin, error) {
pvInformer := fh.SharedInformerFactory().Core().V1().PersistentVolumes()
storageClassInformer := fh.SharedInformerFactory().Storage().V1().StorageClasses()
csiNodeInformer := fh.SharedInformerFactory().Storage().V1().CSINodes()
var capacityCheck *scheduling.CapacityCheck
var capacityCheck *CapacityCheck
if utilfeature.DefaultFeatureGate.Enabled(features.CSIStorageCapacity) {
capacityCheck = &scheduling.CapacityCheck{
capacityCheck = &CapacityCheck{
CSIDriverInformer: fh.SharedInformerFactory().Storage().V1().CSIDrivers(),
CSIStorageCapacityInformer: fh.SharedInformerFactory().Storage().V1beta1().CSIStorageCapacities(),
}
}
binder := scheduling.NewVolumeBinder(fh.ClientSet(), podInformer, nodeInformer, csiNodeInformer, pvcInformer, pvInformer, storageClassInformer, capacityCheck, time.Duration(args.BindTimeoutSeconds)*time.Second)
binder := NewVolumeBinder(fh.ClientSet(), podInformer, nodeInformer, csiNodeInformer, pvcInformer, pvInformer, storageClassInformer, capacityCheck, time.Duration(args.BindTimeoutSeconds)*time.Second)
// build score function
var scorer volumeCapacityScorer

View File

@ -32,13 +32,10 @@ import (
"k8s.io/client-go/kubernetes/fake"
"k8s.io/component-base/featuregate"
featuregatetesting "k8s.io/component-base/featuregate/testing"
pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
"k8s.io/kubernetes/pkg/controller/volume/scheduling"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/scheduler/apis/config"
"k8s.io/kubernetes/pkg/scheduler/framework"
"k8s.io/kubernetes/pkg/scheduler/framework/runtime"
"k8s.io/utils/pointer"
)
var (
@ -75,112 +72,6 @@ var (
}
)
func makeNode(name string) *v1.Node {
return &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: map[string]string{
v1.LabelHostname: name,
},
},
}
}
func mergeNodeLabels(node *v1.Node, labels map[string]string) *v1.Node {
for k, v := range labels {
node.Labels[k] = v
}
return node
}
func makePV(name string, className string) *v1.PersistentVolume {
return &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1.PersistentVolumeSpec{
StorageClassName: className,
},
Status: v1.PersistentVolumeStatus{
Phase: v1.VolumeAvailable,
},
}
}
func setPVNodeAffinity(pv *v1.PersistentVolume, keyValues map[string][]string) *v1.PersistentVolume {
matchExpressions := make([]v1.NodeSelectorRequirement, 0)
for key, values := range keyValues {
matchExpressions = append(matchExpressions, v1.NodeSelectorRequirement{
Key: key,
Operator: v1.NodeSelectorOpIn,
Values: values,
})
}
pv.Spec.NodeAffinity = &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: matchExpressions,
},
},
},
}
return pv
}
func setPVCapacity(pv *v1.PersistentVolume, capacity resource.Quantity) *v1.PersistentVolume {
pv.Spec.Capacity = v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): capacity,
}
return pv
}
func makePVC(name string, boundPVName string, storageClassName string) *v1.PersistentVolumeClaim {
pvc := &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: v1.NamespaceDefault,
},
Spec: v1.PersistentVolumeClaimSpec{
StorageClassName: pointer.StringPtr(storageClassName),
},
}
if boundPVName != "" {
pvc.Spec.VolumeName = boundPVName
metav1.SetMetaDataAnnotation(&pvc.ObjectMeta, pvutil.AnnBindCompleted, "true")
}
return pvc
}
func setPVCRequestStorage(pvc *v1.PersistentVolumeClaim, request resource.Quantity) *v1.PersistentVolumeClaim {
pvc.Spec.Resources = v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): request,
},
}
return pvc
}
func makePod(name string, pvcNames []string) *v1.Pod {
p := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: v1.NamespaceDefault,
},
}
p.Spec.Volumes = make([]v1.Volume, 0)
for _, pvcName := range pvcNames {
p.Spec.Volumes = append(p.Spec.Volumes, v1.Volume{
VolumeSource: v1.VolumeSource{
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{
ClaimName: pvcName,
},
},
})
}
return p
}
func TestVolumeBinding(t *testing.T) {
table := []struct {
name string
@ -197,9 +88,9 @@ func TestVolumeBinding(t *testing.T) {
}{
{
name: "pod has not pvcs",
pod: makePod("pod-a", nil),
pod: makePod("pod-a").Pod,
nodes: []*v1.Node{
makeNode("node-a"),
makeNode("node-a").Node,
},
wantStateAfterPreFilter: &stateData{
skip: true,
@ -213,22 +104,22 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "all bound",
pod: makePod("pod-a", []string{"pvc-a"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").Pod,
nodes: []*v1.Node{
makeNode("node-a"),
makeNode("node-a").Node,
},
pvcs: []*v1.PersistentVolumeClaim{
makePVC("pvc-a", "pv-a", waitSC.Name),
makePVC("pvc-a", waitSC.Name).withBoundPV("pv-a").PersistentVolumeClaim,
},
pvs: []*v1.PersistentVolume{
makePV("pv-a", waitSC.Name),
makePV("pv-a", waitSC.Name).withPhase(v1.VolumeAvailable).PersistentVolume,
},
wantStateAfterPreFilter: &stateData{
boundClaims: []*v1.PersistentVolumeClaim{
makePVC("pvc-a", "pv-a", waitSC.Name),
makePVC("pvc-a", waitSC.Name).withBoundPV("pv-a").PersistentVolumeClaim,
},
claimsToBind: []*v1.PersistentVolumeClaim{},
podVolumesByNode: map[string]*scheduling.PodVolumes{},
podVolumesByNode: map[string]*PodVolumes{},
},
wantFilterStatus: []*framework.Status{
nil,
@ -239,9 +130,9 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "PVC does not exist",
pod: makePod("pod-a", []string{"pvc-a"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").Pod,
nodes: []*v1.Node{
makeNode("node-a"),
makeNode("node-a").Node,
},
pvcs: []*v1.PersistentVolumeClaim{},
wantPreFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, `persistentvolumeclaim "pvc-a" not found`),
@ -254,12 +145,12 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "Part of PVCs do not exist",
pod: makePod("pod-a", []string{"pvc-a", "pvc-b"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").withPVCVolume("pvc-b", "").Pod,
nodes: []*v1.Node{
makeNode("node-a"),
makeNode("node-a").Node,
},
pvcs: []*v1.PersistentVolumeClaim{
makePVC("pvc-a", "pv-a", waitSC.Name),
makePVC("pvc-a", waitSC.Name).withBoundPV("pv-a").PersistentVolumeClaim,
},
wantPreFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, `persistentvolumeclaim "pvc-b" not found`),
wantFilterStatus: []*framework.Status{
@ -271,12 +162,12 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "immediate claims not bound",
pod: makePod("pod-a", []string{"pvc-a"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").Pod,
nodes: []*v1.Node{
makeNode("node-a"),
makeNode("node-a").Node,
},
pvcs: []*v1.PersistentVolumeClaim{
makePVC("pvc-a", "", immediateSC.Name),
makePVC("pvc-a", immediateSC.Name).PersistentVolumeClaim,
},
wantPreFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, "pod has unbound immediate PersistentVolumeClaims"),
wantFilterStatus: []*framework.Status{
@ -288,22 +179,22 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "unbound claims no matches",
pod: makePod("pod-a", []string{"pvc-a"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").Pod,
nodes: []*v1.Node{
makeNode("node-a"),
makeNode("node-a").Node,
},
pvcs: []*v1.PersistentVolumeClaim{
makePVC("pvc-a", "", waitSC.Name),
makePVC("pvc-a", waitSC.Name).PersistentVolumeClaim,
},
wantStateAfterPreFilter: &stateData{
boundClaims: []*v1.PersistentVolumeClaim{},
claimsToBind: []*v1.PersistentVolumeClaim{
makePVC("pvc-a", "", waitSC.Name),
makePVC("pvc-a", waitSC.Name).PersistentVolumeClaim,
},
podVolumesByNode: map[string]*scheduling.PodVolumes{},
podVolumesByNode: map[string]*PodVolumes{},
},
wantFilterStatus: []*framework.Status{
framework.NewStatus(framework.UnschedulableAndUnresolvable, string(scheduling.ErrReasonBindConflict)),
framework.NewStatus(framework.UnschedulableAndUnresolvable, string(ErrReasonBindConflict)),
},
wantScores: []int64{
0,
@ -311,32 +202,30 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "bound and unbound unsatisfied",
pod: makePod("pod-a", []string{"pvc-a", "pvc-b"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").withPVCVolume("pvc-b", "").Pod,
nodes: []*v1.Node{
mergeNodeLabels(makeNode("node-a"), map[string]string{
"foo": "barbar",
}),
makeNode("node-a").withLabel("foo", "barbar").Node,
},
pvcs: []*v1.PersistentVolumeClaim{
makePVC("pvc-a", "pv-a", waitSC.Name),
makePVC("pvc-b", "", waitSC.Name),
makePVC("pvc-a", waitSC.Name).withBoundPV("pv-a").PersistentVolumeClaim,
makePVC("pvc-b", waitSC.Name).PersistentVolumeClaim,
},
pvs: []*v1.PersistentVolume{
setPVNodeAffinity(makePV("pv-a", waitSC.Name), map[string][]string{
"foo": {"bar"},
}),
makePV("pv-a", waitSC.Name).
withPhase(v1.VolumeAvailable).
withNodeAffinity(map[string][]string{"foo": {"bar"}}).PersistentVolume,
},
wantStateAfterPreFilter: &stateData{
boundClaims: []*v1.PersistentVolumeClaim{
makePVC("pvc-a", "pv-a", waitSC.Name),
makePVC("pvc-a", waitSC.Name).withBoundPV("pv-a").PersistentVolumeClaim,
},
claimsToBind: []*v1.PersistentVolumeClaim{
makePVC("pvc-b", "", waitSC.Name),
makePVC("pvc-b", waitSC.Name).PersistentVolumeClaim,
},
podVolumesByNode: map[string]*scheduling.PodVolumes{},
podVolumesByNode: map[string]*PodVolumes{},
},
wantFilterStatus: []*framework.Status{
framework.NewStatus(framework.UnschedulableAndUnresolvable, string(scheduling.ErrReasonNodeConflict), string(scheduling.ErrReasonBindConflict)),
framework.NewStatus(framework.UnschedulableAndUnresolvable, string(ErrReasonNodeConflict), string(ErrReasonBindConflict)),
},
wantScores: []int64{
0,
@ -344,9 +233,9 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "pvc not found",
pod: makePod("pod-a", []string{"pvc-a"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").Pod,
nodes: []*v1.Node{
makeNode("node-a"),
makeNode("node-a").Node,
},
wantPreFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, `persistentvolumeclaim "pvc-a" not found`),
wantFilterStatus: []*framework.Status{
@ -358,20 +247,20 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "pv not found",
pod: makePod("pod-a", []string{"pvc-a"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").Pod,
nodes: []*v1.Node{
makeNode("node-a"),
makeNode("node-a").Node,
},
pvcs: []*v1.PersistentVolumeClaim{
makePVC("pvc-a", "pv-a", waitSC.Name),
makePVC("pvc-a", waitSC.Name).withBoundPV("pv-a").PersistentVolumeClaim,
},
wantPreFilterStatus: nil,
wantStateAfterPreFilter: &stateData{
boundClaims: []*v1.PersistentVolumeClaim{
makePVC("pvc-a", "pv-a", waitSC.Name),
makePVC("pvc-a", waitSC.Name).withBoundPV("pv-a").PersistentVolumeClaim,
},
claimsToBind: []*v1.PersistentVolumeClaim{},
podVolumesByNode: map[string]*scheduling.PodVolumes{},
podVolumesByNode: map[string]*PodVolumes{},
},
wantFilterStatus: []*framework.Status{
framework.NewStatus(framework.UnschedulableAndUnresolvable, `pvc(s) bound to non-existent pv(s)`),
@ -382,29 +271,41 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "local volumes with close capacity are preferred",
pod: makePod("pod-a", []string{"pvc-a"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").Pod,
nodes: []*v1.Node{
makeNode("node-a"),
makeNode("node-b"),
makeNode("node-c"),
makeNode("node-a").Node,
makeNode("node-b").Node,
makeNode("node-c").Node,
},
pvcs: []*v1.PersistentVolumeClaim{
setPVCRequestStorage(makePVC("pvc-a", "", waitSC.Name), resource.MustParse("50Gi")),
makePVC("pvc-a", waitSC.Name).withRequestStorage(resource.MustParse("50Gi")).PersistentVolumeClaim,
},
pvs: []*v1.PersistentVolume{
setPVNodeAffinity(setPVCapacity(makePV("pv-a-0", waitSC.Name), resource.MustParse("200Gi")), map[string][]string{v1.LabelHostname: {"node-a"}}),
setPVNodeAffinity(setPVCapacity(makePV("pv-a-1", waitSC.Name), resource.MustParse("200Gi")), map[string][]string{v1.LabelHostname: {"node-a"}}),
setPVNodeAffinity(setPVCapacity(makePV("pv-b-0", waitSC.Name), resource.MustParse("100Gi")), map[string][]string{v1.LabelHostname: {"node-b"}}),
setPVNodeAffinity(setPVCapacity(makePV("pv-b-1", waitSC.Name), resource.MustParse("100Gi")), map[string][]string{v1.LabelHostname: {"node-b"}}),
makePV("pv-a-0", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("200Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-a"}}).PersistentVolume,
makePV("pv-a-1", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("200Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-a"}}).PersistentVolume,
makePV("pv-b-0", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("100Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-b"}}).PersistentVolume,
makePV("pv-b-1", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("100Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-b"}}).PersistentVolume,
},
feature: features.VolumeCapacityPriority,
wantPreFilterStatus: nil,
wantStateAfterPreFilter: &stateData{
boundClaims: []*v1.PersistentVolumeClaim{},
claimsToBind: []*v1.PersistentVolumeClaim{
setPVCRequestStorage(makePVC("pvc-a", "", waitSC.Name), resource.MustParse("50Gi")),
makePVC("pvc-a", waitSC.Name).withRequestStorage(resource.MustParse("50Gi")).PersistentVolumeClaim,
},
podVolumesByNode: map[string]*scheduling.PodVolumes{},
podVolumesByNode: map[string]*PodVolumes{},
},
wantFilterStatus: []*framework.Status{
nil,
@ -419,35 +320,59 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "local volumes with close capacity are preferred (multiple pvcs)",
pod: makePod("pod-a", []string{"pvc-0", "pvc-1"}),
pod: makePod("pod-a").withPVCVolume("pvc-0", "").withPVCVolume("pvc-1", "").Pod,
nodes: []*v1.Node{
makeNode("node-a"),
makeNode("node-b"),
makeNode("node-c"),
makeNode("node-a").Node,
makeNode("node-b").Node,
makeNode("node-c").Node,
},
pvcs: []*v1.PersistentVolumeClaim{
setPVCRequestStorage(makePVC("pvc-0", "", waitSC.Name), resource.MustParse("50Gi")),
setPVCRequestStorage(makePVC("pvc-1", "", waitHDDSC.Name), resource.MustParse("100Gi")),
makePVC("pvc-0", waitSC.Name).withRequestStorage(resource.MustParse("50Gi")).PersistentVolumeClaim,
makePVC("pvc-1", waitHDDSC.Name).withRequestStorage(resource.MustParse("100Gi")).PersistentVolumeClaim,
},
pvs: []*v1.PersistentVolume{
setPVNodeAffinity(setPVCapacity(makePV("pv-a-0", waitSC.Name), resource.MustParse("200Gi")), map[string][]string{v1.LabelHostname: {"node-a"}}),
setPVNodeAffinity(setPVCapacity(makePV("pv-a-1", waitSC.Name), resource.MustParse("200Gi")), map[string][]string{v1.LabelHostname: {"node-a"}}),
setPVNodeAffinity(setPVCapacity(makePV("pv-a-2", waitHDDSC.Name), resource.MustParse("200Gi")), map[string][]string{v1.LabelHostname: {"node-a"}}),
setPVNodeAffinity(setPVCapacity(makePV("pv-a-3", waitHDDSC.Name), resource.MustParse("200Gi")), map[string][]string{v1.LabelHostname: {"node-a"}}),
setPVNodeAffinity(setPVCapacity(makePV("pv-b-0", waitSC.Name), resource.MustParse("100Gi")), map[string][]string{v1.LabelHostname: {"node-b"}}),
setPVNodeAffinity(setPVCapacity(makePV("pv-b-1", waitSC.Name), resource.MustParse("100Gi")), map[string][]string{v1.LabelHostname: {"node-b"}}),
setPVNodeAffinity(setPVCapacity(makePV("pv-b-2", waitHDDSC.Name), resource.MustParse("100Gi")), map[string][]string{v1.LabelHostname: {"node-b"}}),
setPVNodeAffinity(setPVCapacity(makePV("pv-b-3", waitHDDSC.Name), resource.MustParse("100Gi")), map[string][]string{v1.LabelHostname: {"node-b"}}),
makePV("pv-a-0", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("200Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-a"}}).PersistentVolume,
makePV("pv-a-1", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("200Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-a"}}).PersistentVolume,
makePV("pv-a-2", waitHDDSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("200Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-a"}}).PersistentVolume,
makePV("pv-a-3", waitHDDSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("200Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-a"}}).PersistentVolume,
makePV("pv-b-0", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("100Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-b"}}).PersistentVolume,
makePV("pv-b-1", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("100Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-b"}}).PersistentVolume,
makePV("pv-b-2", waitHDDSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("100Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-b"}}).PersistentVolume,
makePV("pv-b-3", waitHDDSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("100Gi")).
withNodeAffinity(map[string][]string{v1.LabelHostname: {"node-b"}}).PersistentVolume,
},
feature: features.VolumeCapacityPriority,
wantPreFilterStatus: nil,
wantStateAfterPreFilter: &stateData{
boundClaims: []*v1.PersistentVolumeClaim{},
claimsToBind: []*v1.PersistentVolumeClaim{
setPVCRequestStorage(makePVC("pvc-0", "", waitSC.Name), resource.MustParse("50Gi")),
setPVCRequestStorage(makePVC("pvc-1", "", waitHDDSC.Name), resource.MustParse("100Gi")),
makePVC("pvc-0", waitSC.Name).withRequestStorage(resource.MustParse("50Gi")).PersistentVolumeClaim,
makePVC("pvc-1", waitHDDSC.Name).withRequestStorage(resource.MustParse("100Gi")).PersistentVolumeClaim,
},
podVolumesByNode: map[string]*scheduling.PodVolumes{},
podVolumesByNode: map[string]*PodVolumes{},
},
wantFilterStatus: []*framework.Status{
nil,
@ -462,62 +387,68 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "zonal volumes with close capacity are preferred",
pod: makePod("pod-a", []string{"pvc-a"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").Pod,
nodes: []*v1.Node{
mergeNodeLabels(makeNode("zone-a-node-a"), map[string]string{
"topology.kubernetes.io/region": "region-a",
"topology.kubernetes.io/zone": "zone-a",
}),
mergeNodeLabels(makeNode("zone-a-node-b"), map[string]string{
"topology.kubernetes.io/region": "region-a",
"topology.kubernetes.io/zone": "zone-a",
}),
mergeNodeLabels(makeNode("zone-b-node-a"), map[string]string{
"topology.kubernetes.io/region": "region-b",
"topology.kubernetes.io/zone": "zone-b",
}),
mergeNodeLabels(makeNode("zone-b-node-b"), map[string]string{
"topology.kubernetes.io/region": "region-b",
"topology.kubernetes.io/zone": "zone-b",
}),
mergeNodeLabels(makeNode("zone-c-node-a"), map[string]string{
"topology.kubernetes.io/region": "region-c",
"topology.kubernetes.io/zone": "zone-c",
}),
mergeNodeLabels(makeNode("zone-c-node-b"), map[string]string{
"topology.kubernetes.io/region": "region-c",
"topology.kubernetes.io/zone": "zone-c",
}),
makeNode("zone-a-node-a").
withLabel("topology.kubernetes.io/region", "region-a").
withLabel("topology.kubernetes.io/zone", "zone-a").Node,
makeNode("zone-a-node-b").
withLabel("topology.kubernetes.io/region", "region-a").
withLabel("topology.kubernetes.io/zone", "zone-a").Node,
makeNode("zone-b-node-a").
withLabel("topology.kubernetes.io/region", "region-b").
withLabel("topology.kubernetes.io/zone", "zone-b").Node,
makeNode("zone-b-node-b").
withLabel("topology.kubernetes.io/region", "region-b").
withLabel("topology.kubernetes.io/zone", "zone-b").Node,
makeNode("zone-c-node-a").
withLabel("topology.kubernetes.io/region", "region-c").
withLabel("topology.kubernetes.io/zone", "zone-c").Node,
makeNode("zone-c-node-b").
withLabel("topology.kubernetes.io/region", "region-c").
withLabel("topology.kubernetes.io/zone", "zone-c").Node,
},
pvcs: []*v1.PersistentVolumeClaim{
setPVCRequestStorage(makePVC("pvc-a", "", waitSC.Name), resource.MustParse("50Gi")),
makePVC("pvc-a", waitSC.Name).withRequestStorage(resource.MustParse("50Gi")).PersistentVolumeClaim,
},
pvs: []*v1.PersistentVolume{
setPVNodeAffinity(setPVCapacity(makePV("pv-a-0", waitSC.Name), resource.MustParse("200Gi")), map[string][]string{
"topology.kubernetes.io/region": {"region-a"},
"topology.kubernetes.io/zone": {"zone-a"},
}),
setPVNodeAffinity(setPVCapacity(makePV("pv-a-1", waitSC.Name), resource.MustParse("200Gi")), map[string][]string{
"topology.kubernetes.io/region": {"region-a"},
"topology.kubernetes.io/zone": {"zone-a"},
}),
setPVNodeAffinity(setPVCapacity(makePV("pv-b-0", waitSC.Name), resource.MustParse("100Gi")), map[string][]string{
"topology.kubernetes.io/region": {"region-b"},
"topology.kubernetes.io/zone": {"zone-b"},
}),
setPVNodeAffinity(setPVCapacity(makePV("pv-b-1", waitSC.Name), resource.MustParse("100Gi")), map[string][]string{
"topology.kubernetes.io/region": {"region-b"},
"topology.kubernetes.io/zone": {"zone-b"},
}),
makePV("pv-a-0", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("200Gi")).
withNodeAffinity(map[string][]string{
"topology.kubernetes.io/region": {"region-a"},
"topology.kubernetes.io/zone": {"zone-a"},
}).PersistentVolume,
makePV("pv-a-1", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("200Gi")).
withNodeAffinity(map[string][]string{
"topology.kubernetes.io/region": {"region-a"},
"topology.kubernetes.io/zone": {"zone-a"},
}).PersistentVolume,
makePV("pv-b-0", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("100Gi")).
withNodeAffinity(map[string][]string{
"topology.kubernetes.io/region": {"region-b"},
"topology.kubernetes.io/zone": {"zone-b"},
}).PersistentVolume,
makePV("pv-b-1", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("100Gi")).
withNodeAffinity(map[string][]string{
"topology.kubernetes.io/region": {"region-b"},
"topology.kubernetes.io/zone": {"zone-b"},
}).PersistentVolume,
},
feature: features.VolumeCapacityPriority,
wantPreFilterStatus: nil,
wantStateAfterPreFilter: &stateData{
boundClaims: []*v1.PersistentVolumeClaim{},
claimsToBind: []*v1.PersistentVolumeClaim{
setPVCRequestStorage(makePVC("pvc-a", "", waitSC.Name), resource.MustParse("50Gi")),
makePVC("pvc-a", waitSC.Name).withRequestStorage(resource.MustParse("50Gi")).PersistentVolumeClaim,
},
podVolumesByNode: map[string]*scheduling.PodVolumes{},
podVolumesByNode: map[string]*PodVolumes{},
},
wantFilterStatus: []*framework.Status{
nil,
@ -538,53 +469,59 @@ func TestVolumeBinding(t *testing.T) {
},
{
name: "zonal volumes with close capacity are preferred (custom shape)",
pod: makePod("pod-a", []string{"pvc-a"}),
pod: makePod("pod-a").withPVCVolume("pvc-a", "").Pod,
nodes: []*v1.Node{
mergeNodeLabels(makeNode("zone-a-node-a"), map[string]string{
"topology.kubernetes.io/region": "region-a",
"topology.kubernetes.io/zone": "zone-a",
}),
mergeNodeLabels(makeNode("zone-a-node-b"), map[string]string{
"topology.kubernetes.io/region": "region-a",
"topology.kubernetes.io/zone": "zone-a",
}),
mergeNodeLabels(makeNode("zone-b-node-a"), map[string]string{
"topology.kubernetes.io/region": "region-b",
"topology.kubernetes.io/zone": "zone-b",
}),
mergeNodeLabels(makeNode("zone-b-node-b"), map[string]string{
"topology.kubernetes.io/region": "region-b",
"topology.kubernetes.io/zone": "zone-b",
}),
mergeNodeLabels(makeNode("zone-c-node-a"), map[string]string{
"topology.kubernetes.io/region": "region-c",
"topology.kubernetes.io/zone": "zone-c",
}),
mergeNodeLabels(makeNode("zone-c-node-b"), map[string]string{
"topology.kubernetes.io/region": "region-c",
"topology.kubernetes.io/zone": "zone-c",
}),
makeNode("zone-a-node-a").
withLabel("topology.kubernetes.io/region", "region-a").
withLabel("topology.kubernetes.io/zone", "zone-a").Node,
makeNode("zone-a-node-b").
withLabel("topology.kubernetes.io/region", "region-a").
withLabel("topology.kubernetes.io/zone", "zone-a").Node,
makeNode("zone-b-node-a").
withLabel("topology.kubernetes.io/region", "region-b").
withLabel("topology.kubernetes.io/zone", "zone-b").Node,
makeNode("zone-b-node-b").
withLabel("topology.kubernetes.io/region", "region-b").
withLabel("topology.kubernetes.io/zone", "zone-b").Node,
makeNode("zone-c-node-a").
withLabel("topology.kubernetes.io/region", "region-c").
withLabel("topology.kubernetes.io/zone", "zone-c").Node,
makeNode("zone-c-node-b").
withLabel("topology.kubernetes.io/region", "region-c").
withLabel("topology.kubernetes.io/zone", "zone-c").Node,
},
pvcs: []*v1.PersistentVolumeClaim{
setPVCRequestStorage(makePVC("pvc-a", "", waitSC.Name), resource.MustParse("50Gi")),
makePVC("pvc-a", waitSC.Name).withRequestStorage(resource.MustParse("50Gi")).PersistentVolumeClaim,
},
pvs: []*v1.PersistentVolume{
setPVNodeAffinity(setPVCapacity(makePV("pv-a-0", waitSC.Name), resource.MustParse("200Gi")), map[string][]string{
"topology.kubernetes.io/region": {"region-a"},
"topology.kubernetes.io/zone": {"zone-a"},
}),
setPVNodeAffinity(setPVCapacity(makePV("pv-a-1", waitSC.Name), resource.MustParse("200Gi")), map[string][]string{
"topology.kubernetes.io/region": {"region-a"},
"topology.kubernetes.io/zone": {"zone-a"},
}),
setPVNodeAffinity(setPVCapacity(makePV("pv-b-0", waitSC.Name), resource.MustParse("100Gi")), map[string][]string{
"topology.kubernetes.io/region": {"region-b"},
"topology.kubernetes.io/zone": {"zone-b"},
}),
setPVNodeAffinity(setPVCapacity(makePV("pv-b-1", waitSC.Name), resource.MustParse("100Gi")), map[string][]string{
"topology.kubernetes.io/region": {"region-b"},
"topology.kubernetes.io/zone": {"zone-b"},
}),
makePV("pv-a-0", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("200Gi")).
withNodeAffinity(map[string][]string{
"topology.kubernetes.io/region": {"region-a"},
"topology.kubernetes.io/zone": {"zone-a"},
}).PersistentVolume,
makePV("pv-a-1", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("200Gi")).
withNodeAffinity(map[string][]string{
"topology.kubernetes.io/region": {"region-a"},
"topology.kubernetes.io/zone": {"zone-a"},
}).PersistentVolume,
makePV("pv-b-0", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("100Gi")).
withNodeAffinity(map[string][]string{
"topology.kubernetes.io/region": {"region-b"},
"topology.kubernetes.io/zone": {"zone-b"},
}).PersistentVolume,
makePV("pv-b-1", waitSC.Name).
withPhase(v1.VolumeAvailable).
withCapacity(resource.MustParse("100Gi")).
withNodeAffinity(map[string][]string{
"topology.kubernetes.io/region": {"region-b"},
"topology.kubernetes.io/zone": {"zone-b"},
}).PersistentVolume,
},
feature: features.VolumeCapacityPriority,
args: &config.VolumeBindingArgs{
@ -608,9 +545,9 @@ func TestVolumeBinding(t *testing.T) {
wantStateAfterPreFilter: &stateData{
boundClaims: []*v1.PersistentVolumeClaim{},
claimsToBind: []*v1.PersistentVolumeClaim{
setPVCRequestStorage(makePVC("pvc-a", "", waitSC.Name), resource.MustParse("50Gi")),
makePVC("pvc-a", waitSC.Name).withRequestStorage(resource.MustParse("50Gi")).PersistentVolumeClaim,
},
podVolumesByNode: map[string]*scheduling.PodVolumes{},
podVolumesByNode: map[string]*PodVolumes{},
},
wantFilterStatus: []*framework.Status{
nil,

View File

@ -30,7 +30,6 @@ import (
"k8s.io/client-go/informers"
clientsetfake "k8s.io/client-go/kubernetes/fake"
extenderv1 "k8s.io/kube-scheduler/extender/v1"
volumescheduling "k8s.io/kubernetes/pkg/controller/volume/scheduling"
"k8s.io/kubernetes/pkg/scheduler/framework"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/interpodaffinity"
@ -41,6 +40,7 @@ import (
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/podtopologyspread"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumerestrictions"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumezone"
frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
@ -135,8 +135,8 @@ func TestNodesWherePreemptionMightHelp(t *testing.T) {
name: "ErrVolume... errors should not be tried as it indicates that the pod is unschedulable due to no matching volumes for pod on node",
nodesStatuses: framework.NodeToStatusMap{
"node1": framework.NewStatus(framework.UnschedulableAndUnresolvable, volumezone.ErrReasonConflict),
"node2": framework.NewStatus(framework.UnschedulableAndUnresolvable, string(volumescheduling.ErrReasonNodeConflict)),
"node3": framework.NewStatus(framework.UnschedulableAndUnresolvable, string(volumescheduling.ErrReasonBindConflict)),
"node2": framework.NewStatus(framework.UnschedulableAndUnresolvable, string(volumebinding.ErrReasonNodeConflict)),
"node3": framework.NewStatus(framework.UnschedulableAndUnresolvable, string(volumebinding.ErrReasonBindConflict)),
},
expected: sets.NewString("node4"),
},

View File

@ -22,7 +22,7 @@ import (
"k8s.io/component-base/metrics"
"k8s.io/component-base/metrics/legacyregistry"
volumeschedulingmetrics "k8s.io/kubernetes/pkg/controller/volume/scheduling/metrics"
volumebindingmetrics "k8s.io/kubernetes/pkg/scheduler/framework/plugins/volumebinding/metrics"
)
const (
@ -189,7 +189,7 @@ func Register() {
// Register the metrics.
registerMetrics.Do(func() {
RegisterMetrics(metricsList...)
volumeschedulingmetrics.RegisterVolumeSchedulingMetrics()
volumebindingmetrics.RegisterVolumeSchedulingMetrics()
})
}

View File

@ -47,7 +47,6 @@ import (
clienttesting "k8s.io/client-go/testing"
clientcache "k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/events"
"k8s.io/kubernetes/pkg/controller/volume/scheduling"
schedulerapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
"k8s.io/kubernetes/pkg/scheduler/framework"
"k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
@ -954,7 +953,7 @@ func setupTestScheduler(queuedPodStore *clientcache.FIFO, scache internalcache.C
return sched, bindingChan, errChan
}
func setupTestSchedulerWithVolumeBinding(volumeBinder scheduling.SchedulerVolumeBinder, stop <-chan struct{}, broadcaster events.EventBroadcaster) (*Scheduler, chan *v1.Binding, chan error) {
func setupTestSchedulerWithVolumeBinding(volumeBinder volumebinding.SchedulerVolumeBinder, stop <-chan struct{}, broadcaster events.EventBroadcaster) (*Scheduler, chan *v1.Binding, chan error) {
testNode := v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "machine1", UID: types.UID("machine1")}}
queuedPodStore := clientcache.NewFIFO(clientcache.MetaNamespaceKeyFunc)
pod := podWithID("foo", "")
@ -1009,11 +1008,11 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
expectAssumeCalled bool
expectBindCalled bool
eventReason string
volumeBinderConfig *scheduling.FakeVolumeBinderConfig
volumeBinderConfig *volumebinding.FakeVolumeBinderConfig
}{
{
name: "all bound",
volumeBinderConfig: &scheduling.FakeVolumeBinderConfig{
volumeBinderConfig: &volumebinding.FakeVolumeBinderConfig{
AllBound: true,
},
expectAssumeCalled: true,
@ -1022,32 +1021,32 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
},
{
name: "bound/invalid pv affinity",
volumeBinderConfig: &scheduling.FakeVolumeBinderConfig{
volumeBinderConfig: &volumebinding.FakeVolumeBinderConfig{
AllBound: true,
FindReasons: scheduling.ConflictReasons{scheduling.ErrReasonNodeConflict},
FindReasons: volumebinding.ConflictReasons{volumebinding.ErrReasonNodeConflict},
},
eventReason: "FailedScheduling",
expectError: makePredicateError("1 node(s) had volume node affinity conflict"),
},
{
name: "unbound/no matches",
volumeBinderConfig: &scheduling.FakeVolumeBinderConfig{
FindReasons: scheduling.ConflictReasons{scheduling.ErrReasonBindConflict},
volumeBinderConfig: &volumebinding.FakeVolumeBinderConfig{
FindReasons: volumebinding.ConflictReasons{volumebinding.ErrReasonBindConflict},
},
eventReason: "FailedScheduling",
expectError: makePredicateError("1 node(s) didn't find available persistent volumes to bind"),
},
{
name: "bound and unbound unsatisfied",
volumeBinderConfig: &scheduling.FakeVolumeBinderConfig{
FindReasons: scheduling.ConflictReasons{scheduling.ErrReasonBindConflict, scheduling.ErrReasonNodeConflict},
volumeBinderConfig: &volumebinding.FakeVolumeBinderConfig{
FindReasons: volumebinding.ConflictReasons{volumebinding.ErrReasonBindConflict, volumebinding.ErrReasonNodeConflict},
},
eventReason: "FailedScheduling",
expectError: makePredicateError("1 node(s) didn't find available persistent volumes to bind, 1 node(s) had volume node affinity conflict"),
},
{
name: "unbound/found matches/bind succeeds",
volumeBinderConfig: &scheduling.FakeVolumeBinderConfig{},
volumeBinderConfig: &volumebinding.FakeVolumeBinderConfig{},
expectAssumeCalled: true,
expectBindCalled: true,
expectPodBind: &v1.Binding{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "foo-ns", UID: types.UID("foo")}, Target: v1.ObjectReference{Kind: "Node", Name: "machine1"}},
@ -1055,7 +1054,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
},
{
name: "predicate error",
volumeBinderConfig: &scheduling.FakeVolumeBinderConfig{
volumeBinderConfig: &volumebinding.FakeVolumeBinderConfig{
FindErr: findErr,
},
eventReason: "FailedScheduling",
@ -1063,7 +1062,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
},
{
name: "assume error",
volumeBinderConfig: &scheduling.FakeVolumeBinderConfig{
volumeBinderConfig: &volumebinding.FakeVolumeBinderConfig{
AssumeErr: assumeErr,
},
expectAssumeCalled: true,
@ -1072,7 +1071,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
},
{
name: "bind error",
volumeBinderConfig: &scheduling.FakeVolumeBinderConfig{
volumeBinderConfig: &volumebinding.FakeVolumeBinderConfig{
BindErr: bindErr,
},
expectAssumeCalled: true,
@ -1085,7 +1084,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
for _, item := range table {
t.Run(item.name, func(t *testing.T) {
stop := make(chan struct{})
fakeVolumeBinder := scheduling.NewFakeVolumeBinder(item.volumeBinderConfig)
fakeVolumeBinder := volumebinding.NewFakeVolumeBinder(item.volumeBinderConfig)
s, bindingChan, errChan := setupTestSchedulerWithVolumeBinding(fakeVolumeBinder, stop, eventBroadcaster)
eventChan := make(chan struct{})
stopFunc := eventBroadcaster.StartEventWatcher(func(obj runtime.Object) {

View File

@ -37,7 +37,6 @@ rules:
- k8s.io/kubernetes/pkg/controller/service
- k8s.io/kubernetes/pkg/controller/util/node
- k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util
- k8s.io/kubernetes/pkg/controller/volume/scheduling
- k8s.io/kubernetes/pkg/credentialprovider
- k8s.io/kubernetes/pkg/credentialprovider/aws
- k8s.io/kubernetes/pkg/credentialprovider/azure

View File

@ -44,7 +44,6 @@ import (
clientset "k8s.io/client-go/kubernetes"
cachetools "k8s.io/client-go/tools/cache"
watchtools "k8s.io/client-go/tools/watch"
"k8s.io/kubernetes/pkg/controller/volume/scheduling"
"k8s.io/kubernetes/pkg/kubelet/events"
"k8s.io/kubernetes/test/e2e/framework"
e2eevents "k8s.io/kubernetes/test/e2e/framework/events"
@ -1883,11 +1882,12 @@ const (
pvcAsSourceProtectionFinalizer = "snapshot.storage.kubernetes.io/pvc-as-source-protection"
volumeSnapshotContentFinalizer = "snapshot.storage.kubernetes.io/volumesnapshotcontent-bound-protection"
volumeSnapshotBoundFinalizer = "snapshot.storage.kubernetes.io/volumesnapshot-bound-protection"
errReasonNotEnoughSpace = "node(s) did not have enough free storage"
)
var (
errPodCompleted = fmt.Errorf("pod ran to completion")
errNotEnoughSpace = errors.New(scheduling.ErrReasonNotEnoughSpace)
errNotEnoughSpace = errors.New(errReasonNotEnoughSpace)
)
func podHasStorage(ctx context.Context, c clientset.Interface, podName, namespace string, when time.Time) wait.ConditionFunc {
@ -1911,7 +1911,7 @@ func podHasStorage(ctx context.Context, c clientset.Interface, podName, namespac
}
for _, event := range events.Items {
if /* event.CreationTimestamp.After(when) &&
*/strings.Contains(event.Message, scheduling.ErrReasonNotEnoughSpace) {
*/strings.Contains(event.Message, errReasonNotEnoughSpace) {
return false, errNotEnoughSpace
}
}