Unverified Commit ef550e69 authored by Kubernetes Prow Robot's avatar Kubernetes Prow Robot Committed by GitHub

Merge pull request #75434 from cofyc/fix56098

Refactor PV scheduling library into a separate package
parents e8712412 214ea1a9
...@@ -12,7 +12,6 @@ go_library( ...@@ -12,7 +12,6 @@ go_library(
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//cmd/kube-scheduler/app/config:go_default_library", "//cmd/kube-scheduler/app/config:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/client/leaderelectionconfig:go_default_library", "//pkg/client/leaderelectionconfig:go_default_library",
"//pkg/master/ports:go_default_library", "//pkg/master/ports:go_default_library",
"//pkg/scheduler/apis/config:go_default_library", "//pkg/scheduler/apis/config:go_default_library",
...@@ -29,6 +28,7 @@ go_library( ...@@ -29,6 +28,7 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library", "//staging/src/k8s.io/client-go/informers:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/rest:go_default_library", "//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library", "//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
......
...@@ -30,6 +30,7 @@ import ( ...@@ -30,6 +30,7 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/informers" "k8s.io/client-go/informers"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/kubernetes/scheme"
v1core "k8s.io/client-go/kubernetes/typed/core/v1" v1core "k8s.io/client-go/kubernetes/typed/core/v1"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
...@@ -42,7 +43,6 @@ import ( ...@@ -42,7 +43,6 @@ import (
"k8s.io/klog" "k8s.io/klog"
kubeschedulerconfigv1alpha1 "k8s.io/kube-scheduler/config/v1alpha1" kubeschedulerconfigv1alpha1 "k8s.io/kube-scheduler/config/v1alpha1"
schedulerappconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config" schedulerappconfig "k8s.io/kubernetes/cmd/kube-scheduler/app/config"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/client/leaderelectionconfig" "k8s.io/kubernetes/pkg/client/leaderelectionconfig"
"k8s.io/kubernetes/pkg/master/ports" "k8s.io/kubernetes/pkg/master/ports"
kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config"
...@@ -238,7 +238,7 @@ func (o *Options) Config() (*schedulerappconfig.Config, error) { ...@@ -238,7 +238,7 @@ func (o *Options) Config() (*schedulerappconfig.Config, error) {
// Prepare event clients. // Prepare event clients.
eventBroadcaster := record.NewBroadcaster() eventBroadcaster := record.NewBroadcaster()
recorder := eventBroadcaster.NewRecorder(legacyscheme.Scheme, corev1.EventSource{Component: c.ComponentConfig.SchedulerName}) recorder := eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: c.ComponentConfig.SchedulerName})
// Set up leader election if enabled. // Set up leader election if enabled.
var leaderElectionConfig *leaderelection.LeaderElectionConfig var leaderElectionConfig *leaderelection.LeaderElectionConfig
......
...@@ -107,6 +107,8 @@ pkg/controller/volume/expand ...@@ -107,6 +107,8 @@ pkg/controller/volume/expand
pkg/controller/volume/persistentvolume pkg/controller/volume/persistentvolume
pkg/controller/volume/persistentvolume/config/v1alpha1 pkg/controller/volume/persistentvolume/config/v1alpha1
pkg/controller/volume/persistentvolume/options pkg/controller/volume/persistentvolume/options
pkg/controller/volume/persistentvolume/testing
pkg/controller/volume/scheduling
pkg/credentialprovider pkg/credentialprovider
pkg/credentialprovider/gcp pkg/credentialprovider/gcp
pkg/features pkg/features
......
...@@ -146,6 +146,7 @@ filegroup( ...@@ -146,6 +146,7 @@ filegroup(
"//pkg/controller/volume/protectionutil:all-srcs", "//pkg/controller/volume/protectionutil:all-srcs",
"//pkg/controller/volume/pvcprotection:all-srcs", "//pkg/controller/volume/pvcprotection:all-srcs",
"//pkg/controller/volume/pvprotection:all-srcs", "//pkg/controller/volume/pvprotection:all-srcs",
"//pkg/controller/volume/scheduling:all-srcs",
], ],
tags = ["automanaged"], tags = ["automanaged"],
) )
...@@ -12,12 +12,6 @@ go_library( ...@@ -12,12 +12,6 @@ go_library(
"index.go", "index.go",
"pv_controller.go", "pv_controller.go",
"pv_controller_base.go", "pv_controller_base.go",
"scheduler_assume_cache.go",
"scheduler_bind_cache_metrics.go",
"scheduler_binder.go",
"scheduler_binder_cache.go",
"scheduler_binder_fake.go",
"util.go",
"volume_host.go", "volume_host.go",
], ],
importpath = "k8s.io/kubernetes/pkg/controller/volume/persistentvolume", importpath = "k8s.io/kubernetes/pkg/controller/volume/persistentvolume",
...@@ -26,6 +20,7 @@ go_library( ...@@ -26,6 +20,7 @@ go_library(
"//pkg/controller:go_default_library", "//pkg/controller:go_default_library",
"//pkg/controller/volume/events:go_default_library", "//pkg/controller/volume/events:go_default_library",
"//pkg/controller/volume/persistentvolume/metrics:go_default_library", "//pkg/controller/volume/persistentvolume/metrics:go_default_library",
"//pkg/controller/volume/persistentvolume/util:go_default_library",
"//pkg/features:go_default_library", "//pkg/features:go_default_library",
"//pkg/util/goroutinemap:go_default_library", "//pkg/util/goroutinemap:go_default_library",
"//pkg/util/goroutinemap/exponentialbackoff:go_default_library", "//pkg/util/goroutinemap/exponentialbackoff:go_default_library",
...@@ -39,14 +34,12 @@ go_library( ...@@ -39,14 +34,12 @@ go_library(
"//staging/src/k8s.io/api/storage/v1:go_default_library", "//staging/src/k8s.io/api/storage/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/storage/etcd:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/client-go/informers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/informers/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/informers/storage/v1:go_default_library", "//staging/src/k8s.io/client-go/informers/storage/v1:go_default_library",
...@@ -62,7 +55,6 @@ go_library( ...@@ -62,7 +55,6 @@ go_library(
"//staging/src/k8s.io/cloud-provider:go_default_library", "//staging/src/k8s.io/cloud-provider:go_default_library",
"//staging/src/k8s.io/cloud-provider/volume/errors:go_default_library", "//staging/src/k8s.io/cloud-provider/volume/errors:go_default_library",
"//staging/src/k8s.io/csi-translation-lib:go_default_library", "//staging/src/k8s.io/csi-translation-lib:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/k8s.io/klog:go_default_library", "//vendor/k8s.io/klog:go_default_library",
], ],
) )
...@@ -77,15 +69,14 @@ go_test( ...@@ -77,15 +69,14 @@ go_test(
"provision_test.go", "provision_test.go",
"pv_controller_test.go", "pv_controller_test.go",
"recycle_test.go", "recycle_test.go",
"scheduler_assume_cache_test.go",
"scheduler_binder_cache_test.go",
"scheduler_binder_test.go",
], ],
embed = [":go_default_library"], embed = [":go_default_library"],
deps = [ deps = [
"//pkg/api/testapi:go_default_library", "//pkg/api/testapi:go_default_library",
"//pkg/apis/core:go_default_library", "//pkg/apis/core:go_default_library",
"//pkg/controller:go_default_library", "//pkg/controller:go_default_library",
"//pkg/controller/volume/persistentvolume/testing:go_default_library",
"//pkg/controller/volume/persistentvolume/util:go_default_library",
"//pkg/features:go_default_library", "//pkg/features:go_default_library",
"//pkg/volume:go_default_library", "//pkg/volume:go_default_library",
"//pkg/volume/util:go_default_library", "//pkg/volume/util:go_default_library",
...@@ -95,16 +86,12 @@ go_test( ...@@ -95,16 +86,12 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library", "//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library", "//staging/src/k8s.io/client-go/informers:go_default_library",
"//staging/src/k8s.io/client-go/informers/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library", "//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
...@@ -132,6 +119,8 @@ filegroup( ...@@ -132,6 +119,8 @@ filegroup(
"//pkg/controller/volume/persistentvolume/config:all-srcs", "//pkg/controller/volume/persistentvolume/config:all-srcs",
"//pkg/controller/volume/persistentvolume/metrics:all-srcs", "//pkg/controller/volume/persistentvolume/metrics:all-srcs",
"//pkg/controller/volume/persistentvolume/options:all-srcs", "//pkg/controller/volume/persistentvolume/options:all-srcs",
"//pkg/controller/volume/persistentvolume/testing:all-srcs",
"//pkg/controller/volume/persistentvolume/util:all-srcs",
], ],
tags = ["automanaged"], tags = ["automanaged"],
) )
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1" storage "k8s.io/api/storage/v1"
pvtesting "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/testing"
) )
// Test single call to syncVolume, expecting recycling to happen. // Test single call to syncVolume, expecting recycling to happen.
...@@ -91,11 +92,9 @@ func TestDeleteSync(t *testing.T) { ...@@ -91,11 +92,9 @@ func TestDeleteSync(t *testing.T) {
noclaims, noclaims,
noclaims, noclaims,
noevents, noerrors, noevents, noerrors,
wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationDelete, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *volumeReactor) { wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationDelete, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor) {
// Delete the volume before delete operation starts // Delete the volume before delete operation starts
reactor.lock.Lock() reactor.DeleteVolume("volume8-6")
delete(reactor.volumes, "volume8-6")
reactor.lock.Unlock()
}), }),
}, },
{ {
...@@ -108,16 +107,12 @@ func TestDeleteSync(t *testing.T) { ...@@ -108,16 +107,12 @@ func TestDeleteSync(t *testing.T) {
noclaims, noclaims,
newClaimArray("claim8-7", "uid8-7", "10Gi", "volume8-7", v1.ClaimBound, nil), newClaimArray("claim8-7", "uid8-7", "10Gi", "volume8-7", v1.ClaimBound, nil),
noevents, noerrors, noevents, noerrors,
wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationDelete, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *volumeReactor) { wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationDelete, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor) {
reactor.lock.Lock()
defer reactor.lock.Unlock()
// Bind the volume to resurrected claim (this should never // Bind the volume to resurrected claim (this should never
// happen) // happen)
claim := newClaim("claim8-7", "uid8-7", "10Gi", "volume8-7", v1.ClaimBound, nil) claim := newClaim("claim8-7", "uid8-7", "10Gi", "volume8-7", v1.ClaimBound, nil)
reactor.claims[claim.Name] = claim reactor.AddClaimBoundToVolume(claim)
ctrl.claims.Add(claim) ctrl.claims.Add(claim)
volume := reactor.volumes["volume8-7"]
volume.Status.Phase = v1.VolumeBound
}), }),
}, },
{ {
...@@ -141,7 +136,7 @@ func TestDeleteSync(t *testing.T) { ...@@ -141,7 +136,7 @@ func TestDeleteSync(t *testing.T) {
noclaims, noclaims,
noclaims, noclaims,
noevents, noerrors, noevents, noerrors,
func(ctrl *PersistentVolumeController, reactor *volumeReactor, test controllerTest) error { func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
// Inject external deleter annotation // Inject external deleter annotation
test.initialVolumes[0].Annotations[annDynamicallyProvisioned] = "external.io/test" test.initialVolumes[0].Annotations[annDynamicallyProvisioned] = "external.io/test"
test.expectedVolumes[0].Annotations[annDynamicallyProvisioned] = "external.io/test" test.expectedVolumes[0].Annotations[annDynamicallyProvisioned] = "external.io/test"
...@@ -184,7 +179,7 @@ func TestDeleteSync(t *testing.T) { ...@@ -184,7 +179,7 @@ func TestDeleteSync(t *testing.T) {
newClaimArray("claim8-12", "uid8-12", "10Gi", "volume8-12-2", v1.ClaimBound, nil), newClaimArray("claim8-12", "uid8-12", "10Gi", "volume8-12-2", v1.ClaimBound, nil),
newClaimArray("claim8-12", "uid8-12", "10Gi", "volume8-12-2", v1.ClaimBound, nil), newClaimArray("claim8-12", "uid8-12", "10Gi", "volume8-12-2", v1.ClaimBound, nil),
noevents, noerrors, noevents, noerrors,
func(ctrl *PersistentVolumeController, reactor *volumeReactor, test controllerTest) error { func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
// Inject external deleter annotation // Inject external deleter annotation
test.initialVolumes[0].Annotations[annDynamicallyProvisioned] = "external.io/test" test.initialVolumes[0].Annotations[annDynamicallyProvisioned] = "external.io/test"
test.expectedVolumes[0].Annotations[annDynamicallyProvisioned] = "external.io/test" test.expectedVolumes[0].Annotations[annDynamicallyProvisioned] = "external.io/test"
......
...@@ -21,13 +21,9 @@ import ( ...@@ -21,13 +21,9 @@ import (
"sort" "sort"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/features" pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
volumeutil "k8s.io/kubernetes/pkg/volume/util" volumeutil "k8s.io/kubernetes/pkg/volume/util"
) )
...@@ -96,7 +92,7 @@ func (pvIndex *persistentVolumeOrderedIndex) findByClaim(claim *v1.PersistentVol ...@@ -96,7 +92,7 @@ func (pvIndex *persistentVolumeOrderedIndex) findByClaim(claim *v1.PersistentVol
return nil, err return nil, err
} }
bestVol, err := findMatchingVolume(claim, volumes, nil /* node for topology binding*/, nil /* exclusion map */, delayBinding) bestVol, err := pvutil.FindMatchingVolume(claim, volumes, nil /* node for topology binding*/, nil /* exclusion map */, delayBinding)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -108,176 +104,6 @@ func (pvIndex *persistentVolumeOrderedIndex) findByClaim(claim *v1.PersistentVol ...@@ -108,176 +104,6 @@ func (pvIndex *persistentVolumeOrderedIndex) findByClaim(claim *v1.PersistentVol
return nil, nil return nil, nil
} }
// findMatchingVolume goes through the list of volumes to find the best matching volume
// for the claim.
//
// This function is used by both the PV controller and scheduler.
//
// delayBinding is true only in the PV controller path. When set, prebound PVs are still returned
// as a match for the claim, but unbound PVs are skipped.
//
// node is set only in the scheduler path. When set, the PV node affinity is checked against
// the node's labels.
//
// excludedVolumes is only used in the scheduler path, and is needed for evaluating multiple
// unbound PVCs for a single Pod at one time. As each PVC finds a matching PV, the chosen
// PV needs to be excluded from future matching.
func findMatchingVolume(
claim *v1.PersistentVolumeClaim,
volumes []*v1.PersistentVolume,
node *v1.Node,
excludedVolumes map[string]*v1.PersistentVolume,
delayBinding bool) (*v1.PersistentVolume, error) {
var smallestVolume *v1.PersistentVolume
var smallestVolumeQty resource.Quantity
requestedQty := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
requestedClass := v1helper.GetPersistentVolumeClaimClass(claim)
var selector labels.Selector
if claim.Spec.Selector != nil {
internalSelector, err := metav1.LabelSelectorAsSelector(claim.Spec.Selector)
if err != nil {
// should be unreachable code due to validation
return nil, fmt.Errorf("error creating internal label selector for claim: %v: %v", claimToClaimKey(claim), err)
}
selector = internalSelector
}
// Go through all available volumes with two goals:
// - find a volume that is either pre-bound by user or dynamically
// provisioned for this claim. Because of this we need to loop through
// all volumes.
// - find the smallest matching one if there is no volume pre-bound to
// the claim.
for _, volume := range volumes {
if _, ok := excludedVolumes[volume.Name]; ok {
// Skip volumes in the excluded list
continue
}
volumeQty := volume.Spec.Capacity[v1.ResourceStorage]
// check if volumeModes do not match (feature gate protected)
isMismatch, err := checkVolumeModeMismatches(&claim.Spec, &volume.Spec)
if err != nil {
return nil, fmt.Errorf("error checking if volumeMode was a mismatch: %v", err)
}
// filter out mismatching volumeModes
if isMismatch {
continue
}
// check if PV's DeletionTimeStamp is set, if so, skip this volume.
if utilfeature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection) {
if volume.ObjectMeta.DeletionTimestamp != nil {
continue
}
}
nodeAffinityValid := true
if node != nil {
// Scheduler path, check that the PV NodeAffinity
// is satisfied by the node
err := volumeutil.CheckNodeAffinity(volume, node.Labels)
if err != nil {
nodeAffinityValid = false
}
}
if IsVolumeBoundToClaim(volume, claim) {
// this claim and volume are pre-bound; return
// the volume if the size request is satisfied,
// otherwise continue searching for a match
if volumeQty.Cmp(requestedQty) < 0 {
continue
}
// If PV node affinity is invalid, return no match.
// This means the prebound PV (and therefore PVC)
// is not suitable for this node.
if !nodeAffinityValid {
return nil, nil
}
return volume, nil
}
if node == nil && delayBinding {
// PV controller does not bind this claim.
// Scheduler will handle binding unbound volumes
// Scheduler path will have node != nil
continue
}
// filter out:
// - volumes in non-available phase
// - volumes bound to another claim
// - volumes whose labels don't match the claim's selector, if specified
// - volumes in Class that is not requested
// - volumes whose NodeAffinity does not match the node
if volume.Status.Phase != v1.VolumeAvailable {
// We ignore volumes in non-available phase, because volumes that
// satisfies matching criteria will be updated to available, binding
// them now has high chance of encountering unnecessary failures
// due to API conflicts.
continue
} else if volume.Spec.ClaimRef != nil {
continue
} else if selector != nil && !selector.Matches(labels.Set(volume.Labels)) {
continue
}
if v1helper.GetPersistentVolumeClass(volume) != requestedClass {
continue
}
if !nodeAffinityValid {
continue
}
if node != nil {
// Scheduler path
// Check that the access modes match
if !checkAccessModes(claim, volume) {
continue
}
}
if volumeQty.Cmp(requestedQty) >= 0 {
if smallestVolume == nil || smallestVolumeQty.Cmp(volumeQty) > 0 {
smallestVolume = volume
smallestVolumeQty = volumeQty
}
}
}
if smallestVolume != nil {
// Found a matching volume
return smallestVolume, nil
}
return nil, nil
}
// checkVolumeModeMismatches is a convenience method that checks volumeMode for PersistentVolume
// and PersistentVolumeClaims
func checkVolumeModeMismatches(pvcSpec *v1.PersistentVolumeClaimSpec, pvSpec *v1.PersistentVolumeSpec) (bool, error) {
if !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
return false, nil
}
// In HA upgrades, we cannot guarantee that the apiserver is on a version >= controller-manager.
// So we default a nil volumeMode to filesystem
requestedVolumeMode := v1.PersistentVolumeFilesystem
if pvcSpec.VolumeMode != nil {
requestedVolumeMode = *pvcSpec.VolumeMode
}
pvVolumeMode := v1.PersistentVolumeFilesystem
if pvSpec.VolumeMode != nil {
pvVolumeMode = *pvSpec.VolumeMode
}
return requestedVolumeMode != pvVolumeMode, nil
}
// findBestMatchForClaim is a convenience method that finds a volume by the claim's AccessModes and requests for Storage // findBestMatchForClaim is a convenience method that finds a volume by the claim's AccessModes and requests for Storage
func (pvIndex *persistentVolumeOrderedIndex) findBestMatchForClaim(claim *v1.PersistentVolumeClaim, delayBinding bool) (*v1.PersistentVolume, error) { func (pvIndex *persistentVolumeOrderedIndex) findBestMatchForClaim(claim *v1.PersistentVolumeClaim, delayBinding bool) (*v1.PersistentVolume, error) {
return pvIndex.findByClaim(claim, delayBinding) return pvIndex.findByClaim(claim, delayBinding)
...@@ -362,19 +188,3 @@ func claimToClaimKey(claim *v1.PersistentVolumeClaim) string { ...@@ -362,19 +188,3 @@ func claimToClaimKey(claim *v1.PersistentVolumeClaim) string {
func claimrefToClaimKey(claimref *v1.ObjectReference) string { func claimrefToClaimKey(claimref *v1.ObjectReference) string {
return fmt.Sprintf("%s/%s", claimref.Namespace, claimref.Name) return fmt.Sprintf("%s/%s", claimref.Namespace, claimref.Name)
} }
// Returns true if PV satisfies all the PVC's requested AccessModes
func checkAccessModes(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) bool {
pvModesMap := map[v1.PersistentVolumeAccessMode]bool{}
for _, mode := range volume.Spec.AccessModes {
pvModesMap[mode] = true
}
for _, mode := range claim.Spec.AccessModes {
_, ok := pvModesMap[mode]
if !ok {
return false
}
}
return true
}
...@@ -28,6 +28,7 @@ import ( ...@@ -28,6 +28,7 @@ import (
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
ref "k8s.io/client-go/tools/reference" ref "k8s.io/client-go/tools/reference"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/volume/util" "k8s.io/kubernetes/pkg/volume/util"
) )
...@@ -773,7 +774,7 @@ func createTestVolumes() []*v1.PersistentVolume { ...@@ -773,7 +774,7 @@ func createTestVolumes() []*v1.PersistentVolume {
v1.ReadOnlyMany, v1.ReadOnlyMany,
}, },
StorageClassName: classWait, StorageClassName: classWait,
NodeAffinity: getVolumeNodeAffinity("key1", "value1"), NodeAffinity: pvutil.GetVolumeNodeAffinity("key1", "value1"),
VolumeMode: &fs, VolumeMode: &fs,
}, },
Status: v1.PersistentVolumeStatus{ Status: v1.PersistentVolumeStatus{
...@@ -797,7 +798,7 @@ func createTestVolumes() []*v1.PersistentVolume { ...@@ -797,7 +798,7 @@ func createTestVolumes() []*v1.PersistentVolume {
v1.ReadOnlyMany, v1.ReadOnlyMany,
}, },
StorageClassName: classWait, StorageClassName: classWait,
NodeAffinity: getVolumeNodeAffinity("key1", "value1"), NodeAffinity: pvutil.GetVolumeNodeAffinity("key1", "value1"),
VolumeMode: &fs, VolumeMode: &fs,
}, },
Status: v1.PersistentVolumeStatus{ Status: v1.PersistentVolumeStatus{
...@@ -822,7 +823,7 @@ func createTestVolumes() []*v1.PersistentVolume { ...@@ -822,7 +823,7 @@ func createTestVolumes() []*v1.PersistentVolume {
}, },
StorageClassName: classWait, StorageClassName: classWait,
ClaimRef: &v1.ObjectReference{Name: "claim02", Namespace: "myns"}, ClaimRef: &v1.ObjectReference{Name: "claim02", Namespace: "myns"},
NodeAffinity: getVolumeNodeAffinity("key1", "value1"), NodeAffinity: pvutil.GetVolumeNodeAffinity("key1", "value1"),
VolumeMode: &fs, VolumeMode: &fs,
}, },
Status: v1.PersistentVolumeStatus{ Status: v1.PersistentVolumeStatus{
...@@ -846,7 +847,7 @@ func createTestVolumes() []*v1.PersistentVolume { ...@@ -846,7 +847,7 @@ func createTestVolumes() []*v1.PersistentVolume {
v1.ReadOnlyMany, v1.ReadOnlyMany,
}, },
StorageClassName: classWait, StorageClassName: classWait,
NodeAffinity: getVolumeNodeAffinity("key1", "value3"), NodeAffinity: pvutil.GetVolumeNodeAffinity("key1", "value3"),
VolumeMode: &fs, VolumeMode: &fs,
}, },
Status: v1.PersistentVolumeStatus{ Status: v1.PersistentVolumeStatus{
...@@ -870,7 +871,7 @@ func createTestVolumes() []*v1.PersistentVolume { ...@@ -870,7 +871,7 @@ func createTestVolumes() []*v1.PersistentVolume {
v1.ReadOnlyMany, v1.ReadOnlyMany,
}, },
StorageClassName: classWait, StorageClassName: classWait,
NodeAffinity: getVolumeNodeAffinity("key1", "value4"), NodeAffinity: pvutil.GetVolumeNodeAffinity("key1", "value4"),
VolumeMode: &fs, VolumeMode: &fs,
}, },
Status: v1.PersistentVolumeStatus{ Status: v1.PersistentVolumeStatus{
...@@ -894,7 +895,7 @@ func createTestVolumes() []*v1.PersistentVolume { ...@@ -894,7 +895,7 @@ func createTestVolumes() []*v1.PersistentVolume {
v1.ReadOnlyMany, v1.ReadOnlyMany,
}, },
StorageClassName: classWait, StorageClassName: classWait,
NodeAffinity: getVolumeNodeAffinity("key1", "value4"), NodeAffinity: pvutil.GetVolumeNodeAffinity("key1", "value4"),
VolumeMode: &fs, VolumeMode: &fs,
}, },
Status: v1.PersistentVolumeStatus{ Status: v1.PersistentVolumeStatus{
...@@ -918,7 +919,7 @@ func createTestVolumes() []*v1.PersistentVolume { ...@@ -918,7 +919,7 @@ func createTestVolumes() []*v1.PersistentVolume {
v1.ReadOnlyMany, v1.ReadOnlyMany,
}, },
StorageClassName: classWait, StorageClassName: classWait,
NodeAffinity: getVolumeNodeAffinity("key1", "value4"), NodeAffinity: pvutil.GetVolumeNodeAffinity("key1", "value4"),
VolumeMode: &fs, VolumeMode: &fs,
}, },
Status: v1.PersistentVolumeStatus{ Status: v1.PersistentVolumeStatus{
...@@ -942,7 +943,7 @@ func createTestVolumes() []*v1.PersistentVolume { ...@@ -942,7 +943,7 @@ func createTestVolumes() []*v1.PersistentVolume {
v1.ReadOnlyMany, v1.ReadOnlyMany,
}, },
StorageClassName: classWait, StorageClassName: classWait,
NodeAffinity: getVolumeNodeAffinity("key1", "value4"), NodeAffinity: pvutil.GetVolumeNodeAffinity("key1", "value4"),
VolumeMode: &fs, VolumeMode: &fs,
}, },
}, },
...@@ -968,24 +969,6 @@ func testVolume(name, size string) *v1.PersistentVolume { ...@@ -968,24 +969,6 @@ func testVolume(name, size string) *v1.PersistentVolume {
} }
} }
func getVolumeNodeAffinity(key string, value string) *v1.VolumeNodeAffinity {
return &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: key,
Operator: v1.NodeSelectorOpIn,
Values: []string{value},
},
},
},
},
},
}
}
func createVolumeModeBlockTestVolume() *v1.PersistentVolume { func createVolumeModeBlockTestVolume() *v1.PersistentVolume {
blockMode := v1.PersistentVolumeBlock blockMode := v1.PersistentVolumeBlock
...@@ -1163,7 +1146,7 @@ func TestVolumeModeCheck(t *testing.T) { ...@@ -1163,7 +1146,7 @@ func TestVolumeModeCheck(t *testing.T) {
for name, scenario := range scenarios { for name, scenario := range scenarios {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, scenario.enableBlock)() defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.BlockVolume, scenario.enableBlock)()
expectedMismatch, err := checkVolumeModeMismatches(&scenario.pvc.Spec, &scenario.vol.Spec) expectedMismatch, err := pvutil.CheckVolumeModeMismatches(&scenario.pvc.Spec, &scenario.vol.Spec)
if err != nil { if err != nil {
t.Errorf("Unexpected failure for checkVolumeModeMismatches: %v", err) t.Errorf("Unexpected failure for checkVolumeModeMismatches: %v", err)
} }
...@@ -1608,7 +1591,7 @@ func TestFindMatchVolumeWithNode(t *testing.T) { ...@@ -1608,7 +1591,7 @@ func TestFindMatchVolumeWithNode(t *testing.T) {
} }
for name, scenario := range scenarios { for name, scenario := range scenarios {
volume, err := findMatchingVolume(scenario.claim, volumes, scenario.node, scenario.excludedVolumes, true) volume, err := pvutil.FindMatchingVolume(scenario.claim, volumes, scenario.node, scenario.excludedVolumes, true)
if err != nil { if err != nil {
t.Errorf("Unexpected error matching volume by claim: %v", err) t.Errorf("Unexpected error matching volume by claim: %v", err)
} }
...@@ -1662,7 +1645,7 @@ func TestCheckAccessModes(t *testing.T) { ...@@ -1662,7 +1645,7 @@ func TestCheckAccessModes(t *testing.T) {
} }
for name, scenario := range scenarios { for name, scenario := range scenarios {
result := checkAccessModes(scenario.claim, volume) result := pvutil.CheckAccessModes(scenario.claim, volume)
if result != scenario.shouldSucceed { if result != scenario.shouldSucceed {
t.Errorf("Test %q failed: Expected %v, got %v", name, scenario.shouldSucceed, result) t.Errorf("Test %q failed: Expected %v, got %v", name, scenario.shouldSucceed, result)
} }
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
apierrs "k8s.io/apimachinery/pkg/api/errors" apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
api "k8s.io/kubernetes/pkg/apis/core" api "k8s.io/kubernetes/pkg/apis/core"
pvtesting "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/testing"
) )
var class1Parameters = map[string]string{ var class1Parameters = map[string]string{
...@@ -191,13 +192,11 @@ func TestProvisionSync(t *testing.T) { ...@@ -191,13 +192,11 @@ func TestProvisionSync(t *testing.T) {
// The claim would be bound in next syncClaim // The claim would be bound in next syncClaim
newClaimArray("claim11-7", "uid11-7", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner), newClaimArray("claim11-7", "uid11-7", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner),
noevents, noerrors, noevents, noerrors,
wrapTestWithInjectedOperation(wrapTestWithProvisionCalls([]provisionCall{}, testSyncClaim), func(ctrl *PersistentVolumeController, reactor *volumeReactor) { wrapTestWithInjectedOperation(wrapTestWithProvisionCalls([]provisionCall{}, testSyncClaim), func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor) {
// Create a volume before provisionClaimOperation starts. // Create a volume before provisionClaimOperation starts.
// This similates a parallel controller provisioning the volume. // This similates a parallel controller provisioning the volume.
reactor.lock.Lock()
volume := newVolume("pvc-uid11-7", "1Gi", "uid11-7", "claim11-7", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classGold, annBoundByController, annDynamicallyProvisioned) volume := newVolume("pvc-uid11-7", "1Gi", "uid11-7", "claim11-7", v1.VolumeBound, v1.PersistentVolumeReclaimDelete, classGold, annBoundByController, annDynamicallyProvisioned)
reactor.volumes[volume.Name] = volume reactor.AddVolume(volume)
reactor.lock.Unlock()
}), }),
}, },
{ {
...@@ -210,11 +209,11 @@ func TestProvisionSync(t *testing.T) { ...@@ -210,11 +209,11 @@ func TestProvisionSync(t *testing.T) {
// Binding will be completed in the next syncClaim // Binding will be completed in the next syncClaim
newClaimArray("claim11-8", "uid11-8", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner), newClaimArray("claim11-8", "uid11-8", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner),
[]string{"Normal ProvisioningSucceeded"}, []string{"Normal ProvisioningSucceeded"},
[]reactorError{ []pvtesting.ReactorError{
// Inject error to the first // Inject error to the first
// kubeclient.PersistentVolumes.Create() call. All other calls // kubeclient.PersistentVolumes.Create() call. All other calls
// will succeed. // will succeed.
{"create", "persistentvolumes", errors.New("Mock creation error")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error")},
}, },
wrapTestWithProvisionCalls([]provisionCall{provision1Success}, testSyncClaim), wrapTestWithProvisionCalls([]provisionCall{provision1Success}, testSyncClaim),
}, },
...@@ -227,14 +226,14 @@ func TestProvisionSync(t *testing.T) { ...@@ -227,14 +226,14 @@ func TestProvisionSync(t *testing.T) {
newClaimArray("claim11-9", "uid11-9", "1Gi", "", v1.ClaimPending, &classGold), newClaimArray("claim11-9", "uid11-9", "1Gi", "", v1.ClaimPending, &classGold),
newClaimArray("claim11-9", "uid11-9", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner), newClaimArray("claim11-9", "uid11-9", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner),
[]string{"Warning ProvisioningFailed"}, []string{"Warning ProvisioningFailed"},
[]reactorError{ []pvtesting.ReactorError{
// Inject error to five kubeclient.PersistentVolumes.Create() // Inject error to five kubeclient.PersistentVolumes.Create()
// calls // calls
{"create", "persistentvolumes", errors.New("Mock creation error1")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error1")},
{"create", "persistentvolumes", errors.New("Mock creation error2")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error2")},
{"create", "persistentvolumes", errors.New("Mock creation error3")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error3")},
{"create", "persistentvolumes", errors.New("Mock creation error4")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error4")},
{"create", "persistentvolumes", errors.New("Mock creation error5")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error5")},
}, },
wrapTestWithPluginCalls( wrapTestWithPluginCalls(
nil, // recycle calls nil, // recycle calls
...@@ -252,14 +251,14 @@ func TestProvisionSync(t *testing.T) { ...@@ -252,14 +251,14 @@ func TestProvisionSync(t *testing.T) {
newClaimArray("claim11-10", "uid11-10", "1Gi", "", v1.ClaimPending, &classGold), newClaimArray("claim11-10", "uid11-10", "1Gi", "", v1.ClaimPending, &classGold),
newClaimArray("claim11-10", "uid11-10", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner), newClaimArray("claim11-10", "uid11-10", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner),
[]string{"Warning ProvisioningFailed", "Warning ProvisioningCleanupFailed"}, []string{"Warning ProvisioningFailed", "Warning ProvisioningCleanupFailed"},
[]reactorError{ []pvtesting.ReactorError{
// Inject error to five kubeclient.PersistentVolumes.Create() // Inject error to five kubeclient.PersistentVolumes.Create()
// calls // calls
{"create", "persistentvolumes", errors.New("Mock creation error1")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error1")},
{"create", "persistentvolumes", errors.New("Mock creation error2")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error2")},
{"create", "persistentvolumes", errors.New("Mock creation error3")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error3")},
{"create", "persistentvolumes", errors.New("Mock creation error4")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error4")},
{"create", "persistentvolumes", errors.New("Mock creation error5")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error5")},
}, },
// No deleteCalls are configured, which results into no deleter plugin available for the volume // No deleteCalls are configured, which results into no deleter plugin available for the volume
wrapTestWithProvisionCalls([]provisionCall{provision1Success}, testSyncClaim), wrapTestWithProvisionCalls([]provisionCall{provision1Success}, testSyncClaim),
...@@ -273,14 +272,14 @@ func TestProvisionSync(t *testing.T) { ...@@ -273,14 +272,14 @@ func TestProvisionSync(t *testing.T) {
newClaimArray("claim11-11", "uid11-11", "1Gi", "", v1.ClaimPending, &classGold), newClaimArray("claim11-11", "uid11-11", "1Gi", "", v1.ClaimPending, &classGold),
newClaimArray("claim11-11", "uid11-11", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner), newClaimArray("claim11-11", "uid11-11", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner),
[]string{"Warning ProvisioningFailed", "Warning ProvisioningCleanupFailed"}, []string{"Warning ProvisioningFailed", "Warning ProvisioningCleanupFailed"},
[]reactorError{ []pvtesting.ReactorError{
// Inject error to five kubeclient.PersistentVolumes.Create() // Inject error to five kubeclient.PersistentVolumes.Create()
// calls // calls
{"create", "persistentvolumes", errors.New("Mock creation error1")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error1")},
{"create", "persistentvolumes", errors.New("Mock creation error2")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error2")},
{"create", "persistentvolumes", errors.New("Mock creation error3")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error3")},
{"create", "persistentvolumes", errors.New("Mock creation error4")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error4")},
{"create", "persistentvolumes", errors.New("Mock creation error5")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error5")},
}, },
wrapTestWithPluginCalls( wrapTestWithPluginCalls(
nil, // recycle calls nil, // recycle calls
...@@ -303,14 +302,14 @@ func TestProvisionSync(t *testing.T) { ...@@ -303,14 +302,14 @@ func TestProvisionSync(t *testing.T) {
newClaimArray("claim11-12", "uid11-12", "1Gi", "", v1.ClaimPending, &classGold), newClaimArray("claim11-12", "uid11-12", "1Gi", "", v1.ClaimPending, &classGold),
newClaimArray("claim11-12", "uid11-12", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner), newClaimArray("claim11-12", "uid11-12", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner),
[]string{"Warning ProvisioningFailed"}, []string{"Warning ProvisioningFailed"},
[]reactorError{ []pvtesting.ReactorError{
// Inject error to five kubeclient.PersistentVolumes.Create() // Inject error to five kubeclient.PersistentVolumes.Create()
// calls // calls
{"create", "persistentvolumes", errors.New("Mock creation error1")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error1")},
{"create", "persistentvolumes", errors.New("Mock creation error2")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error2")},
{"create", "persistentvolumes", errors.New("Mock creation error3")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error3")},
{"create", "persistentvolumes", errors.New("Mock creation error4")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error4")},
{"create", "persistentvolumes", errors.New("Mock creation error5")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error5")},
}, },
wrapTestWithPluginCalls( wrapTestWithPluginCalls(
nil, // recycle calls nil, // recycle calls
...@@ -397,11 +396,11 @@ func TestProvisionSync(t *testing.T) { ...@@ -397,11 +396,11 @@ func TestProvisionSync(t *testing.T) {
newClaimArray("claim11-19", "uid11-19", "1Gi", "", v1.ClaimPending, &classGold), newClaimArray("claim11-19", "uid11-19", "1Gi", "", v1.ClaimPending, &classGold),
newClaimArray("claim11-19", "uid11-19", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner), newClaimArray("claim11-19", "uid11-19", "1Gi", "", v1.ClaimPending, &classGold, annStorageProvisioner),
noevents, noevents,
[]reactorError{ []pvtesting.ReactorError{
// Inject errors to simulate crashed API server during // Inject errors to simulate crashed API server during
// kubeclient.PersistentVolumes.Create() // kubeclient.PersistentVolumes.Create()
{"create", "persistentvolumes", errors.New("Mock creation error1")}, {Verb: "create", Resource: "persistentvolumes", Error: errors.New("Mock creation error1")},
{"create", "persistentvolumes", apierrs.NewAlreadyExists(api.Resource("persistentvolumes"), "")}, {Verb: "create", Resource: "persistentvolumes", Error: apierrs.NewAlreadyExists(api.Resource("persistentvolumes"), "")},
}, },
wrapTestWithPluginCalls( wrapTestWithPluginCalls(
nil, // recycle calls nil, // recycle calls
......
...@@ -43,6 +43,7 @@ import ( ...@@ -43,6 +43,7 @@ import (
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/controller/volume/events" "k8s.io/kubernetes/pkg/controller/volume/events"
"k8s.io/kubernetes/pkg/controller/volume/persistentvolume/metrics" "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/metrics"
pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
"k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/goroutinemap" "k8s.io/kubernetes/pkg/util/goroutinemap"
"k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff" "k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff"
...@@ -276,7 +277,7 @@ func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVo ...@@ -276,7 +277,7 @@ func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVo
return fmt.Errorf("storageClassName does not match") return fmt.Errorf("storageClassName does not match")
} }
isMismatch, err := checkVolumeModeMismatches(&claim.Spec, &volume.Spec) isMismatch, err := pvutil.CheckVolumeModeMismatches(&claim.Spec, &volume.Spec)
if err != nil { if err != nil {
return fmt.Errorf("error checking volumeMode: %v", err) return fmt.Errorf("error checking volumeMode: %v", err)
} }
...@@ -284,7 +285,7 @@ func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVo ...@@ -284,7 +285,7 @@ func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVo
return fmt.Errorf("incompatible volumeMode") return fmt.Errorf("incompatible volumeMode")
} }
if !checkAccessModes(claim, volume) { if !pvutil.CheckAccessModes(claim, volume) {
return fmt.Errorf("incompatible accessMode") return fmt.Errorf("incompatible accessMode")
} }
...@@ -309,7 +310,7 @@ func (ctrl *PersistentVolumeController) shouldDelayBinding(claim *v1.PersistentV ...@@ -309,7 +310,7 @@ func (ctrl *PersistentVolumeController) shouldDelayBinding(claim *v1.PersistentV
} }
// If claim is in delay binding mode. // If claim is in delay binding mode.
return IsDelayBindingMode(claim, ctrl.classLister) return pvutil.IsDelayBindingMode(claim, ctrl.classLister)
} }
// syncUnboundClaim is the main controller method to decide what to do with an // syncUnboundClaim is the main controller method to decide what to do with an
...@@ -407,7 +408,7 @@ func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *v1.PersistentVol ...@@ -407,7 +408,7 @@ func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *v1.PersistentVol
} }
// OBSERVATION: pvc is "Bound", pv is "Bound" // OBSERVATION: pvc is "Bound", pv is "Bound"
return nil return nil
} else if IsVolumeBoundToClaim(volume, claim) { } else if pvutil.IsVolumeBoundToClaim(volume, claim) {
// User asked for a PV that is claimed by this PVC // User asked for a PV that is claimed by this PVC
// OBSERVATION: pvc is "Pending", pv is "Bound" // OBSERVATION: pvc is "Pending", pv is "Bound"
klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume already bound, finishing the binding", claimToClaimKey(claim)) klog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume already bound, finishing the binding", claimToClaimKey(claim))
...@@ -610,7 +611,7 @@ func (ctrl *PersistentVolumeController) syncVolume(volume *v1.PersistentVolume) ...@@ -610,7 +611,7 @@ func (ctrl *PersistentVolumeController) syncVolume(volume *v1.PersistentVolume)
} }
return nil return nil
} else if claim.Spec.VolumeName == "" { } else if claim.Spec.VolumeName == "" {
if isMismatch, err := checkVolumeModeMismatches(&claim.Spec, &volume.Spec); err != nil || isMismatch { if isMismatch, err := pvutil.CheckVolumeModeMismatches(&claim.Spec, &volume.Spec); err != nil || isMismatch {
// Binding for the volume won't be called in syncUnboundClaim, // Binding for the volume won't be called in syncUnboundClaim,
// because findBestMatchForClaim won't return the volume due to volumeMode mismatch. // because findBestMatchForClaim won't return the volume due to volumeMode mismatch.
volumeMsg := fmt.Sprintf("Cannot bind PersistentVolume to requested PersistentVolumeClaim %q due to incompatible volumeMode.", claim.Name) volumeMsg := fmt.Sprintf("Cannot bind PersistentVolume to requested PersistentVolumeClaim %q due to incompatible volumeMode.", claim.Name)
...@@ -851,7 +852,7 @@ func (ctrl *PersistentVolumeController) updateVolumePhaseWithEvent(volume *v1.Pe ...@@ -851,7 +852,7 @@ func (ctrl *PersistentVolumeController) updateVolumePhaseWithEvent(volume *v1.Pe
func (ctrl *PersistentVolumeController) bindVolumeToClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) (*v1.PersistentVolume, error) { func (ctrl *PersistentVolumeController) bindVolumeToClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) (*v1.PersistentVolume, error) {
klog.V(4).Infof("updating PersistentVolume[%s]: binding to %q", volume.Name, claimToClaimKey(claim)) klog.V(4).Infof("updating PersistentVolume[%s]: binding to %q", volume.Name, claimToClaimKey(claim))
volumeClone, dirty, err := GetBindVolumeToClaim(volume, claim) volumeClone, dirty, err := pvutil.GetBindVolumeToClaim(volume, claim)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -30,6 +30,7 @@ import ( ...@@ -30,6 +30,7 @@ import (
"k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/cache"
"k8s.io/klog" "k8s.io/klog"
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
pvtesting "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/testing"
) )
var ( var (
...@@ -60,9 +61,9 @@ func TestControllerSync(t *testing.T) { ...@@ -60,9 +61,9 @@ func TestControllerSync(t *testing.T) {
newClaimArray("claim5-2", "uid5-2", "1Gi", "volume5-2", v1.ClaimBound, nil, annBoundByController, annBindCompleted), newClaimArray("claim5-2", "uid5-2", "1Gi", "volume5-2", v1.ClaimBound, nil, annBoundByController, annBindCompleted),
noevents, noerrors, noevents, noerrors,
// Custom test function that generates an add event // Custom test function that generates an add event
func(ctrl *PersistentVolumeController, reactor *volumeReactor, test controllerTest) error { func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
claim := newClaim("claim5-2", "uid5-2", "1Gi", "", v1.ClaimPending, nil) claim := newClaim("claim5-2", "uid5-2", "1Gi", "", v1.ClaimPending, nil)
reactor.addClaimEvent(claim) reactor.AddClaimEvent(claim)
return nil return nil
}, },
}, },
...@@ -75,10 +76,10 @@ func TestControllerSync(t *testing.T) { ...@@ -75,10 +76,10 @@ func TestControllerSync(t *testing.T) {
noclaims, noclaims,
noevents, noerrors, noevents, noerrors,
// Custom test function that generates a delete event // Custom test function that generates a delete event
func(ctrl *PersistentVolumeController, reactor *volumeReactor, test controllerTest) error { func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
obj := ctrl.claims.List()[0] obj := ctrl.claims.List()[0]
claim := obj.(*v1.PersistentVolumeClaim) claim := obj.(*v1.PersistentVolumeClaim)
reactor.deleteClaimEvent(claim) reactor.DeleteClaimEvent(claim)
return nil return nil
}, },
}, },
...@@ -91,10 +92,10 @@ func TestControllerSync(t *testing.T) { ...@@ -91,10 +92,10 @@ func TestControllerSync(t *testing.T) {
newClaimArray("claim5-4", "uid5-4", "1Gi", "volume5-4", v1.ClaimLost, nil, annBoundByController, annBindCompleted), newClaimArray("claim5-4", "uid5-4", "1Gi", "volume5-4", v1.ClaimLost, nil, annBoundByController, annBindCompleted),
[]string{"Warning ClaimLost"}, noerrors, []string{"Warning ClaimLost"}, noerrors,
// Custom test function that generates a delete event // Custom test function that generates a delete event
func(ctrl *PersistentVolumeController, reactor *volumeReactor, test controllerTest) error { func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor, test controllerTest) error {
obj := ctrl.volumes.store.List()[0] obj := ctrl.volumes.store.List()[0]
volume := obj.(*v1.PersistentVolume) volume := obj.(*v1.PersistentVolume)
reactor.deleteVolumeEvent(volume) reactor.DeleteVolumeEvent(volume)
return nil return nil
}, },
}, },
...@@ -120,13 +121,13 @@ func TestControllerSync(t *testing.T) { ...@@ -120,13 +121,13 @@ func TestControllerSync(t *testing.T) {
reactor := newVolumeReactor(client, ctrl, fakeVolumeWatch, fakeClaimWatch, test.errors) reactor := newVolumeReactor(client, ctrl, fakeVolumeWatch, fakeClaimWatch, test.errors)
for _, claim := range test.initialClaims { for _, claim := range test.initialClaims {
reactor.claims[claim.Name] = claim reactor.AddClaim(claim)
go func(claim *v1.PersistentVolumeClaim) { go func(claim *v1.PersistentVolumeClaim) {
fakeClaimWatch.Add(claim) fakeClaimWatch.Add(claim)
}(claim) }(claim)
} }
for _, volume := range test.initialVolumes { for _, volume := range test.initialVolumes {
reactor.volumes[volume.Name] = volume reactor.AddVolume(volume)
go func(volume *v1.PersistentVolume) { go func(volume *v1.PersistentVolume) {
fakeVolumeWatch.Add(volume) fakeVolumeWatch.Add(volume)
}(volume) }(volume)
...@@ -148,7 +149,7 @@ func TestControllerSync(t *testing.T) { ...@@ -148,7 +149,7 @@ func TestControllerSync(t *testing.T) {
klog.V(4).Infof("controller synced, starting test") klog.V(4).Infof("controller synced, starting test")
// Call the tested function // Call the tested function
err = test.test(ctrl, reactor, test) err = test.test(ctrl, reactor.VolumeReactor, test)
if err != nil { if err != nil {
t.Errorf("Test %q initial test call failed: %v", test.name, err) t.Errorf("Test %q initial test call failed: %v", test.name, err)
} }
...@@ -162,7 +163,7 @@ func TestControllerSync(t *testing.T) { ...@@ -162,7 +163,7 @@ func TestControllerSync(t *testing.T) {
} }
close(stopCh) close(stopCh)
evaluateTestResults(ctrl, reactor, test, t) evaluateTestResults(ctrl, reactor.VolumeReactor, test, t)
} }
} }
......
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1" storage "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
pvtesting "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/testing"
) )
// Test single call to syncVolume, expecting recycling to happen. // Test single call to syncVolume, expecting recycling to happen.
...@@ -130,11 +131,9 @@ func TestRecycleSync(t *testing.T) { ...@@ -130,11 +131,9 @@ func TestRecycleSync(t *testing.T) {
noclaims, noclaims,
noclaims, noclaims,
noevents, noerrors, noevents, noerrors,
wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationRecycle, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *volumeReactor) { wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationRecycle, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor) {
// Delete the volume before recycle operation starts // Delete the volume before recycle operation starts
reactor.lock.Lock() reactor.DeleteVolume("volume6-6")
delete(reactor.volumes, "volume6-6")
reactor.lock.Unlock()
}), }),
}, },
{ {
...@@ -147,14 +146,9 @@ func TestRecycleSync(t *testing.T) { ...@@ -147,14 +146,9 @@ func TestRecycleSync(t *testing.T) {
noclaims, noclaims,
noclaims, noclaims,
noevents, noerrors, noevents, noerrors,
wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationRecycle, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *volumeReactor) { wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationRecycle, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor) {
// Mark the volume as Available before the recycler starts // Mark the volume as Available before the recycler starts
reactor.lock.Lock() reactor.MarkVolumeAvaiable("volume6-7")
volume := reactor.volumes["volume6-7"]
volume.Spec.ClaimRef = nil
volume.Status.Phase = v1.VolumeAvailable
volume.Annotations = nil
reactor.lock.Unlock()
}), }),
}, },
{ {
...@@ -164,17 +158,13 @@ func TestRecycleSync(t *testing.T) { ...@@ -164,17 +158,13 @@ func TestRecycleSync(t *testing.T) {
// user. // user.
"6-8 - prebound volume is deleted before recycling", "6-8 - prebound volume is deleted before recycling",
newVolumeArray("volume6-8", "1Gi", "uid6-8", "claim6-8", v1.VolumeBound, v1.PersistentVolumeReclaimRecycle, classEmpty), newVolumeArray("volume6-8", "1Gi", "uid6-8", "claim6-8", v1.VolumeBound, v1.PersistentVolumeReclaimRecycle, classEmpty),
newVolumeArray("volume6-8", "1Gi", "", "claim6-8", v1.VolumeAvailable, v1.PersistentVolumeReclaimRecycle, classEmpty), newVolumeArray("volume6-8", "1Gi", "", "", v1.VolumeAvailable, v1.PersistentVolumeReclaimRecycle, classEmpty),
noclaims, noclaims,
noclaims, noclaims,
noevents, noerrors, noevents, noerrors,
wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationRecycle, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *volumeReactor) { wrapTestWithInjectedOperation(wrapTestWithReclaimCalls(operationRecycle, []error{}, testSyncVolume), func(ctrl *PersistentVolumeController, reactor *pvtesting.VolumeReactor) {
// Mark the volume as Available before the recycler starts // Mark the volume as Available before the recycler starts
reactor.lock.Lock() reactor.MarkVolumeAvaiable("volume6-8")
volume := reactor.volumes["volume6-8"]
volume.Spec.ClaimRef.UID = ""
volume.Status.Phase = v1.VolumeAvailable
reactor.lock.Unlock()
}), }),
}, },
{ {
......
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["testing.go"],
importpath = "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/testing",
visibility = ["//visibility:public"],
deps = [
"//pkg/features:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/testing:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["util.go"],
importpath = "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util",
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/features:go_default_library",
"//pkg/volume/util:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/storage/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//staging/src/k8s.io/client-go/listers/storage/v1:go_default_library",
"//staging/src/k8s.io/client-go/tools/reference:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
...@@ -21,11 +21,41 @@ import ( ...@@ -21,11 +21,41 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
storage "k8s.io/api/storage/v1" storage "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/kubernetes/scheme"
storagelisters "k8s.io/client-go/listers/storage/v1" storagelisters "k8s.io/client-go/listers/storage/v1"
"k8s.io/client-go/tools/reference" "k8s.io/client-go/tools/reference"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/features"
volumeutil "k8s.io/kubernetes/pkg/volume/util"
)
const (
// AnnBindCompleted Annotation applies to PVCs. It indicates that the lifecycle
// of the PVC has passed through the initial setup. This information changes how
// we interpret some observations of the state of the objects. Value of this
// Annotation does not matter.
AnnBindCompleted = "pv.kubernetes.io/bind-completed"
// AnnBoundByController annotation applies to PVs and PVCs. It indicates that
// the binding (PV->PVC or PVC->PV) was installed by the controller. The
// absence of this annotation means the binding was done by the user (i.e.
// pre-bound). Value of this annotation does not matter.
// External PV binders must bind PV the same way as PV controller, otherwise PV
// controller may not handle it correctly.
AnnBoundByController = "pv.kubernetes.io/bound-by-controller"
// AnnSelectedNode annotation is added to a PVC that has been triggered by scheduler to
// be dynamically provisioned. Its value is the name of the selected node.
AnnSelectedNode = "volume.kubernetes.io/selected-node"
// NotSupportedProvisioner is a special provisioner name which can be set
// in storage class to indicate dynamic provisioning is not supported by
// the storage.
NotSupportedProvisioner = "kubernetes.io/no-provisioner"
) )
// IsDelayBindingMode checks if claim is in delay binding mode. // IsDelayBindingMode checks if claim is in delay binding mode.
...@@ -77,9 +107,9 @@ func GetBindVolumeToClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolum ...@@ -77,9 +107,9 @@ func GetBindVolumeToClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolum
dirty = true dirty = true
} }
// Set annBoundByController if it is not set yet // Set AnnBoundByController if it is not set yet
if shouldSetBoundByController && !metav1.HasAnnotation(volumeClone.ObjectMeta, annBoundByController) { if shouldSetBoundByController && !metav1.HasAnnotation(volumeClone.ObjectMeta, AnnBoundByController) {
metav1.SetMetaDataAnnotation(&volumeClone.ObjectMeta, annBoundByController, "yes") metav1.SetMetaDataAnnotation(&volumeClone.ObjectMeta, AnnBoundByController, "yes")
dirty = true dirty = true
} }
...@@ -101,3 +131,212 @@ func IsVolumeBoundToClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolum ...@@ -101,3 +131,212 @@ func IsVolumeBoundToClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolum
} }
return true return true
} }
// FindMatchingVolume goes through the list of volumes to find the best matching volume
// for the claim.
//
// This function is used by both the PV controller and scheduler.
//
// delayBinding is true only in the PV controller path. When set, prebound PVs are still returned
// as a match for the claim, but unbound PVs are skipped.
//
// node is set only in the scheduler path. When set, the PV node affinity is checked against
// the node's labels.
//
// excludedVolumes is only used in the scheduler path, and is needed for evaluating multiple
// unbound PVCs for a single Pod at one time. As each PVC finds a matching PV, the chosen
// PV needs to be excluded from future matching.
func FindMatchingVolume(
claim *v1.PersistentVolumeClaim,
volumes []*v1.PersistentVolume,
node *v1.Node,
excludedVolumes map[string]*v1.PersistentVolume,
delayBinding bool) (*v1.PersistentVolume, error) {
var smallestVolume *v1.PersistentVolume
var smallestVolumeQty resource.Quantity
requestedQty := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
requestedClass := v1helper.GetPersistentVolumeClaimClass(claim)
var selector labels.Selector
if claim.Spec.Selector != nil {
internalSelector, err := metav1.LabelSelectorAsSelector(claim.Spec.Selector)
if err != nil {
// should be unreachable code due to validation
return nil, fmt.Errorf("error creating internal label selector for claim: %v: %v", claimToClaimKey(claim), err)
}
selector = internalSelector
}
// Go through all available volumes with two goals:
// - find a volume that is either pre-bound by user or dynamically
// provisioned for this claim. Because of this we need to loop through
// all volumes.
// - find the smallest matching one if there is no volume pre-bound to
// the claim.
for _, volume := range volumes {
if _, ok := excludedVolumes[volume.Name]; ok {
// Skip volumes in the excluded list
continue
}
volumeQty := volume.Spec.Capacity[v1.ResourceStorage]
// check if volumeModes do not match (feature gate protected)
isMismatch, err := CheckVolumeModeMismatches(&claim.Spec, &volume.Spec)
if err != nil {
return nil, fmt.Errorf("error checking if volumeMode was a mismatch: %v", err)
}
// filter out mismatching volumeModes
if isMismatch {
continue
}
// check if PV's DeletionTimeStamp is set, if so, skip this volume.
if utilfeature.DefaultFeatureGate.Enabled(features.StorageObjectInUseProtection) {
if volume.ObjectMeta.DeletionTimestamp != nil {
continue
}
}
nodeAffinityValid := true
if node != nil {
// Scheduler path, check that the PV NodeAffinity
// is satisfied by the node
err := volumeutil.CheckNodeAffinity(volume, node.Labels)
if err != nil {
nodeAffinityValid = false
}
}
if IsVolumeBoundToClaim(volume, claim) {
// this claim and volume are pre-bound; return
// the volume if the size request is satisfied,
// otherwise continue searching for a match
if volumeQty.Cmp(requestedQty) < 0 {
continue
}
// If PV node affinity is invalid, return no match.
// This means the prebound PV (and therefore PVC)
// is not suitable for this node.
if !nodeAffinityValid {
return nil, nil
}
return volume, nil
}
if node == nil && delayBinding {
// PV controller does not bind this claim.
// Scheduler will handle binding unbound volumes
// Scheduler path will have node != nil
continue
}
// filter out:
// - volumes in non-available phase
// - volumes bound to another claim
// - volumes whose labels don't match the claim's selector, if specified
// - volumes in Class that is not requested
// - volumes whose NodeAffinity does not match the node
if volume.Status.Phase != v1.VolumeAvailable {
// We ignore volumes in non-available phase, because volumes that
// satisfies matching criteria will be updated to available, binding
// them now has high chance of encountering unnecessary failures
// due to API conflicts.
continue
} else if volume.Spec.ClaimRef != nil {
continue
} else if selector != nil && !selector.Matches(labels.Set(volume.Labels)) {
continue
}
if v1helper.GetPersistentVolumeClass(volume) != requestedClass {
continue
}
if !nodeAffinityValid {
continue
}
if node != nil {
// Scheduler path
// Check that the access modes match
if !CheckAccessModes(claim, volume) {
continue
}
}
if volumeQty.Cmp(requestedQty) >= 0 {
if smallestVolume == nil || smallestVolumeQty.Cmp(volumeQty) > 0 {
smallestVolume = volume
smallestVolumeQty = volumeQty
}
}
}
if smallestVolume != nil {
// Found a matching volume
return smallestVolume, nil
}
return nil, nil
}
// CheckVolumeModeMismatches is a convenience method that checks volumeMode for PersistentVolume
// and PersistentVolumeClaims
func CheckVolumeModeMismatches(pvcSpec *v1.PersistentVolumeClaimSpec, pvSpec *v1.PersistentVolumeSpec) (bool, error) {
if !utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) {
return false, nil
}
// In HA upgrades, we cannot guarantee that the apiserver is on a version >= controller-manager.
// So we default a nil volumeMode to filesystem
requestedVolumeMode := v1.PersistentVolumeFilesystem
if pvcSpec.VolumeMode != nil {
requestedVolumeMode = *pvcSpec.VolumeMode
}
pvVolumeMode := v1.PersistentVolumeFilesystem
if pvSpec.VolumeMode != nil {
pvVolumeMode = *pvSpec.VolumeMode
}
return requestedVolumeMode != pvVolumeMode, nil
}
// CheckAccessModes returns true if PV satisfies all the PVC's requested AccessModes
func CheckAccessModes(claim *v1.PersistentVolumeClaim, volume *v1.PersistentVolume) bool {
pvModesMap := map[v1.PersistentVolumeAccessMode]bool{}
for _, mode := range volume.Spec.AccessModes {
pvModesMap[mode] = true
}
for _, mode := range claim.Spec.AccessModes {
_, ok := pvModesMap[mode]
if !ok {
return false
}
}
return true
}
func claimToClaimKey(claim *v1.PersistentVolumeClaim) string {
return fmt.Sprintf("%s/%s", claim.Namespace, claim.Name)
}
// GetVolumeNodeAffinity returns a VolumeNodeAffinity for given key and value.
func GetVolumeNodeAffinity(key string, value string) *v1.VolumeNodeAffinity {
return &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{
{
MatchExpressions: []v1.NodeSelectorRequirement{
{
Key: key,
Operator: v1.NodeSelectorOpIn,
Values: []string{value},
},
},
},
},
},
}
}
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"scheduler_assume_cache.go",
"scheduler_bind_cache_metrics.go",
"scheduler_binder.go",
"scheduler_binder_cache.go",
"scheduler_binder_fake.go",
],
importpath = "k8s.io/kubernetes/pkg/controller/volume/scheduling",
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/controller/volume/persistentvolume/util:go_default_library",
"//pkg/volume/util:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apiserver/pkg/storage/etcd:go_default_library",
"//staging/src/k8s.io/client-go/informers/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/informers/storage/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/listers/storage/v1:go_default_library",
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"scheduler_assume_cache_test.go",
"scheduler_binder_cache_test.go",
"scheduler_binder_test.go",
],
embed = [":go_default_library"],
deps = [
"//pkg/api/testapi:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/controller/volume/persistentvolume/testing:go_default_library",
"//pkg/controller/volume/persistentvolume/util:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/storage/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library",
"//staging/src/k8s.io/client-go/informers/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/testing:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package persistentvolume package scheduling
import ( import (
"fmt" "fmt"
......
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package persistentvolume package scheduling
import ( import (
"fmt" "fmt"
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/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 { func makePV(name, version, storageClass string) *v1.PersistentVolume {
...@@ -456,7 +457,7 @@ func TestAssumeUpdatePVCCache(t *testing.T) { ...@@ -456,7 +457,7 @@ func TestAssumeUpdatePVCCache(t *testing.T) {
// Assume PVC // Assume PVC
newPVC := pvc.DeepCopy() newPVC := pvc.DeepCopy()
newPVC.Annotations[annSelectedNode] = "test-node" newPVC.Annotations[pvutil.AnnSelectedNode] = "test-node"
if err := cache.Assume(newPVC); err != nil { if err := cache.Assume(newPVC); err != nil {
t.Fatalf("failed to assume PVC: %v", err) t.Fatalf("failed to assume PVC: %v", err)
} }
......
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package persistentvolume package scheduling
import ( import (
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
......
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package persistentvolume package scheduling
import ( import (
"fmt" "fmt"
...@@ -32,6 +32,7 @@ import ( ...@@ -32,6 +32,7 @@ import (
storagelisters "k8s.io/client-go/listers/storage/v1" storagelisters "k8s.io/client-go/listers/storage/v1"
"k8s.io/klog" "k8s.io/klog"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
volumeutil "k8s.io/kubernetes/pkg/volume/util" volumeutil "k8s.io/kubernetes/pkg/volume/util"
) )
...@@ -211,7 +212,7 @@ func (b *volumeBinder) FindPodVolumes(pod *v1.Pod, node *v1.Node) (unboundVolume ...@@ -211,7 +212,7 @@ func (b *volumeBinder) FindPodVolumes(pod *v1.Pod, node *v1.Node) (unboundVolume
// Filter out claims to provision // Filter out claims to provision
for _, claim := range claimsToBind { for _, claim := range claimsToBind {
if selectedNode, ok := claim.Annotations[annSelectedNode]; ok { if selectedNode, ok := claim.Annotations[pvutil.AnnSelectedNode]; ok {
if selectedNode != node.Name { if selectedNode != node.Name {
// Fast path, skip unmatched node // Fast path, skip unmatched node
return false, boundVolumesSatisfied, nil return false, boundVolumesSatisfied, nil
...@@ -274,7 +275,7 @@ func (b *volumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string) (al ...@@ -274,7 +275,7 @@ func (b *volumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string) (al
// Assume PV // Assume PV
newBindings := []*bindingInfo{} newBindings := []*bindingInfo{}
for _, binding := range claimsToBind { for _, binding := range claimsToBind {
newPV, dirty, err := GetBindVolumeToClaim(binding.pv, binding.pvc) newPV, dirty, err := pvutil.GetBindVolumeToClaim(binding.pv, binding.pvc)
klog.V(5).Infof("AssumePodVolumes: GetBindVolumeToClaim for pod %q, PV %q, PVC %q. newPV %p, dirty %v, err: %v", klog.V(5).Infof("AssumePodVolumes: GetBindVolumeToClaim for pod %q, PV %q, PVC %q. newPV %p, dirty %v, err: %v",
podName, podName,
binding.pv.Name, binding.pv.Name,
...@@ -303,7 +304,7 @@ func (b *volumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string) (al ...@@ -303,7 +304,7 @@ func (b *volumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string) (al
// The claims from method args can be pointing to watcher cache. We must not // The claims from method args can be pointing to watcher cache. We must not
// modify these, therefore create a copy. // modify these, therefore create a copy.
claimClone := claim.DeepCopy() claimClone := claim.DeepCopy()
metav1.SetMetaDataAnnotation(&claimClone.ObjectMeta, annSelectedNode, nodeName) metav1.SetMetaDataAnnotation(&claimClone.ObjectMeta, pvutil.AnnSelectedNode, nodeName)
err = b.pvcCache.Assume(claimClone) err = b.pvcCache.Assume(claimClone)
if err != nil { if err != nil {
b.revertAssumedPVs(newBindings) b.revertAssumedPVs(newBindings)
...@@ -511,7 +512,7 @@ func (b *volumeBinder) checkBindings(pod *v1.Pod, bindings []*bindingInfo, claim ...@@ -511,7 +512,7 @@ func (b *volumeBinder) checkBindings(pod *v1.Pod, bindings []*bindingInfo, claim
if pvc.Annotations == nil { if pvc.Annotations == nil {
return false, fmt.Errorf("selectedNode annotation reset for PVC %q", pvc.Name) return false, fmt.Errorf("selectedNode annotation reset for PVC %q", pvc.Name)
} }
selectedNode := pvc.Annotations[annSelectedNode] selectedNode := pvc.Annotations[pvutil.AnnSelectedNode]
if selectedNode != pod.Spec.NodeName { if selectedNode != pod.Spec.NodeName {
return false, fmt.Errorf("selectedNode annotation value %q not set to scheduled node %q", selectedNode, pod.Spec.NodeName) return false, fmt.Errorf("selectedNode annotation value %q not set to scheduled node %q", selectedNode, pod.Spec.NodeName)
} }
...@@ -582,7 +583,7 @@ func (b *volumeBinder) isPVCBound(namespace, pvcName string) (bool, *v1.Persiste ...@@ -582,7 +583,7 @@ func (b *volumeBinder) isPVCBound(namespace, pvcName string) (bool, *v1.Persiste
} }
func (b *volumeBinder) isPVCFullyBound(pvc *v1.PersistentVolumeClaim) bool { func (b *volumeBinder) isPVCFullyBound(pvc *v1.PersistentVolumeClaim) bool {
return pvc.Spec.VolumeName != "" && metav1.HasAnnotation(pvc.ObjectMeta, annBindCompleted) return pvc.Spec.VolumeName != "" && metav1.HasAnnotation(pvc.ObjectMeta, pvutil.AnnBindCompleted)
} }
// arePodVolumesBound returns true if all volumes are fully bound // arePodVolumesBound returns true if all volumes are fully bound
...@@ -614,7 +615,7 @@ func (b *volumeBinder) getPodVolumes(pod *v1.Pod) (boundClaims []*v1.PersistentV ...@@ -614,7 +615,7 @@ func (b *volumeBinder) getPodVolumes(pod *v1.Pod) (boundClaims []*v1.PersistentV
if volumeBound { if volumeBound {
boundClaims = append(boundClaims, pvc) boundClaims = append(boundClaims, pvc)
} else { } else {
delayBindingMode, err := IsDelayBindingMode(pvc, b.classLister) delayBindingMode, err := pvutil.IsDelayBindingMode(pvc, b.classLister)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
...@@ -674,7 +675,7 @@ func (b *volumeBinder) findMatchingVolumes(pod *v1.Pod, claimsToBind []*v1.Persi ...@@ -674,7 +675,7 @@ func (b *volumeBinder) findMatchingVolumes(pod *v1.Pod, claimsToBind []*v1.Persi
pvcName := getPVCName(pvc) pvcName := getPVCName(pvc)
// Find a matching PV // Find a matching PV
pv, err := findMatchingVolume(pvc, allPVs, node, chosenPVs, true) pv, err := pvutil.FindMatchingVolume(pvc, allPVs, node, chosenPVs, true)
if err != nil { if err != nil {
return false, nil, nil, err return false, nil, nil, err
} }
...@@ -717,7 +718,7 @@ func (b *volumeBinder) checkVolumeProvisions(pod *v1.Pod, claimsToProvision []*v ...@@ -717,7 +718,7 @@ func (b *volumeBinder) checkVolumeProvisions(pod *v1.Pod, claimsToProvision []*v
return false, nil, fmt.Errorf("failed to find storage class %q", className) return false, nil, fmt.Errorf("failed to find storage class %q", className)
} }
provisioner := class.Provisioner provisioner := class.Provisioner
if provisioner == "" || provisioner == notSupportedProvisioner { if provisioner == "" || provisioner == pvutil.NotSupportedProvisioner {
klog.V(4).Infof("storage class %q of claim %q does not support dynamic provisioning", className, pvcName) klog.V(4).Infof("storage class %q of claim %q does not support dynamic provisioning", className, pvcName)
return false, nil, nil return false, nil, nil
} }
...@@ -775,3 +776,7 @@ func (a byPVCSize) Less(i, j int) bool { ...@@ -775,3 +776,7 @@ func (a byPVCSize) Less(i, j int) bool {
// return true if iSize is less than jSize // return true if iSize is less than jSize
return iSize.Cmp(jSize) == -1 return iSize.Cmp(jSize) == -1
} }
func claimToClaimKey(claim *v1.PersistentVolumeClaim) string {
return fmt.Sprintf("%s/%s", claim.Namespace, claim.Name)
}
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package persistentvolume package scheduling
import ( import (
"sync" "sync"
......
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package persistentvolume package scheduling
import ( import (
"reflect" "reflect"
......
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package persistentvolume package scheduling
import "k8s.io/api/core/v1" import "k8s.io/api/core/v1"
......
...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and ...@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package persistentvolume package scheduling
import ( import (
"context" "context"
...@@ -39,6 +39,8 @@ import ( ...@@ -39,6 +39,8 @@ import (
"k8s.io/klog" "k8s.io/klog"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
pvtesting "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/testing"
pvutil "k8s.io/kubernetes/pkg/controller/volume/persistentvolume/util"
) )
var ( var (
...@@ -97,7 +99,7 @@ var ( ...@@ -97,7 +99,7 @@ var (
type testEnv struct { type testEnv struct {
client clientset.Interface client clientset.Interface
reactor *volumeReactor reactor *pvtesting.VolumeReactor
binder SchedulerVolumeBinder binder SchedulerVolumeBinder
internalBinder *volumeBinder internalBinder *volumeBinder
internalNodeInformer coreinformers.NodeInformer internalNodeInformer coreinformers.NodeInformer
...@@ -107,7 +109,7 @@ type testEnv struct { ...@@ -107,7 +109,7 @@ type testEnv struct {
func newTestBinder(t *testing.T, stopCh <-chan struct{}) *testEnv { func newTestBinder(t *testing.T, stopCh <-chan struct{}) *testEnv {
client := &fake.Clientset{} client := &fake.Clientset{}
reactor := newVolumeReactor(client, nil, nil, nil, nil) reactor := pvtesting.NewVolumeReactor(client, nil, nil, nil)
// TODO refactor all tests to use real watch mechanism, see #72327 // TODO refactor all tests to use real watch mechanism, see #72327
client.AddWatchReactor("*", func(action k8stesting.Action) (handled bool, ret watch.Interface, err error) { client.AddWatchReactor("*", func(action k8stesting.Action) (handled bool, ret watch.Interface, err error) {
gvr := action.GetResource() gvr := action.GetResource()
...@@ -238,11 +240,11 @@ func (env *testEnv) initClaims(cachedPVCs []*v1.PersistentVolumeClaim, apiPVCs [ ...@@ -238,11 +240,11 @@ func (env *testEnv) initClaims(cachedPVCs []*v1.PersistentVolumeClaim, apiPVCs [
for _, pvc := range cachedPVCs { for _, pvc := range cachedPVCs {
internalPVCCache.add(pvc) internalPVCCache.add(pvc)
if apiPVCs == nil { if apiPVCs == nil {
env.reactor.claims[pvc.Name] = pvc env.reactor.AddClaim(pvc)
} }
} }
for _, pvc := range apiPVCs { for _, pvc := range apiPVCs {
env.reactor.claims[pvc.Name] = pvc env.reactor.AddClaim(pvc)
} }
} }
...@@ -251,11 +253,11 @@ func (env *testEnv) initVolumes(cachedPVs []*v1.PersistentVolume, apiPVs []*v1.P ...@@ -251,11 +253,11 @@ func (env *testEnv) initVolumes(cachedPVs []*v1.PersistentVolume, apiPVs []*v1.P
for _, pv := range cachedPVs { for _, pv := range cachedPVs {
internalPVCache.add(pv) internalPVCache.add(pv)
if apiPVs == nil { if apiPVs == nil {
env.reactor.volumes[pv.Name] = pv env.reactor.AddVolume(pv)
} }
} }
for _, pv := range apiPVs { for _, pv := range apiPVs {
env.reactor.volumes[pv.Name] = pv env.reactor.AddVolume(pv)
} }
} }
...@@ -421,8 +423,8 @@ func (env *testEnv) validateAssume(t *testing.T, name string, pod *v1.Pod, bindi ...@@ -421,8 +423,8 @@ func (env *testEnv) validateAssume(t *testing.T, name string, pod *v1.Pod, bindi
t.Errorf("Test %q failed: GetPVC %q returned error: %v", name, pvcKey, err) t.Errorf("Test %q failed: GetPVC %q returned error: %v", name, pvcKey, err)
continue continue
} }
if pvc.Annotations[annSelectedNode] != nodeLabelValue { if pvc.Annotations[pvutil.AnnSelectedNode] != nodeLabelValue {
t.Errorf("Test %q failed: expected annSelectedNode of pvc %q to be %q, but got %q", name, pvcKey, nodeLabelValue, pvc.Annotations[annSelectedNode]) t.Errorf("Test %q failed: expected pvutil.AnnSelectedNode of pvc %q to be %q, but got %q", name, pvcKey, nodeLabelValue, pvc.Annotations[pvutil.AnnSelectedNode])
} }
} }
} }
...@@ -447,8 +449,8 @@ func (env *testEnv) validateFailedAssume(t *testing.T, name string, pod *v1.Pod, ...@@ -447,8 +449,8 @@ func (env *testEnv) validateFailedAssume(t *testing.T, name string, pod *v1.Pod,
t.Errorf("Test %q failed: GetPVC %q returned error: %v", name, pvcKey, err) t.Errorf("Test %q failed: GetPVC %q returned error: %v", name, pvcKey, err)
continue continue
} }
if pvc.Annotations[annSelectedNode] != "" { if pvc.Annotations[pvutil.AnnSelectedNode] != "" {
t.Errorf("Test %q failed: expected annSelectedNode of pvc %q empty, but got %q", name, pvcKey, pvc.Annotations[annSelectedNode]) t.Errorf("Test %q failed: expected pvutil.AnnSelectedNode of pvc %q empty, but got %q", name, pvcKey, pvc.Annotations[pvutil.AnnSelectedNode])
} }
} }
} }
...@@ -476,7 +478,7 @@ func (env *testEnv) validateBind( ...@@ -476,7 +478,7 @@ func (env *testEnv) validateBind(
} }
// Check reactor for API updates // Check reactor for API updates
if err := env.reactor.checkVolumes(expectedAPIPVs); err != nil { if err := env.reactor.CheckVolumes(expectedAPIPVs); err != nil {
t.Errorf("Test %q failed: API reactor validation failed: %v", name, err) t.Errorf("Test %q failed: API reactor validation failed: %v", name, err)
} }
} }
...@@ -504,7 +506,7 @@ func (env *testEnv) validateProvision( ...@@ -504,7 +506,7 @@ func (env *testEnv) validateProvision(
} }
// Check reactor for API updates // Check reactor for API updates
if err := env.reactor.checkClaims(expectedAPIPVCs); err != nil { if err := env.reactor.CheckClaims(expectedAPIPVCs); err != nil {
t.Errorf("Test %q failed: API reactor validation failed: %v", name, err) t.Errorf("Test %q failed: API reactor validation failed: %v", name, err)
} }
} }
...@@ -543,10 +545,10 @@ func makeTestPVC(name, size, node string, pvcBoundState int, pvName, resourceVer ...@@ -543,10 +545,10 @@ func makeTestPVC(name, size, node string, pvcBoundState int, pvName, resourceVer
switch pvcBoundState { switch pvcBoundState {
case pvcSelectedNode: case pvcSelectedNode:
metav1.SetMetaDataAnnotation(&pvc.ObjectMeta, annSelectedNode, node) metav1.SetMetaDataAnnotation(&pvc.ObjectMeta, pvutil.AnnSelectedNode, node)
// don't fallthrough // don't fallthrough
case pvcBound: case pvcBound:
metav1.SetMetaDataAnnotation(&pvc.ObjectMeta, annBindCompleted, "yes") metav1.SetMetaDataAnnotation(&pvc.ObjectMeta, pvutil.AnnBindCompleted, "yes")
fallthrough fallthrough
case pvcPrebound: case pvcPrebound:
pvc.Spec.VolumeName = pvName pvc.Spec.VolumeName = pvName
...@@ -595,7 +597,7 @@ func makeTestPV(name, node, capacity, version string, boundToPVC *v1.PersistentV ...@@ -595,7 +597,7 @@ func makeTestPV(name, node, capacity, version string, boundToPVC *v1.PersistentV
}, },
} }
if node != "" { if node != "" {
pv.Spec.NodeAffinity = getVolumeNodeAffinity(nodeLabelKey, node) pv.Spec.NodeAffinity = pvutil.GetVolumeNodeAffinity(nodeLabelKey, node)
} }
if boundToPVC != nil { if boundToPVC != nil {
...@@ -607,7 +609,7 @@ func makeTestPV(name, node, capacity, version string, boundToPVC *v1.PersistentV ...@@ -607,7 +609,7 @@ func makeTestPV(name, node, capacity, version string, boundToPVC *v1.PersistentV
Namespace: boundToPVC.Namespace, Namespace: boundToPVC.Namespace,
UID: boundToPVC.UID, UID: boundToPVC.UID,
} }
metav1.SetMetaDataAnnotation(&pv.ObjectMeta, annBoundByController, "yes") metav1.SetMetaDataAnnotation(&pv.ObjectMeta, pvutil.AnnBoundByController, "yes")
} }
return pv return pv
...@@ -615,7 +617,7 @@ func makeTestPV(name, node, capacity, version string, boundToPVC *v1.PersistentV ...@@ -615,7 +617,7 @@ func makeTestPV(name, node, capacity, version string, boundToPVC *v1.PersistentV
func pvcSetSelectedNode(pvc *v1.PersistentVolumeClaim, node string) *v1.PersistentVolumeClaim { func pvcSetSelectedNode(pvc *v1.PersistentVolumeClaim, node string) *v1.PersistentVolumeClaim {
newPVC := pvc.DeepCopy() newPVC := pvc.DeepCopy()
metav1.SetMetaDataAnnotation(&newPVC.ObjectMeta, annSelectedNode, node) metav1.SetMetaDataAnnotation(&newPVC.ObjectMeta, pvutil.AnnSelectedNode, node)
return newPVC return newPVC
} }
...@@ -691,7 +693,7 @@ func makeBinding(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume) *bindin ...@@ -691,7 +693,7 @@ func makeBinding(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume) *bindin
func addProvisionAnn(pvc *v1.PersistentVolumeClaim) *v1.PersistentVolumeClaim { func addProvisionAnn(pvc *v1.PersistentVolumeClaim) *v1.PersistentVolumeClaim {
res := pvc.DeepCopy() res := pvc.DeepCopy()
// Add provision related annotations // Add provision related annotations
metav1.SetMetaDataAnnotation(&res.ObjectMeta, annSelectedNode, nodeLabelValue) metav1.SetMetaDataAnnotation(&res.ObjectMeta, pvutil.AnnSelectedNode, nodeLabelValue)
return res return res
} }
...@@ -1488,7 +1490,7 @@ func TestBindPodVolumes(t *testing.T) { ...@@ -1488,7 +1490,7 @@ func TestBindPodVolumes(t *testing.T) {
// Update PVC to be fully bound to PV // Update PVC to be fully bound to PV
newPVC := pvc.DeepCopy() newPVC := pvc.DeepCopy()
newPVC.Spec.VolumeName = pv.Name newPVC.Spec.VolumeName = pv.Name
metav1.SetMetaDataAnnotation(&newPVC.ObjectMeta, annBindCompleted, "yes") metav1.SetMetaDataAnnotation(&newPVC.ObjectMeta, pvutil.AnnBindCompleted, "yes")
if _, err := testEnv.client.CoreV1().PersistentVolumeClaims(newPVC.Namespace).Update(newPVC); err != nil { if _, err := testEnv.client.CoreV1().PersistentVolumeClaims(newPVC.Namespace).Update(newPVC); err != nil {
t.Errorf("failed to update PVC %q: %v", newPVC.Name, err) t.Errorf("failed to update PVC %q: %v", newPVC.Name, err)
} }
...@@ -1512,7 +1514,7 @@ func TestBindPodVolumes(t *testing.T) { ...@@ -1512,7 +1514,7 @@ func TestBindPodVolumes(t *testing.T) {
return return
} }
newPVC.Spec.VolumeName = dynamicPV.Name newPVC.Spec.VolumeName = dynamicPV.Name
metav1.SetMetaDataAnnotation(&newPVC.ObjectMeta, annBindCompleted, "yes") metav1.SetMetaDataAnnotation(&newPVC.ObjectMeta, pvutil.AnnBindCompleted, "yes")
if _, err := testEnv.client.CoreV1().PersistentVolumeClaims(newPVC.Namespace).Update(newPVC); err != nil { if _, err := testEnv.client.CoreV1().PersistentVolumeClaims(newPVC.Namespace).Update(newPVC); err != nil {
t.Errorf("failed to update PVC %q: %v", newPVC.Name, err) t.Errorf("failed to update PVC %q: %v", newPVC.Name, err)
} }
...@@ -1588,7 +1590,7 @@ func TestBindPodVolumes(t *testing.T) { ...@@ -1588,7 +1590,7 @@ func TestBindPodVolumes(t *testing.T) {
// Update PVC to be fully bound to a PV with a different node // Update PVC to be fully bound to a PV with a different node
newPVC := pvcs[0].DeepCopy() newPVC := pvcs[0].DeepCopy()
newPVC.Spec.VolumeName = pvNode2.Name newPVC.Spec.VolumeName = pvNode2.Name
metav1.SetMetaDataAnnotation(&newPVC.ObjectMeta, annBindCompleted, "yes") metav1.SetMetaDataAnnotation(&newPVC.ObjectMeta, pvutil.AnnBindCompleted, "yes")
if _, err := testEnv.client.CoreV1().PersistentVolumeClaims(newPVC.Namespace).Update(newPVC); err != nil { if _, err := testEnv.client.CoreV1().PersistentVolumeClaims(newPVC.Namespace).Update(newPVC); err != nil {
t.Errorf("failed to update PVC %q: %v", newPVC.Name, err) t.Errorf("failed to update PVC %q: %v", newPVC.Name, err)
} }
......
...@@ -49,8 +49,7 @@ go_test( ...@@ -49,8 +49,7 @@ go_test(
], ],
embed = [":go_default_library"], embed = [":go_default_library"],
deps = [ deps = [
"//pkg/api/legacyscheme:go_default_library", "//pkg/controller/volume/scheduling:go_default_library",
"//pkg/controller/volume/persistentvolume:go_default_library",
"//pkg/scheduler/algorithm:go_default_library", "//pkg/scheduler/algorithm:go_default_library",
"//pkg/scheduler/algorithm/predicates:go_default_library", "//pkg/scheduler/algorithm/predicates:go_default_library",
"//pkg/scheduler/algorithm/priorities:go_default_library", "//pkg/scheduler/algorithm/priorities:go_default_library",
...@@ -75,6 +74,7 @@ go_test( ...@@ -75,6 +74,7 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library", "//staging/src/k8s.io/client-go/informers:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library", "//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/scheme:go_default_library",
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/tools/cache:go_default_library", "//staging/src/k8s.io/client-go/tools/cache:go_default_library",
"//staging/src/k8s.io/client-go/tools/record:go_default_library", "//staging/src/k8s.io/client-go/tools/record:go_default_library",
......
...@@ -10,7 +10,7 @@ go_library( ...@@ -10,7 +10,7 @@ go_library(
], ],
importpath = "k8s.io/kubernetes/pkg/scheduler/metrics", importpath = "k8s.io/kubernetes/pkg/scheduler/metrics",
deps = [ deps = [
"//pkg/controller/volume/persistentvolume:go_default_library", "//pkg/controller/volume/scheduling:go_default_library",
"//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
], ],
) )
......
...@@ -21,7 +21,7 @@ import ( ...@@ -21,7 +21,7 @@ import (
"time" "time"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"k8s.io/kubernetes/pkg/controller/volume/persistentvolume" volumescheduling "k8s.io/kubernetes/pkg/controller/volume/scheduling"
) )
const ( const (
...@@ -234,7 +234,7 @@ func Register() { ...@@ -234,7 +234,7 @@ func Register() {
prometheus.MustRegister(metric) prometheus.MustRegister(metric)
} }
persistentvolume.RegisterVolumeSchedulingMetrics() volumescheduling.RegisterVolumeSchedulingMetrics()
}) })
} }
......
...@@ -37,11 +37,11 @@ import ( ...@@ -37,11 +37,11 @@ import (
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/informers" "k8s.io/client-go/informers"
clientsetfake "k8s.io/client-go/kubernetes/fake" clientsetfake "k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/kubernetes/scheme"
corelister "k8s.io/client-go/listers/core/v1" corelister "k8s.io/client-go/listers/core/v1"
clientcache "k8s.io/client-go/tools/cache" clientcache "k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/record" "k8s.io/client-go/tools/record"
"k8s.io/kubernetes/pkg/api/legacyscheme" volumescheduling "k8s.io/kubernetes/pkg/controller/volume/scheduling"
"k8s.io/kubernetes/pkg/controller/volume/persistentvolume"
"k8s.io/kubernetes/pkg/scheduler/algorithm" "k8s.io/kubernetes/pkg/scheduler/algorithm"
"k8s.io/kubernetes/pkg/scheduler/algorithm/predicates" "k8s.io/kubernetes/pkg/scheduler/algorithm/predicates"
"k8s.io/kubernetes/pkg/scheduler/algorithm/priorities" "k8s.io/kubernetes/pkg/scheduler/algorithm/priorities"
...@@ -194,7 +194,7 @@ func TestSchedulerCreation(t *testing.T) { ...@@ -194,7 +194,7 @@ func TestSchedulerCreation(t *testing.T) {
informerFactory.Core().V1().Services(), informerFactory.Core().V1().Services(),
informerFactory.Policy().V1beta1().PodDisruptionBudgets(), informerFactory.Policy().V1beta1().PodDisruptionBudgets(),
informerFactory.Storage().V1().StorageClasses(), informerFactory.Storage().V1().StorageClasses(),
eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: "scheduler"}), eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "scheduler"}),
kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &testSource}, kubeschedulerconfig.SchedulerAlgorithmSource{Provider: &testSource},
stopCh, stopCh,
EmptyPluginRegistry, EmptyPluginRegistry,
...@@ -302,8 +302,8 @@ func TestScheduler(t *testing.T) { ...@@ -302,8 +302,8 @@ func TestScheduler(t *testing.T) {
return item.sendPod return item.sendPod
}, },
Framework: fwk, Framework: fwk,
Recorder: eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: "scheduler"}), Recorder: eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "scheduler"}),
VolumeBinder: volumebinder.NewFakeVolumeBinder(&persistentvolume.FakeVolumeBinderConfig{AllBound: true}), VolumeBinder: volumebinder.NewFakeVolumeBinder(&volumescheduling.FakeVolumeBinderConfig{AllBound: true}),
}) })
called := make(chan struct{}) called := make(chan struct{})
events := eventBroadcaster.StartEventWatcher(func(e *v1.Event) { events := eventBroadcaster.StartEventWatcher(func(e *v1.Event) {
...@@ -679,7 +679,7 @@ func setupTestScheduler(queuedPodStore *clientcache.FIFO, scache internalcache.C ...@@ -679,7 +679,7 @@ func setupTestScheduler(queuedPodStore *clientcache.FIFO, scache internalcache.C
PodConditionUpdater: fakePodConditionUpdater{}, PodConditionUpdater: fakePodConditionUpdater{},
PodPreemptor: fakePodPreemptor{}, PodPreemptor: fakePodPreemptor{},
Framework: framework, Framework: framework,
VolumeBinder: volumebinder.NewFakeVolumeBinder(&persistentvolume.FakeVolumeBinderConfig{AllBound: true}), VolumeBinder: volumebinder.NewFakeVolumeBinder(&volumescheduling.FakeVolumeBinderConfig{AllBound: true}),
} }
if recorder != nil { if recorder != nil {
...@@ -736,7 +736,7 @@ func setupTestSchedulerLongBindingWithRetry(queuedPodStore *clientcache.FIFO, sc ...@@ -736,7 +736,7 @@ func setupTestSchedulerLongBindingWithRetry(queuedPodStore *clientcache.FIFO, sc
PodPreemptor: fakePodPreemptor{}, PodPreemptor: fakePodPreemptor{},
StopEverything: stop, StopEverything: stop,
Framework: framework, Framework: framework,
VolumeBinder: volumebinder.NewFakeVolumeBinder(&persistentvolume.FakeVolumeBinderConfig{AllBound: true}), VolumeBinder: volumebinder.NewFakeVolumeBinder(&volumescheduling.FakeVolumeBinderConfig{AllBound: true}),
}) })
return sched, bindingChan return sched, bindingChan
...@@ -760,7 +760,7 @@ func setupTestSchedulerWithVolumeBinding(fakeVolumeBinder *volumebinder.VolumeBi ...@@ -760,7 +760,7 @@ func setupTestSchedulerWithVolumeBinding(fakeVolumeBinder *volumebinder.VolumeBi
predicates.CheckVolumeBindingPred: predicates.NewVolumeBindingPredicate(fakeVolumeBinder), predicates.CheckVolumeBindingPred: predicates.NewVolumeBindingPredicate(fakeVolumeBinder),
} }
recorder := broadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: "scheduler"}) recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "scheduler"})
s, bindingChan, errChan := setupTestScheduler(queuedPodStore, scache, informerFactory, predicateMap, recorder) s, bindingChan, errChan := setupTestScheduler(queuedPodStore, scache, informerFactory, predicateMap, recorder)
informerFactory.Start(stop) informerFactory.Start(stop)
informerFactory.WaitForCacheSync(stop) informerFactory.WaitForCacheSync(stop)
...@@ -794,11 +794,11 @@ func TestSchedulerWithVolumeBinding(t *testing.T) { ...@@ -794,11 +794,11 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
expectAssumeCalled bool expectAssumeCalled bool
expectBindCalled bool expectBindCalled bool
eventReason string eventReason string
volumeBinderConfig *persistentvolume.FakeVolumeBinderConfig volumeBinderConfig *volumescheduling.FakeVolumeBinderConfig
}{ }{
{ {
name: "all bound", name: "all bound",
volumeBinderConfig: &persistentvolume.FakeVolumeBinderConfig{ volumeBinderConfig: &volumescheduling.FakeVolumeBinderConfig{
AllBound: true, AllBound: true,
FindUnboundSatsified: true, FindUnboundSatsified: true,
FindBoundSatsified: true, FindBoundSatsified: true,
...@@ -809,7 +809,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) { ...@@ -809,7 +809,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
}, },
{ {
name: "bound/invalid pv affinity", name: "bound/invalid pv affinity",
volumeBinderConfig: &persistentvolume.FakeVolumeBinderConfig{ volumeBinderConfig: &volumescheduling.FakeVolumeBinderConfig{
AllBound: true, AllBound: true,
FindUnboundSatsified: true, FindUnboundSatsified: true,
FindBoundSatsified: false, FindBoundSatsified: false,
...@@ -819,7 +819,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) { ...@@ -819,7 +819,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
}, },
{ {
name: "unbound/no matches", name: "unbound/no matches",
volumeBinderConfig: &persistentvolume.FakeVolumeBinderConfig{ volumeBinderConfig: &volumescheduling.FakeVolumeBinderConfig{
FindUnboundSatsified: false, FindUnboundSatsified: false,
FindBoundSatsified: true, FindBoundSatsified: true,
}, },
...@@ -828,7 +828,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) { ...@@ -828,7 +828,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
}, },
{ {
name: "bound and unbound unsatisfied", name: "bound and unbound unsatisfied",
volumeBinderConfig: &persistentvolume.FakeVolumeBinderConfig{ volumeBinderConfig: &volumescheduling.FakeVolumeBinderConfig{
FindUnboundSatsified: false, FindUnboundSatsified: false,
FindBoundSatsified: false, FindBoundSatsified: false,
}, },
...@@ -837,7 +837,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) { ...@@ -837,7 +837,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
}, },
{ {
name: "unbound/found matches/bind succeeds", name: "unbound/found matches/bind succeeds",
volumeBinderConfig: &persistentvolume.FakeVolumeBinderConfig{ volumeBinderConfig: &volumescheduling.FakeVolumeBinderConfig{
FindUnboundSatsified: true, FindUnboundSatsified: true,
FindBoundSatsified: true, FindBoundSatsified: true,
}, },
...@@ -848,7 +848,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) { ...@@ -848,7 +848,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
}, },
{ {
name: "predicate error", name: "predicate error",
volumeBinderConfig: &persistentvolume.FakeVolumeBinderConfig{ volumeBinderConfig: &volumescheduling.FakeVolumeBinderConfig{
FindErr: findErr, FindErr: findErr,
}, },
eventReason: "FailedScheduling", eventReason: "FailedScheduling",
...@@ -856,7 +856,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) { ...@@ -856,7 +856,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
}, },
{ {
name: "assume error", name: "assume error",
volumeBinderConfig: &persistentvolume.FakeVolumeBinderConfig{ volumeBinderConfig: &volumescheduling.FakeVolumeBinderConfig{
FindUnboundSatsified: true, FindUnboundSatsified: true,
FindBoundSatsified: true, FindBoundSatsified: true,
AssumeErr: assumeErr, AssumeErr: assumeErr,
...@@ -867,7 +867,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) { ...@@ -867,7 +867,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
}, },
{ {
name: "bind error", name: "bind error",
volumeBinderConfig: &persistentvolume.FakeVolumeBinderConfig{ volumeBinderConfig: &volumescheduling.FakeVolumeBinderConfig{
FindUnboundSatsified: true, FindUnboundSatsified: true,
FindBoundSatsified: true, FindBoundSatsified: true,
BindErr: bindErr, BindErr: bindErr,
...@@ -883,7 +883,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) { ...@@ -883,7 +883,7 @@ func TestSchedulerWithVolumeBinding(t *testing.T) {
t.Run(item.name, func(t *testing.T) { t.Run(item.name, func(t *testing.T) {
stop := make(chan struct{}) stop := make(chan struct{})
fakeVolumeBinder := volumebinder.NewFakeVolumeBinder(item.volumeBinderConfig) fakeVolumeBinder := volumebinder.NewFakeVolumeBinder(item.volumeBinderConfig)
internalBinder, ok := fakeVolumeBinder.Binder.(*persistentvolume.FakeVolumeBinder) internalBinder, ok := fakeVolumeBinder.Binder.(*volumescheduling.FakeVolumeBinder)
if !ok { if !ok {
t.Fatalf("Failed to get fake volume binder") t.Fatalf("Failed to get fake volume binder")
} }
......
...@@ -6,7 +6,7 @@ go_library( ...@@ -6,7 +6,7 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/scheduler/volumebinder", importpath = "k8s.io/kubernetes/pkg/scheduler/volumebinder",
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
deps = [ deps = [
"//pkg/controller/volume/persistentvolume:go_default_library", "//pkg/controller/volume/scheduling:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library", "//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/informers/core/v1:go_default_library", "//staging/src/k8s.io/client-go/informers/core/v1:go_default_library",
"//staging/src/k8s.io/client-go/informers/storage/v1:go_default_library", "//staging/src/k8s.io/client-go/informers/storage/v1:go_default_library",
......
...@@ -23,12 +23,12 @@ import ( ...@@ -23,12 +23,12 @@ import (
coreinformers "k8s.io/client-go/informers/core/v1" coreinformers "k8s.io/client-go/informers/core/v1"
storageinformers "k8s.io/client-go/informers/storage/v1" storageinformers "k8s.io/client-go/informers/storage/v1"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/controller/volume/persistentvolume" volumescheduling "k8s.io/kubernetes/pkg/controller/volume/scheduling"
) )
// VolumeBinder sets up the volume binding library // VolumeBinder sets up the volume binding library
type VolumeBinder struct { type VolumeBinder struct {
Binder persistentvolume.SchedulerVolumeBinder Binder volumescheduling.SchedulerVolumeBinder
} }
// NewVolumeBinder sets up the volume binding library and binding queue // NewVolumeBinder sets up the volume binding library and binding queue
...@@ -41,14 +41,14 @@ func NewVolumeBinder( ...@@ -41,14 +41,14 @@ func NewVolumeBinder(
bindTimeout time.Duration) *VolumeBinder { bindTimeout time.Duration) *VolumeBinder {
return &VolumeBinder{ return &VolumeBinder{
Binder: persistentvolume.NewVolumeBinder(client, nodeInformer, pvcInformer, pvInformer, storageClassInformer, bindTimeout), Binder: volumescheduling.NewVolumeBinder(client, nodeInformer, pvcInformer, pvInformer, storageClassInformer, bindTimeout),
} }
} }
// NewFakeVolumeBinder sets up a fake volume binder and binding queue // NewFakeVolumeBinder sets up a fake volume binder and binding queue
func NewFakeVolumeBinder(config *persistentvolume.FakeVolumeBinderConfig) *VolumeBinder { func NewFakeVolumeBinder(config *volumescheduling.FakeVolumeBinderConfig) *VolumeBinder {
return &VolumeBinder{ return &VolumeBinder{
Binder: persistentvolume.NewFakeVolumeBinder(config), Binder: volumescheduling.NewFakeVolumeBinder(config),
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment