mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Add volume operation metrics to operation executor and PV controller
This commit is contained in:
		@@ -24,6 +24,7 @@ go_library(
 | 
				
			|||||||
        "//pkg/util/io:go_default_library",
 | 
					        "//pkg/util/io:go_default_library",
 | 
				
			||||||
        "//pkg/util/mount:go_default_library",
 | 
					        "//pkg/util/mount:go_default_library",
 | 
				
			||||||
        "//pkg/volume:go_default_library",
 | 
					        "//pkg/volume:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/volume/util:go_default_library",
 | 
				
			||||||
        "//vendor/github.com/golang/glog:go_default_library",
 | 
					        "//vendor/github.com/golang/glog:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/api/core/v1:go_default_library",
 | 
					        "//vendor/k8s.io/api/core/v1:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/api/storage/v1:go_default_library",
 | 
					        "//vendor/k8s.io/api/storage/v1:go_default_library",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,6 +39,7 @@ import (
 | 
				
			|||||||
	"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"
 | 
				
			||||||
	vol "k8s.io/kubernetes/pkg/volume"
 | 
						vol "k8s.io/kubernetes/pkg/volume"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/volume/util"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -1216,7 +1217,10 @@ func (ctrl *PersistentVolumeController) doDeleteVolume(volume *v1.PersistentVolu
 | 
				
			|||||||
		return false, fmt.Errorf("Failed to create deleter for volume %q: %v", volume.Name, err)
 | 
							return false, fmt.Errorf("Failed to create deleter for volume %q: %v", volume.Name, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = deleter.Delete(); err != nil {
 | 
						opComplete := util.OperationCompleteHook(plugin.GetPluginName(), "volume_delete")
 | 
				
			||||||
 | 
						err = deleter.Delete()
 | 
				
			||||||
 | 
						opComplete(err)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
		// Deleter failed
 | 
							// Deleter failed
 | 
				
			||||||
		return false, err
 | 
							return false, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1326,7 +1330,9 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(claimObj interfa
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opComplete := util.OperationCompleteHook(plugin.GetPluginName(), "volume_provision")
 | 
				
			||||||
	volume, err = provisioner.Provision()
 | 
						volume, err = provisioner.Provision()
 | 
				
			||||||
 | 
						opComplete(err)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		strerr := fmt.Sprintf("Failed to provision volume with StorageClass %q: %v", storageClass.Name, err)
 | 
							strerr := fmt.Sprintf("Failed to provision volume with StorageClass %q: %v", storageClass.Name, err)
 | 
				
			||||||
		glog.V(2).Infof("failed to provision volume for claim %q with StorageClass %q: %v", claimToClaimKey(claim), storageClass.Name, err)
 | 
							glog.V(2).Infof("failed to provision volume for claim %q with StorageClass %q: %v", claimToClaimKey(claim), storageClass.Name, err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ go_library(
 | 
				
			|||||||
        "doc.go",
 | 
					        "doc.go",
 | 
				
			||||||
        "fs_unsupported.go",
 | 
					        "fs_unsupported.go",
 | 
				
			||||||
        "io_util.go",
 | 
					        "io_util.go",
 | 
				
			||||||
 | 
					        "metrics.go",
 | 
				
			||||||
        "util.go",
 | 
					        "util.go",
 | 
				
			||||||
    ] + select({
 | 
					    ] + select({
 | 
				
			||||||
        "@io_bazel_rules_go//go/platform:darwin_amd64": [
 | 
					        "@io_bazel_rules_go//go/platform:darwin_amd64": [
 | 
				
			||||||
@@ -31,6 +32,7 @@ go_library(
 | 
				
			|||||||
        "//pkg/api/v1/helper:go_default_library",
 | 
					        "//pkg/api/v1/helper:go_default_library",
 | 
				
			||||||
        "//pkg/util/mount:go_default_library",
 | 
					        "//pkg/util/mount:go_default_library",
 | 
				
			||||||
        "//vendor/github.com/golang/glog:go_default_library",
 | 
					        "//vendor/github.com/golang/glog:go_default_library",
 | 
				
			||||||
 | 
					        "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/api/core/v1:go_default_library",
 | 
					        "//vendor/k8s.io/api/core/v1:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/api/storage/v1:go_default_library",
 | 
					        "//vendor/k8s.io/api/storage/v1:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
 | 
					        "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										63
									
								
								pkg/volume/util/metrics.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								pkg/volume/util/metrics.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					Copyright 2017 The Kubernetes Authors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					You may obtain a copy of the License at
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					limitations under the License.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/prometheus/client_golang/prometheus"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var storageOperationMetric = prometheus.NewHistogramVec(
 | 
				
			||||||
 | 
						prometheus.HistogramOpts{
 | 
				
			||||||
 | 
							Name: "storage_operation_duration_seconds",
 | 
				
			||||||
 | 
							Help: "Storage operation duration",
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[]string{"volume_plugin", "operation_name"},
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var storageOperationErrorMetric = prometheus.NewCounterVec(
 | 
				
			||||||
 | 
						prometheus.CounterOpts{
 | 
				
			||||||
 | 
							Name: "storage_operation_errors_total",
 | 
				
			||||||
 | 
							Help: "Storage operation errors",
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						[]string{"volume_plugin", "operation_name"},
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						registerMetrics()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func registerMetrics() {
 | 
				
			||||||
 | 
						prometheus.MustRegister(storageOperationMetric)
 | 
				
			||||||
 | 
						prometheus.MustRegister(storageOperationErrorMetric)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// OperationCompleteHook returns a hook to call when an operation is completed
 | 
				
			||||||
 | 
					func OperationCompleteHook(plugin, operationName string) func(error) {
 | 
				
			||||||
 | 
						requestTime := time.Now()
 | 
				
			||||||
 | 
						opComplete := func(err error) {
 | 
				
			||||||
 | 
							timeTaken := time.Since(requestTime).Seconds()
 | 
				
			||||||
 | 
							// Create metric with operation name and plugin name
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								storageOperationErrorMetric.WithLabelValues(plugin, operationName).Inc()
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								storageOperationMetric.WithLabelValues(plugin, operationName).Observe(timeTaken)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return opComplete
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -55,7 +55,7 @@ type NestedPendingOperations interface {
 | 
				
			|||||||
	// concatenation of volumeName and podName is removed from the list of
 | 
						// concatenation of volumeName and podName is removed from the list of
 | 
				
			||||||
	// executing operations allowing a new operation to be started with the
 | 
						// executing operations allowing a new operation to be started with the
 | 
				
			||||||
	// volumeName without error.
 | 
						// volumeName without error.
 | 
				
			||||||
	Run(volumeName v1.UniqueVolumeName, podName types.UniquePodName, operationFunc func() error) error
 | 
						Run(volumeName v1.UniqueVolumeName, podName types.UniquePodName, operationFunc func() error, operationCompleteFunc func(error)) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Wait blocks until all operations are completed. This is typically
 | 
						// Wait blocks until all operations are completed. This is typically
 | 
				
			||||||
	// necessary during tests - the test should wait until all operations finish
 | 
						// necessary during tests - the test should wait until all operations finish
 | 
				
			||||||
@@ -94,7 +94,8 @@ type operation struct {
 | 
				
			|||||||
func (grm *nestedPendingOperations) Run(
 | 
					func (grm *nestedPendingOperations) Run(
 | 
				
			||||||
	volumeName v1.UniqueVolumeName,
 | 
						volumeName v1.UniqueVolumeName,
 | 
				
			||||||
	podName types.UniquePodName,
 | 
						podName types.UniquePodName,
 | 
				
			||||||
	operationFunc func() error) error {
 | 
						operationFunc func() error,
 | 
				
			||||||
 | 
						operationCompleteFunc func(error)) error {
 | 
				
			||||||
	grm.lock.Lock()
 | 
						grm.lock.Lock()
 | 
				
			||||||
	defer grm.lock.Unlock()
 | 
						defer grm.lock.Unlock()
 | 
				
			||||||
	opExists, previousOpIndex := grm.isOperationExists(volumeName, podName)
 | 
						opExists, previousOpIndex := grm.isOperationExists(volumeName, podName)
 | 
				
			||||||
@@ -132,6 +133,7 @@ func (grm *nestedPendingOperations) Run(
 | 
				
			|||||||
		defer k8sRuntime.HandleCrash()
 | 
							defer k8sRuntime.HandleCrash()
 | 
				
			||||||
		// Handle completion of and error, if any, from operationFunc()
 | 
							// Handle completion of and error, if any, from operationFunc()
 | 
				
			||||||
		defer grm.operationComplete(volumeName, podName, &err)
 | 
							defer grm.operationComplete(volumeName, podName, &err)
 | 
				
			||||||
 | 
							defer operationCompleteFunc(err)
 | 
				
			||||||
		// Handle panic, if any, from operationFunc()
 | 
							// Handle panic, if any, from operationFunc()
 | 
				
			||||||
		defer k8sRuntime.RecoverFromPanic(&err)
 | 
							defer k8sRuntime.RecoverFromPanic(&err)
 | 
				
			||||||
		return operationFunc()
 | 
							return operationFunc()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,7 +50,7 @@ func Test_NewGoRoutineMap_Positive_SingleOp(t *testing.T) {
 | 
				
			|||||||
	operation := func() error { return nil }
 | 
						operation := func() error { return nil }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Act
 | 
						// Act
 | 
				
			||||||
	err := grm.Run(volumeName, "" /* operationSubName */, operation)
 | 
						err := grm.Run(volumeName, "" /* operationSubName */, operation, func(error) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assert
 | 
						// Assert
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -66,8 +66,8 @@ func Test_NewGoRoutineMap_Positive_TwoOps(t *testing.T) {
 | 
				
			|||||||
	operation := func() error { return nil }
 | 
						operation := func() error { return nil }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Act
 | 
						// Act
 | 
				
			||||||
	err1 := grm.Run(volume1Name, "" /* operationSubName */, operation)
 | 
						err1 := grm.Run(volume1Name, "" /* operationSubName */, operation, func(error) {})
 | 
				
			||||||
	err2 := grm.Run(volume2Name, "" /* operationSubName */, operation)
 | 
						err2 := grm.Run(volume2Name, "" /* operationSubName */, operation, func(error) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assert
 | 
						// Assert
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
@@ -88,8 +88,8 @@ func Test_NewGoRoutineMap_Positive_TwoSubOps(t *testing.T) {
 | 
				
			|||||||
	operation := func() error { return nil }
 | 
						operation := func() error { return nil }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Act
 | 
						// Act
 | 
				
			||||||
	err1 := grm.Run(volumeName, operation1PodName, operation)
 | 
						err1 := grm.Run(volumeName, operation1PodName, operation, func(error) {})
 | 
				
			||||||
	err2 := grm.Run(volumeName, operation2PodName, operation)
 | 
						err2 := grm.Run(volumeName, operation2PodName, operation, func(error) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assert
 | 
						// Assert
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
@@ -108,7 +108,7 @@ func Test_NewGoRoutineMap_Positive_SingleOpWithExpBackoff(t *testing.T) {
 | 
				
			|||||||
	operation := func() error { return nil }
 | 
						operation := func() error { return nil }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Act
 | 
						// Act
 | 
				
			||||||
	err := grm.Run(volumeName, "" /* operationSubName */, operation)
 | 
						err := grm.Run(volumeName, "" /* operationSubName */, operation, func(error) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assert
 | 
						// Assert
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -122,7 +122,7 @@ func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstCompletes(t *testing.T) {
 | 
				
			|||||||
	volumeName := v1.UniqueVolumeName("volume-name")
 | 
						volumeName := v1.UniqueVolumeName("volume-name")
 | 
				
			||||||
	operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
						operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
				
			||||||
	operation1 := generateCallbackFunc(operation1DoneCh)
 | 
						operation1 := generateCallbackFunc(operation1DoneCh)
 | 
				
			||||||
	err1 := grm.Run(volumeName, "" /* operationSubName */, operation1)
 | 
						err1 := grm.Run(volumeName, "" /* operationSubName */, operation1, func(error) {})
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -133,7 +133,7 @@ func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstCompletes(t *testing.T) {
 | 
				
			|||||||
	err2 := retryWithExponentialBackOff(
 | 
						err2 := retryWithExponentialBackOff(
 | 
				
			||||||
		time.Duration(initialOperationWaitTimeShort),
 | 
							time.Duration(initialOperationWaitTimeShort),
 | 
				
			||||||
		func() (bool, error) {
 | 
							func() (bool, error) {
 | 
				
			||||||
			err := grm.Run(volumeName, "" /* operationSubName */, operation2)
 | 
								err := grm.Run(volumeName, "" /* operationSubName */, operation2, func(error) {})
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
									t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
				
			||||||
				return false, nil
 | 
									return false, nil
 | 
				
			||||||
@@ -154,7 +154,7 @@ func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstCompletesWithExpBackoff(t *
 | 
				
			|||||||
	volumeName := v1.UniqueVolumeName("volume-name")
 | 
						volumeName := v1.UniqueVolumeName("volume-name")
 | 
				
			||||||
	operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
						operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
				
			||||||
	operation1 := generateCallbackFunc(operation1DoneCh)
 | 
						operation1 := generateCallbackFunc(operation1DoneCh)
 | 
				
			||||||
	err1 := grm.Run(volumeName, "" /* operationSubName */, operation1)
 | 
						err1 := grm.Run(volumeName, "" /* operationSubName */, operation1, func(error) {})
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -165,7 +165,7 @@ func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstCompletesWithExpBackoff(t *
 | 
				
			|||||||
	err2 := retryWithExponentialBackOff(
 | 
						err2 := retryWithExponentialBackOff(
 | 
				
			||||||
		time.Duration(initialOperationWaitTimeShort),
 | 
							time.Duration(initialOperationWaitTimeShort),
 | 
				
			||||||
		func() (bool, error) {
 | 
							func() (bool, error) {
 | 
				
			||||||
			err := grm.Run(volumeName, "" /* operationSubName */, operation2)
 | 
								err := grm.Run(volumeName, "" /* operationSubName */, operation2, func(error) {})
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
									t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
				
			||||||
				return false, nil
 | 
									return false, nil
 | 
				
			||||||
@@ -185,7 +185,7 @@ func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstPanics(t *testing.T) {
 | 
				
			|||||||
	grm := NewNestedPendingOperations(false /* exponentialBackOffOnError */)
 | 
						grm := NewNestedPendingOperations(false /* exponentialBackOffOnError */)
 | 
				
			||||||
	volumeName := v1.UniqueVolumeName("volume-name")
 | 
						volumeName := v1.UniqueVolumeName("volume-name")
 | 
				
			||||||
	operation1 := generatePanicFunc()
 | 
						operation1 := generatePanicFunc()
 | 
				
			||||||
	err1 := grm.Run(volumeName, "" /* operationSubName */, operation1)
 | 
						err1 := grm.Run(volumeName, "" /* operationSubName */, operation1, func(error) {})
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -195,7 +195,7 @@ func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstPanics(t *testing.T) {
 | 
				
			|||||||
	err2 := retryWithExponentialBackOff(
 | 
						err2 := retryWithExponentialBackOff(
 | 
				
			||||||
		time.Duration(initialOperationWaitTimeShort),
 | 
							time.Duration(initialOperationWaitTimeShort),
 | 
				
			||||||
		func() (bool, error) {
 | 
							func() (bool, error) {
 | 
				
			||||||
			err := grm.Run(volumeName, "" /* operationSubName */, operation2)
 | 
								err := grm.Run(volumeName, "" /* operationSubName */, operation2, func(error) {})
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
									t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
				
			||||||
				return false, nil
 | 
									return false, nil
 | 
				
			||||||
@@ -215,7 +215,7 @@ func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstPanicsWithExpBackoff(t *tes
 | 
				
			|||||||
	grm := NewNestedPendingOperations(true /* exponentialBackOffOnError */)
 | 
						grm := NewNestedPendingOperations(true /* exponentialBackOffOnError */)
 | 
				
			||||||
	volumeName := v1.UniqueVolumeName("volume-name")
 | 
						volumeName := v1.UniqueVolumeName("volume-name")
 | 
				
			||||||
	operation1 := generatePanicFunc()
 | 
						operation1 := generatePanicFunc()
 | 
				
			||||||
	err1 := grm.Run(volumeName, "" /* operationSubName */, operation1)
 | 
						err1 := grm.Run(volumeName, "" /* operationSubName */, operation1, func(error) {})
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -225,7 +225,7 @@ func Test_NewGoRoutineMap_Positive_SecondOpAfterFirstPanicsWithExpBackoff(t *tes
 | 
				
			|||||||
	err2 := retryWithExponentialBackOff(
 | 
						err2 := retryWithExponentialBackOff(
 | 
				
			||||||
		time.Duration(initialOperationWaitTimeLong), // Longer duration to accommodate for backoff
 | 
							time.Duration(initialOperationWaitTimeLong), // Longer duration to accommodate for backoff
 | 
				
			||||||
		func() (bool, error) {
 | 
							func() (bool, error) {
 | 
				
			||||||
			err := grm.Run(volumeName, "" /* operationSubName */, operation2)
 | 
								err := grm.Run(volumeName, "" /* operationSubName */, operation2, func(error) {})
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
									t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
				
			||||||
				return false, nil
 | 
									return false, nil
 | 
				
			||||||
@@ -246,14 +246,14 @@ func Test_NewGoRoutineMap_Negative_SecondOpBeforeFirstCompletes(t *testing.T) {
 | 
				
			|||||||
	volumeName := v1.UniqueVolumeName("volume-name")
 | 
						volumeName := v1.UniqueVolumeName("volume-name")
 | 
				
			||||||
	operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
						operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
				
			||||||
	operation1 := generateWaitFunc(operation1DoneCh)
 | 
						operation1 := generateWaitFunc(operation1DoneCh)
 | 
				
			||||||
	err1 := grm.Run(volumeName, "" /* operationSubName */, operation1)
 | 
						err1 := grm.Run(volumeName, "" /* operationSubName */, operation1, func(error) {})
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	operation2 := generateNoopFunc()
 | 
						operation2 := generateNoopFunc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Act
 | 
						// Act
 | 
				
			||||||
	err2 := grm.Run(volumeName, "" /* operationSubName */, operation2)
 | 
						err2 := grm.Run(volumeName, "" /* operationSubName */, operation2, func(error) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assert
 | 
						// Assert
 | 
				
			||||||
	if err2 == nil {
 | 
						if err2 == nil {
 | 
				
			||||||
@@ -271,14 +271,14 @@ func Test_NewGoRoutineMap_Negative_SecondSubOpBeforeFirstCompletes2(t *testing.T
 | 
				
			|||||||
	operationPodName := types.UniquePodName("operation-podname")
 | 
						operationPodName := types.UniquePodName("operation-podname")
 | 
				
			||||||
	operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
						operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
				
			||||||
	operation1 := generateWaitFunc(operation1DoneCh)
 | 
						operation1 := generateWaitFunc(operation1DoneCh)
 | 
				
			||||||
	err1 := grm.Run(volumeName, operationPodName, operation1)
 | 
						err1 := grm.Run(volumeName, operationPodName, operation1, func(error) {})
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	operation2 := generateNoopFunc()
 | 
						operation2 := generateNoopFunc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Act
 | 
						// Act
 | 
				
			||||||
	err2 := grm.Run(volumeName, operationPodName, operation2)
 | 
						err2 := grm.Run(volumeName, operationPodName, operation2, func(error) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assert
 | 
						// Assert
 | 
				
			||||||
	if err2 == nil {
 | 
						if err2 == nil {
 | 
				
			||||||
@@ -296,14 +296,14 @@ func Test_NewGoRoutineMap_Negative_SecondSubOpBeforeFirstCompletes(t *testing.T)
 | 
				
			|||||||
	operationPodName := types.UniquePodName("operation-podname")
 | 
						operationPodName := types.UniquePodName("operation-podname")
 | 
				
			||||||
	operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
						operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
				
			||||||
	operation1 := generateWaitFunc(operation1DoneCh)
 | 
						operation1 := generateWaitFunc(operation1DoneCh)
 | 
				
			||||||
	err1 := grm.Run(volumeName, operationPodName, operation1)
 | 
						err1 := grm.Run(volumeName, operationPodName, operation1, func(error) {})
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	operation2 := generateNoopFunc()
 | 
						operation2 := generateNoopFunc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Act
 | 
						// Act
 | 
				
			||||||
	err2 := grm.Run(volumeName, operationPodName, operation2)
 | 
						err2 := grm.Run(volumeName, operationPodName, operation2, func(error) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assert
 | 
						// Assert
 | 
				
			||||||
	if err2 == nil {
 | 
						if err2 == nil {
 | 
				
			||||||
@@ -320,14 +320,14 @@ func Test_NewGoRoutineMap_Negative_SecondOpBeforeFirstCompletesWithExpBackoff(t
 | 
				
			|||||||
	volumeName := v1.UniqueVolumeName("volume-name")
 | 
						volumeName := v1.UniqueVolumeName("volume-name")
 | 
				
			||||||
	operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
						operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
				
			||||||
	operation1 := generateWaitFunc(operation1DoneCh)
 | 
						operation1 := generateWaitFunc(operation1DoneCh)
 | 
				
			||||||
	err1 := grm.Run(volumeName, "" /* operationSubName */, operation1)
 | 
						err1 := grm.Run(volumeName, "" /* operationSubName */, operation1, func(error) {})
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	operation2 := generateNoopFunc()
 | 
						operation2 := generateNoopFunc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Act
 | 
						// Act
 | 
				
			||||||
	err2 := grm.Run(volumeName, "" /* operationSubName */, operation2)
 | 
						err2 := grm.Run(volumeName, "" /* operationSubName */, operation2, func(error) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assert
 | 
						// Assert
 | 
				
			||||||
	if err2 == nil {
 | 
						if err2 == nil {
 | 
				
			||||||
@@ -344,7 +344,7 @@ func Test_NewGoRoutineMap_Positive_ThirdOpAfterFirstCompletes(t *testing.T) {
 | 
				
			|||||||
	volumeName := v1.UniqueVolumeName("volume-name")
 | 
						volumeName := v1.UniqueVolumeName("volume-name")
 | 
				
			||||||
	operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
						operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
				
			||||||
	operation1 := generateWaitFunc(operation1DoneCh)
 | 
						operation1 := generateWaitFunc(operation1DoneCh)
 | 
				
			||||||
	err1 := grm.Run(volumeName, "" /* operationSubName */, operation1)
 | 
						err1 := grm.Run(volumeName, "" /* operationSubName */, operation1, func(error) {})
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -352,7 +352,7 @@ func Test_NewGoRoutineMap_Positive_ThirdOpAfterFirstCompletes(t *testing.T) {
 | 
				
			|||||||
	operation3 := generateNoopFunc()
 | 
						operation3 := generateNoopFunc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Act
 | 
						// Act
 | 
				
			||||||
	err2 := grm.Run(volumeName, "" /* operationSubName */, operation2)
 | 
						err2 := grm.Run(volumeName, "" /* operationSubName */, operation2, func(error) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assert
 | 
						// Assert
 | 
				
			||||||
	if err2 == nil {
 | 
						if err2 == nil {
 | 
				
			||||||
@@ -367,7 +367,7 @@ func Test_NewGoRoutineMap_Positive_ThirdOpAfterFirstCompletes(t *testing.T) {
 | 
				
			|||||||
	err3 := retryWithExponentialBackOff(
 | 
						err3 := retryWithExponentialBackOff(
 | 
				
			||||||
		time.Duration(initialOperationWaitTimeShort),
 | 
							time.Duration(initialOperationWaitTimeShort),
 | 
				
			||||||
		func() (bool, error) {
 | 
							func() (bool, error) {
 | 
				
			||||||
			err := grm.Run(volumeName, "" /* operationSubName */, operation3)
 | 
								err := grm.Run(volumeName, "" /* operationSubName */, operation3, func(error) {})
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
									t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
				
			||||||
				return false, nil
 | 
									return false, nil
 | 
				
			||||||
@@ -388,7 +388,7 @@ func Test_NewGoRoutineMap_Positive_ThirdOpAfterFirstCompletesWithExpBackoff(t *t
 | 
				
			|||||||
	volumeName := v1.UniqueVolumeName("volume-name")
 | 
						volumeName := v1.UniqueVolumeName("volume-name")
 | 
				
			||||||
	operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
						operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
				
			||||||
	operation1 := generateWaitFunc(operation1DoneCh)
 | 
						operation1 := generateWaitFunc(operation1DoneCh)
 | 
				
			||||||
	err1 := grm.Run(volumeName, "" /* operationSubName */, operation1)
 | 
						err1 := grm.Run(volumeName, "" /* operationSubName */, operation1, func(error) {})
 | 
				
			||||||
	if err1 != nil {
 | 
						if err1 != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err1)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -396,7 +396,7 @@ func Test_NewGoRoutineMap_Positive_ThirdOpAfterFirstCompletesWithExpBackoff(t *t
 | 
				
			|||||||
	operation3 := generateNoopFunc()
 | 
						operation3 := generateNoopFunc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Act
 | 
						// Act
 | 
				
			||||||
	err2 := grm.Run(volumeName, "" /* operationSubName */, operation2)
 | 
						err2 := grm.Run(volumeName, "" /* operationSubName */, operation2, func(error) {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Assert
 | 
						// Assert
 | 
				
			||||||
	if err2 == nil {
 | 
						if err2 == nil {
 | 
				
			||||||
@@ -411,7 +411,7 @@ func Test_NewGoRoutineMap_Positive_ThirdOpAfterFirstCompletesWithExpBackoff(t *t
 | 
				
			|||||||
	err3 := retryWithExponentialBackOff(
 | 
						err3 := retryWithExponentialBackOff(
 | 
				
			||||||
		time.Duration(initialOperationWaitTimeShort),
 | 
							time.Duration(initialOperationWaitTimeShort),
 | 
				
			||||||
		func() (bool, error) {
 | 
							func() (bool, error) {
 | 
				
			||||||
			err := grm.Run(volumeName, "" /* operationSubName */, operation3)
 | 
								err := grm.Run(volumeName, "" /* operationSubName */, operation3, func(error) {})
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
									t.Logf("Warning: NewGoRoutine failed with %v. Will retry.", err)
 | 
				
			||||||
				return false, nil
 | 
									return false, nil
 | 
				
			||||||
@@ -471,7 +471,7 @@ func Test_NewGoRoutineMap_Positive_Wait(t *testing.T) {
 | 
				
			|||||||
	volumeName := v1.UniqueVolumeName("volume-name")
 | 
						volumeName := v1.UniqueVolumeName("volume-name")
 | 
				
			||||||
	operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
						operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
				
			||||||
	operation1 := generateWaitFunc(operation1DoneCh)
 | 
						operation1 := generateWaitFunc(operation1DoneCh)
 | 
				
			||||||
	err := grm.Run(volumeName, "" /* operationSubName */, operation1)
 | 
						err := grm.Run(volumeName, "" /* operationSubName */, operation1, func(error) {})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -500,7 +500,7 @@ func Test_NewGoRoutineMap_Positive_WaitWithExpBackoff(t *testing.T) {
 | 
				
			|||||||
	volumeName := v1.UniqueVolumeName("volume-name")
 | 
						volumeName := v1.UniqueVolumeName("volume-name")
 | 
				
			||||||
	operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
						operation1DoneCh := make(chan interface{}, 0 /* bufferSize */)
 | 
				
			||||||
	operation1 := generateWaitFunc(operation1DoneCh)
 | 
						operation1 := generateWaitFunc(operation1DoneCh)
 | 
				
			||||||
	err := grm.Run(volumeName, "" /* operationSubName */, operation1)
 | 
						err := grm.Run(volumeName, "" /* operationSubName */, operation1, func(error) {})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err)
 | 
							t.Fatalf("NewGoRoutine failed. Expected: <no error> Actual: <%v>", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,7 @@ import (
 | 
				
			|||||||
	"k8s.io/apimachinery/pkg/types"
 | 
						"k8s.io/apimachinery/pkg/types"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/util/mount"
 | 
						"k8s.io/kubernetes/pkg/util/mount"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/volume"
 | 
						"k8s.io/kubernetes/pkg/volume"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/volume/util"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/volume/util/nestedpendingoperations"
 | 
						"k8s.io/kubernetes/pkg/volume/util/nestedpendingoperations"
 | 
				
			||||||
	volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
 | 
						volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/volume/util/volumehelper"
 | 
						"k8s.io/kubernetes/pkg/volume/util/volumehelper"
 | 
				
			||||||
@@ -535,29 +536,32 @@ func (oe *operationExecutor) IsOperationPending(volumeName v1.UniqueVolumeName,
 | 
				
			|||||||
func (oe *operationExecutor) AttachVolume(
 | 
					func (oe *operationExecutor) AttachVolume(
 | 
				
			||||||
	volumeToAttach VolumeToAttach,
 | 
						volumeToAttach VolumeToAttach,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldAttacherUpdater) error {
 | 
						actualStateOfWorld ActualStateOfWorldAttacherUpdater) error {
 | 
				
			||||||
	attachFunc, err :=
 | 
						attachFunc, plugin, err :=
 | 
				
			||||||
		oe.operationGenerator.GenerateAttachVolumeFunc(volumeToAttach, actualStateOfWorld)
 | 
							oe.operationGenerator.GenerateAttachVolumeFunc(volumeToAttach, actualStateOfWorld)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opCompleteFunc := util.OperationCompleteHook(plugin, "volume_attach")
 | 
				
			||||||
	return oe.pendingOperations.Run(
 | 
						return oe.pendingOperations.Run(
 | 
				
			||||||
		volumeToAttach.VolumeName, "" /* podName */, attachFunc)
 | 
							volumeToAttach.VolumeName, "" /* podName */, attachFunc, opCompleteFunc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (oe *operationExecutor) DetachVolume(
 | 
					func (oe *operationExecutor) DetachVolume(
 | 
				
			||||||
	volumeToDetach AttachedVolume,
 | 
						volumeToDetach AttachedVolume,
 | 
				
			||||||
	verifySafeToDetach bool,
 | 
						verifySafeToDetach bool,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldAttacherUpdater) error {
 | 
						actualStateOfWorld ActualStateOfWorldAttacherUpdater) error {
 | 
				
			||||||
	detachFunc, err :=
 | 
						detachFunc, plugin, err :=
 | 
				
			||||||
		oe.operationGenerator.GenerateDetachVolumeFunc(volumeToDetach, verifySafeToDetach, actualStateOfWorld)
 | 
							oe.operationGenerator.GenerateDetachVolumeFunc(volumeToDetach, verifySafeToDetach, actualStateOfWorld)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opCompleteFunc := util.OperationCompleteHook(plugin, "volume_detach")
 | 
				
			||||||
	return oe.pendingOperations.Run(
 | 
						return oe.pendingOperations.Run(
 | 
				
			||||||
		volumeToDetach.VolumeName, "" /* podName */, detachFunc)
 | 
							volumeToDetach.VolumeName, "" /* podName */, detachFunc, opCompleteFunc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (oe *operationExecutor) VerifyVolumesAreAttached(
 | 
					func (oe *operationExecutor) VerifyVolumesAreAttached(
 | 
				
			||||||
	attachedVolumes map[types.NodeName][]AttachedVolume,
 | 
						attachedVolumes map[types.NodeName][]AttachedVolume,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldAttacherUpdater) {
 | 
						actualStateOfWorld ActualStateOfWorldAttacherUpdater) {
 | 
				
			||||||
@@ -630,9 +634,11 @@ func (oe *operationExecutor) VerifyVolumesAreAttached(
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			glog.Errorf("BulkVerifyVolumes.GenerateBulkVolumeVerifyFunc error bulk verifying volumes for plugin %q with  %v", pluginName, err)
 | 
								glog.Errorf("BulkVerifyVolumes.GenerateBulkVolumeVerifyFunc error bulk verifying volumes for plugin %q with  %v", pluginName, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							opCompleteFunc := util.OperationCompleteHook(pluginName, "verify_volumes_are_attached")
 | 
				
			||||||
		// Ugly hack to ensure - we don't do parallel bulk polling of same volume plugin
 | 
							// Ugly hack to ensure - we don't do parallel bulk polling of same volume plugin
 | 
				
			||||||
		uniquePluginName := v1.UniqueVolumeName(pluginName)
 | 
							uniquePluginName := v1.UniqueVolumeName(pluginName)
 | 
				
			||||||
		err = oe.pendingOperations.Run(uniquePluginName, "" /* Pod Name */, bulkVerifyVolumeFunc)
 | 
							err = oe.pendingOperations.Run(uniquePluginName, "" /* Pod Name */, bulkVerifyVolumeFunc, opCompleteFunc)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			glog.Errorf("BulkVerifyVolumes.Run Error bulk volume verification for plugin %q  with %v", pluginName, err)
 | 
								glog.Errorf("BulkVerifyVolumes.Run Error bulk volume verification for plugin %q  with %v", pluginName, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -648,8 +654,10 @@ func (oe *operationExecutor) VerifyVolumesAreAttachedPerNode(
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opCompleteFunc := util.OperationCompleteHook("<n/a>", "verify_volumes_are_attached_per_node")
 | 
				
			||||||
	// Give an empty UniqueVolumeName so that this operation could be executed concurrently.
 | 
						// Give an empty UniqueVolumeName so that this operation could be executed concurrently.
 | 
				
			||||||
	return oe.pendingOperations.Run("" /* volumeName */, "" /* podName */, volumesAreAttachedFunc)
 | 
						return oe.pendingOperations.Run("" /* volumeName */, "" /* podName */, volumesAreAttachedFunc, opCompleteFunc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (oe *operationExecutor) MountVolume(
 | 
					func (oe *operationExecutor) MountVolume(
 | 
				
			||||||
@@ -657,7 +665,7 @@ func (oe *operationExecutor) MountVolume(
 | 
				
			|||||||
	volumeToMount VolumeToMount,
 | 
						volumeToMount VolumeToMount,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldMounterUpdater,
 | 
						actualStateOfWorld ActualStateOfWorldMounterUpdater,
 | 
				
			||||||
	isRemount bool) error {
 | 
						isRemount bool) error {
 | 
				
			||||||
	mountFunc, err := oe.operationGenerator.GenerateMountVolumeFunc(
 | 
						mountFunc, plugin, err := oe.operationGenerator.GenerateMountVolumeFunc(
 | 
				
			||||||
		waitForAttachTimeout, volumeToMount, actualStateOfWorld, isRemount)
 | 
							waitForAttachTimeout, volumeToMount, actualStateOfWorld, isRemount)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -671,15 +679,17 @@ func (oe *operationExecutor) MountVolume(
 | 
				
			|||||||
		podName = volumehelper.GetUniquePodName(volumeToMount.Pod)
 | 
							podName = volumehelper.GetUniquePodName(volumeToMount.Pod)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO mount_device
 | 
				
			||||||
 | 
						opCompleteFunc := util.OperationCompleteHook(plugin, "volume_mount")
 | 
				
			||||||
	return oe.pendingOperations.Run(
 | 
						return oe.pendingOperations.Run(
 | 
				
			||||||
		volumeToMount.VolumeName, podName, mountFunc)
 | 
							volumeToMount.VolumeName, podName, mountFunc, opCompleteFunc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (oe *operationExecutor) UnmountVolume(
 | 
					func (oe *operationExecutor) UnmountVolume(
 | 
				
			||||||
	volumeToUnmount MountedVolume,
 | 
						volumeToUnmount MountedVolume,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldMounterUpdater) error {
 | 
						actualStateOfWorld ActualStateOfWorldMounterUpdater) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unmountFunc, err :=
 | 
						unmountFunc, plugin, err :=
 | 
				
			||||||
		oe.operationGenerator.GenerateUnmountVolumeFunc(volumeToUnmount, actualStateOfWorld)
 | 
							oe.operationGenerator.GenerateUnmountVolumeFunc(volumeToUnmount, actualStateOfWorld)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -689,36 +699,39 @@ func (oe *operationExecutor) UnmountVolume(
 | 
				
			|||||||
	// same volume in parallel
 | 
						// same volume in parallel
 | 
				
			||||||
	podName := volumetypes.UniquePodName(volumeToUnmount.PodUID)
 | 
						podName := volumetypes.UniquePodName(volumeToUnmount.PodUID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opCompleteFunc := util.OperationCompleteHook(plugin, "volume_unmount")
 | 
				
			||||||
	return oe.pendingOperations.Run(
 | 
						return oe.pendingOperations.Run(
 | 
				
			||||||
		volumeToUnmount.VolumeName, podName, unmountFunc)
 | 
							volumeToUnmount.VolumeName, podName, unmountFunc, opCompleteFunc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (oe *operationExecutor) UnmountDevice(
 | 
					func (oe *operationExecutor) UnmountDevice(
 | 
				
			||||||
	deviceToDetach AttachedVolume,
 | 
						deviceToDetach AttachedVolume,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldMounterUpdater,
 | 
						actualStateOfWorld ActualStateOfWorldMounterUpdater,
 | 
				
			||||||
	mounter mount.Interface) error {
 | 
						mounter mount.Interface) error {
 | 
				
			||||||
	unmountDeviceFunc, err :=
 | 
						unmountDeviceFunc, plugin, err :=
 | 
				
			||||||
		oe.operationGenerator.GenerateUnmountDeviceFunc(deviceToDetach, actualStateOfWorld, mounter)
 | 
							oe.operationGenerator.GenerateUnmountDeviceFunc(deviceToDetach, actualStateOfWorld, mounter)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opCompleteFunc := util.OperationCompleteHook(plugin, "unmount_device")
 | 
				
			||||||
	return oe.pendingOperations.Run(
 | 
						return oe.pendingOperations.Run(
 | 
				
			||||||
		deviceToDetach.VolumeName, "" /* podName */, unmountDeviceFunc)
 | 
							deviceToDetach.VolumeName, "" /* podName */, unmountDeviceFunc, opCompleteFunc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (oe *operationExecutor) VerifyControllerAttachedVolume(
 | 
					func (oe *operationExecutor) VerifyControllerAttachedVolume(
 | 
				
			||||||
	volumeToMount VolumeToMount,
 | 
						volumeToMount VolumeToMount,
 | 
				
			||||||
	nodeName types.NodeName,
 | 
						nodeName types.NodeName,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldAttacherUpdater) error {
 | 
						actualStateOfWorld ActualStateOfWorldAttacherUpdater) error {
 | 
				
			||||||
	verifyControllerAttachedVolumeFunc, err :=
 | 
						verifyControllerAttachedVolumeFunc, plugin, err :=
 | 
				
			||||||
		oe.operationGenerator.GenerateVerifyControllerAttachedVolumeFunc(volumeToMount, nodeName, actualStateOfWorld)
 | 
							oe.operationGenerator.GenerateVerifyControllerAttachedVolumeFunc(volumeToMount, nodeName, actualStateOfWorld)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						opCompleteFunc := util.OperationCompleteHook(plugin, "verify_controller_attached_volume")
 | 
				
			||||||
	return oe.pendingOperations.Run(
 | 
						return oe.pendingOperations.Run(
 | 
				
			||||||
		volumeToMount.VolumeName, "" /* podName */, verifyControllerAttachedVolumeFunc)
 | 
							volumeToMount.VolumeName, "" /* podName */, verifyControllerAttachedVolumeFunc, opCompleteFunc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: this is a workaround for the unmount device issue caused by gci mounter.
 | 
					// TODO: this is a workaround for the unmount device issue caused by gci mounter.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -239,29 +239,29 @@ func newFakeOperationGenerator(ch chan interface{}, quit chan interface{}) Opera
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (fopg *fakeOperationGenerator) GenerateMountVolumeFunc(waitForAttachTimeout time.Duration, volumeToMount VolumeToMount, actualStateOfWorldMounterUpdater ActualStateOfWorldMounterUpdater, isRemount bool) (func() error, error) {
 | 
					func (fopg *fakeOperationGenerator) GenerateMountVolumeFunc(waitForAttachTimeout time.Duration, volumeToMount VolumeToMount, actualStateOfWorldMounterUpdater ActualStateOfWorldMounterUpdater, isRemount bool) (func() error, string, error) {
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
		startOperationAndBlock(fopg.ch, fopg.quit)
 | 
							startOperationAndBlock(fopg.ch, fopg.quit)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, "", nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (fopg *fakeOperationGenerator) GenerateUnmountVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater) (func() error, error) {
 | 
					func (fopg *fakeOperationGenerator) GenerateUnmountVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater) (func() error, string, error) {
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
		startOperationAndBlock(fopg.ch, fopg.quit)
 | 
							startOperationAndBlock(fopg.ch, fopg.quit)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, "", nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (fopg *fakeOperationGenerator) GenerateAttachVolumeFunc(volumeToAttach VolumeToAttach, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error) {
 | 
					func (fopg *fakeOperationGenerator) GenerateAttachVolumeFunc(volumeToAttach VolumeToAttach, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, string, error) {
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
		startOperationAndBlock(fopg.ch, fopg.quit)
 | 
							startOperationAndBlock(fopg.ch, fopg.quit)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, "", nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (fopg *fakeOperationGenerator) GenerateDetachVolumeFunc(volumeToDetach AttachedVolume, verifySafeToDetach bool, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error) {
 | 
					func (fopg *fakeOperationGenerator) GenerateDetachVolumeFunc(volumeToDetach AttachedVolume, verifySafeToDetach bool, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, string, error) {
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
		startOperationAndBlock(fopg.ch, fopg.quit)
 | 
							startOperationAndBlock(fopg.ch, fopg.quit)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, "", nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (fopg *fakeOperationGenerator) GenerateVolumesAreAttachedFunc(attachedVolumes []AttachedVolume, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error) {
 | 
					func (fopg *fakeOperationGenerator) GenerateVolumesAreAttachedFunc(attachedVolumes []AttachedVolume, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error) {
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
@@ -269,17 +269,17 @@ func (fopg *fakeOperationGenerator) GenerateVolumesAreAttachedFunc(attachedVolum
 | 
				
			|||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (fopg *fakeOperationGenerator) GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) (func() error, error) {
 | 
					func (fopg *fakeOperationGenerator) GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) (func() error, string, error) {
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
		startOperationAndBlock(fopg.ch, fopg.quit)
 | 
							startOperationAndBlock(fopg.ch, fopg.quit)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, "", nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
func (fopg *fakeOperationGenerator) GenerateVerifyControllerAttachedVolumeFunc(volumeToMount VolumeToMount, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error) {
 | 
					func (fopg *fakeOperationGenerator) GenerateVerifyControllerAttachedVolumeFunc(volumeToMount VolumeToMount, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, string, error) {
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
		startOperationAndBlock(fopg.ch, fopg.quit)
 | 
							startOperationAndBlock(fopg.ch, fopg.quit)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, "", nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (fopg *fakeOperationGenerator) GenerateBulkVolumeVerifyFunc(
 | 
					func (fopg *fakeOperationGenerator) GenerateBulkVolumeVerifyFunc(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,25 +73,25 @@ func NewOperationGenerator(kubeClient clientset.Interface,
 | 
				
			|||||||
// OperationGenerator interface that extracts out the functions from operation_executor to make it dependency injectable
 | 
					// OperationGenerator interface that extracts out the functions from operation_executor to make it dependency injectable
 | 
				
			||||||
type OperationGenerator interface {
 | 
					type OperationGenerator interface {
 | 
				
			||||||
	// Generates the MountVolume function needed to perform the mount of a volume plugin
 | 
						// Generates the MountVolume function needed to perform the mount of a volume plugin
 | 
				
			||||||
	GenerateMountVolumeFunc(waitForAttachTimeout time.Duration, volumeToMount VolumeToMount, actualStateOfWorldMounterUpdater ActualStateOfWorldMounterUpdater, isRemount bool) (func() error, error)
 | 
						GenerateMountVolumeFunc(waitForAttachTimeout time.Duration, volumeToMount VolumeToMount, actualStateOfWorldMounterUpdater ActualStateOfWorldMounterUpdater, isRemount bool) (func() error, string, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Generates the UnmountVolume function needed to perform the unmount of a volume plugin
 | 
						// Generates the UnmountVolume function needed to perform the unmount of a volume plugin
 | 
				
			||||||
	GenerateUnmountVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater) (func() error, error)
 | 
						GenerateUnmountVolumeFunc(volumeToUnmount MountedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater) (func() error, string, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Generates the AttachVolume function needed to perform attach of a volume plugin
 | 
						// Generates the AttachVolume function needed to perform attach of a volume plugin
 | 
				
			||||||
	GenerateAttachVolumeFunc(volumeToAttach VolumeToAttach, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error)
 | 
						GenerateAttachVolumeFunc(volumeToAttach VolumeToAttach, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, string, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Generates the DetachVolume function needed to perform the detach of a volume plugin
 | 
						// Generates the DetachVolume function needed to perform the detach of a volume plugin
 | 
				
			||||||
	GenerateDetachVolumeFunc(volumeToDetach AttachedVolume, verifySafeToDetach bool, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error)
 | 
						GenerateDetachVolumeFunc(volumeToDetach AttachedVolume, verifySafeToDetach bool, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, string, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Generates the VolumesAreAttached function needed to verify if volume plugins are attached
 | 
						// Generates the VolumesAreAttached function needed to verify if volume plugins are attached
 | 
				
			||||||
	GenerateVolumesAreAttachedFunc(attachedVolumes []AttachedVolume, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error)
 | 
						GenerateVolumesAreAttachedFunc(attachedVolumes []AttachedVolume, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Generates the UnMountDevice function needed to perform the unmount of a device
 | 
						// Generates the UnMountDevice function needed to perform the unmount of a device
 | 
				
			||||||
	GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) (func() error, error)
 | 
						GenerateUnmountDeviceFunc(deviceToDetach AttachedVolume, actualStateOfWorld ActualStateOfWorldMounterUpdater, mounter mount.Interface) (func() error, string, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Generates the function needed to check if the attach_detach controller has attached the volume plugin
 | 
						// Generates the function needed to check if the attach_detach controller has attached the volume plugin
 | 
				
			||||||
	GenerateVerifyControllerAttachedVolumeFunc(volumeToMount VolumeToMount, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error)
 | 
						GenerateVerifyControllerAttachedVolumeFunc(volumeToMount VolumeToMount, nodeName types.NodeName, actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, string, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// GetVolumePluginMgr returns volume plugin manager
 | 
						// GetVolumePluginMgr returns volume plugin manager
 | 
				
			||||||
	GetVolumePluginMgr() *volume.VolumePluginMgr
 | 
						GetVolumePluginMgr() *volume.VolumePluginMgr
 | 
				
			||||||
@@ -245,17 +245,17 @@ func (og *operationGenerator) GenerateBulkVolumeVerifyFunc(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (og *operationGenerator) GenerateAttachVolumeFunc(
 | 
					func (og *operationGenerator) GenerateAttachVolumeFunc(
 | 
				
			||||||
	volumeToAttach VolumeToAttach,
 | 
						volumeToAttach VolumeToAttach,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error) {
 | 
						actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, string, error) {
 | 
				
			||||||
	// Get attacher plugin
 | 
						// Get attacher plugin
 | 
				
			||||||
	attachableVolumePlugin, err :=
 | 
						attachableVolumePlugin, err :=
 | 
				
			||||||
		og.volumePluginMgr.FindAttachablePluginBySpec(volumeToAttach.VolumeSpec)
 | 
							og.volumePluginMgr.FindAttachablePluginBySpec(volumeToAttach.VolumeSpec)
 | 
				
			||||||
	if err != nil || attachableVolumePlugin == nil {
 | 
						if err != nil || attachableVolumePlugin == nil {
 | 
				
			||||||
		return nil, volumeToAttach.GenerateErrorDetailed("AttachVolume.FindAttachablePluginBySpec failed", err)
 | 
							return nil, "", volumeToAttach.GenerateErrorDetailed("AttachVolume.FindAttachablePluginBySpec failed", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	volumeAttacher, newAttacherErr := attachableVolumePlugin.NewAttacher()
 | 
						volumeAttacher, newAttacherErr := attachableVolumePlugin.NewAttacher()
 | 
				
			||||||
	if newAttacherErr != nil {
 | 
						if newAttacherErr != nil {
 | 
				
			||||||
		return nil, volumeToAttach.GenerateErrorDetailed("AttachVolume.NewAttacher failed", newAttacherErr)
 | 
							return nil, attachableVolumePlugin.GetPluginName(), volumeToAttach.GenerateErrorDetailed("AttachVolume.NewAttacher failed", newAttacherErr)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
@@ -283,7 +283,7 @@ func (og *operationGenerator) GenerateAttachVolumeFunc(
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, attachableVolumePlugin.GetPluginName(), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (og *operationGenerator) GetVolumePluginMgr() *volume.VolumePluginMgr {
 | 
					func (og *operationGenerator) GetVolumePluginMgr() *volume.VolumePluginMgr {
 | 
				
			||||||
@@ -293,9 +293,10 @@ func (og *operationGenerator) GetVolumePluginMgr() *volume.VolumePluginMgr {
 | 
				
			|||||||
func (og *operationGenerator) GenerateDetachVolumeFunc(
 | 
					func (og *operationGenerator) GenerateDetachVolumeFunc(
 | 
				
			||||||
	volumeToDetach AttachedVolume,
 | 
						volumeToDetach AttachedVolume,
 | 
				
			||||||
	verifySafeToDetach bool,
 | 
						verifySafeToDetach bool,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error) {
 | 
						actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, string, error) {
 | 
				
			||||||
	var volumeName string
 | 
						var volumeName string
 | 
				
			||||||
	var attachableVolumePlugin volume.AttachableVolumePlugin
 | 
						var attachableVolumePlugin volume.AttachableVolumePlugin
 | 
				
			||||||
 | 
						var pluginName string
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if volumeToDetach.VolumeSpec != nil {
 | 
						if volumeToDetach.VolumeSpec != nil {
 | 
				
			||||||
@@ -303,31 +304,35 @@ func (og *operationGenerator) GenerateDetachVolumeFunc(
 | 
				
			|||||||
		attachableVolumePlugin, err =
 | 
							attachableVolumePlugin, err =
 | 
				
			||||||
			og.volumePluginMgr.FindAttachablePluginBySpec(volumeToDetach.VolumeSpec)
 | 
								og.volumePluginMgr.FindAttachablePluginBySpec(volumeToDetach.VolumeSpec)
 | 
				
			||||||
		if err != nil || attachableVolumePlugin == nil {
 | 
							if err != nil || attachableVolumePlugin == nil {
 | 
				
			||||||
			return nil, volumeToDetach.GenerateErrorDetailed("DetachVolume.FindAttachablePluginBySpec failed", err)
 | 
								return nil, "", volumeToDetach.GenerateErrorDetailed("DetachVolume.FindAttachablePluginBySpec failed", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		volumeName, err =
 | 
							volumeName, err =
 | 
				
			||||||
			attachableVolumePlugin.GetVolumeName(volumeToDetach.VolumeSpec)
 | 
								attachableVolumePlugin.GetVolumeName(volumeToDetach.VolumeSpec)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, volumeToDetach.GenerateErrorDetailed("DetachVolume.GetVolumeName failed", err)
 | 
								return nil, attachableVolumePlugin.GetPluginName(), volumeToDetach.GenerateErrorDetailed("DetachVolume.GetVolumeName failed", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		var pluginName string
 | 
					 | 
				
			||||||
		// Get attacher plugin and the volumeName by splitting the volume unique name in case
 | 
							// Get attacher plugin and the volumeName by splitting the volume unique name in case
 | 
				
			||||||
		// there's no VolumeSpec: this happens only on attach/detach controller crash recovery
 | 
							// there's no VolumeSpec: this happens only on attach/detach controller crash recovery
 | 
				
			||||||
		// when a pod has been deleted during the controller downtime
 | 
							// when a pod has been deleted during the controller downtime
 | 
				
			||||||
		pluginName, volumeName, err = volumehelper.SplitUniqueName(volumeToDetach.VolumeName)
 | 
							pluginName, volumeName, err = volumehelper.SplitUniqueName(volumeToDetach.VolumeName)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, volumeToDetach.GenerateErrorDetailed("DetachVolume.SplitUniqueName failed", err)
 | 
								return nil, pluginName, volumeToDetach.GenerateErrorDetailed("DetachVolume.SplitUniqueName failed", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		attachableVolumePlugin, err = og.volumePluginMgr.FindAttachablePluginByName(pluginName)
 | 
							attachableVolumePlugin, err = og.volumePluginMgr.FindAttachablePluginByName(pluginName)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, volumeToDetach.GenerateErrorDetailed("DetachVolume.FindAttachablePluginBySpec failed", err)
 | 
								return nil, pluginName, volumeToDetach.GenerateErrorDetailed("DetachVolume.FindAttachablePluginBySpec failed", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if pluginName == "" {
 | 
				
			||||||
 | 
							pluginName = attachableVolumePlugin.GetPluginName()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	volumeDetacher, err := attachableVolumePlugin.NewDetacher()
 | 
						volumeDetacher, err := attachableVolumePlugin.NewDetacher()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, volumeToDetach.GenerateErrorDetailed("DetachVolume.NewDetacher failed", err)
 | 
							return nil, pluginName, volumeToDetach.GenerateErrorDetailed("DetachVolume.NewDetacher failed", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
@@ -352,24 +357,24 @@ func (og *operationGenerator) GenerateDetachVolumeFunc(
 | 
				
			|||||||
			volumeToDetach.VolumeName, volumeToDetach.NodeName)
 | 
								volumeToDetach.VolumeName, volumeToDetach.NodeName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, pluginName, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (og *operationGenerator) GenerateMountVolumeFunc(
 | 
					func (og *operationGenerator) GenerateMountVolumeFunc(
 | 
				
			||||||
	waitForAttachTimeout time.Duration,
 | 
						waitForAttachTimeout time.Duration,
 | 
				
			||||||
	volumeToMount VolumeToMount,
 | 
						volumeToMount VolumeToMount,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldMounterUpdater,
 | 
						actualStateOfWorld ActualStateOfWorldMounterUpdater,
 | 
				
			||||||
	isRemount bool) (func() error, error) {
 | 
						isRemount bool) (func() error, string, error) {
 | 
				
			||||||
	// Get mounter plugin
 | 
						// Get mounter plugin
 | 
				
			||||||
	volumePlugin, err :=
 | 
						volumePlugin, err :=
 | 
				
			||||||
		og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
 | 
							og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
 | 
				
			||||||
	if err != nil || volumePlugin == nil {
 | 
						if err != nil || volumePlugin == nil {
 | 
				
			||||||
		return nil, volumeToMount.GenerateErrorDetailed("MountVolume.FindPluginBySpec failed", err)
 | 
							return nil, "", volumeToMount.GenerateErrorDetailed("MountVolume.FindPluginBySpec failed", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	affinityErr := checkNodeAffinity(og, volumeToMount, volumePlugin)
 | 
						affinityErr := checkNodeAffinity(og, volumeToMount, volumePlugin)
 | 
				
			||||||
	if affinityErr != nil {
 | 
						if affinityErr != nil {
 | 
				
			||||||
		return nil, affinityErr
 | 
							return nil, volumePlugin.GetPluginName(), affinityErr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	volumeMounter, newMounterErr := volumePlugin.NewMounter(
 | 
						volumeMounter, newMounterErr := volumePlugin.NewMounter(
 | 
				
			||||||
@@ -379,13 +384,13 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
 | 
				
			|||||||
	if newMounterErr != nil {
 | 
						if newMounterErr != nil {
 | 
				
			||||||
		eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.NewMounter initialization failed", newMounterErr)
 | 
							eventErr, detailedErr := volumeToMount.GenerateError("MountVolume.NewMounter initialization failed", newMounterErr)
 | 
				
			||||||
		og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FailedMountVolume, eventErr.Error())
 | 
							og.recorder.Eventf(volumeToMount.Pod, v1.EventTypeWarning, kevents.FailedMountVolume, eventErr.Error())
 | 
				
			||||||
		return nil, detailedErr
 | 
							return nil, volumePlugin.GetPluginName(), detailedErr
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mountCheckError := checkMountOptionSupport(og, volumeToMount, volumePlugin)
 | 
						mountCheckError := checkMountOptionSupport(og, volumeToMount, volumePlugin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if mountCheckError != nil {
 | 
						if mountCheckError != nil {
 | 
				
			||||||
		return nil, mountCheckError
 | 
							return nil, volumePlugin.GetPluginName(), mountCheckError
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get attacher, if possible
 | 
						// Get attacher, if possible
 | 
				
			||||||
@@ -489,23 +494,23 @@ func (og *operationGenerator) GenerateMountVolumeFunc(
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, volumePlugin.GetPluginName(), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (og *operationGenerator) GenerateUnmountVolumeFunc(
 | 
					func (og *operationGenerator) GenerateUnmountVolumeFunc(
 | 
				
			||||||
	volumeToUnmount MountedVolume,
 | 
						volumeToUnmount MountedVolume,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldMounterUpdater) (func() error, error) {
 | 
						actualStateOfWorld ActualStateOfWorldMounterUpdater) (func() error, string, error) {
 | 
				
			||||||
	// Get mountable plugin
 | 
						// Get mountable plugin
 | 
				
			||||||
	volumePlugin, err :=
 | 
						volumePlugin, err :=
 | 
				
			||||||
		og.volumePluginMgr.FindPluginByName(volumeToUnmount.PluginName)
 | 
							og.volumePluginMgr.FindPluginByName(volumeToUnmount.PluginName)
 | 
				
			||||||
	if err != nil || volumePlugin == nil {
 | 
						if err != nil || volumePlugin == nil {
 | 
				
			||||||
		return nil, volumeToUnmount.GenerateErrorDetailed("UnmountVolume.FindPluginByName failed", err)
 | 
							return nil, "", volumeToUnmount.GenerateErrorDetailed("UnmountVolume.FindPluginByName failed", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	volumeUnmounter, newUnmounterErr := volumePlugin.NewUnmounter(
 | 
						volumeUnmounter, newUnmounterErr := volumePlugin.NewUnmounter(
 | 
				
			||||||
		volumeToUnmount.InnerVolumeSpecName, volumeToUnmount.PodUID)
 | 
							volumeToUnmount.InnerVolumeSpecName, volumeToUnmount.PodUID)
 | 
				
			||||||
	if newUnmounterErr != nil {
 | 
						if newUnmounterErr != nil {
 | 
				
			||||||
		return nil, volumeToUnmount.GenerateErrorDetailed("UnmountVolume.NewUnmounter failed", newUnmounterErr)
 | 
							return nil, volumePlugin.GetPluginName(), volumeToUnmount.GenerateErrorDetailed("UnmountVolume.NewUnmounter failed", newUnmounterErr)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
@@ -535,28 +540,28 @@ func (og *operationGenerator) GenerateUnmountVolumeFunc(
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, volumePlugin.GetPluginName(), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (og *operationGenerator) GenerateUnmountDeviceFunc(
 | 
					func (og *operationGenerator) GenerateUnmountDeviceFunc(
 | 
				
			||||||
	deviceToDetach AttachedVolume,
 | 
						deviceToDetach AttachedVolume,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldMounterUpdater,
 | 
						actualStateOfWorld ActualStateOfWorldMounterUpdater,
 | 
				
			||||||
	mounter mount.Interface) (func() error, error) {
 | 
						mounter mount.Interface) (func() error, string, error) {
 | 
				
			||||||
	// Get attacher plugin
 | 
						// Get attacher plugin
 | 
				
			||||||
	attachableVolumePlugin, err :=
 | 
						attachableVolumePlugin, err :=
 | 
				
			||||||
		og.volumePluginMgr.FindAttachablePluginBySpec(deviceToDetach.VolumeSpec)
 | 
							og.volumePluginMgr.FindAttachablePluginBySpec(deviceToDetach.VolumeSpec)
 | 
				
			||||||
	if err != nil || attachableVolumePlugin == nil {
 | 
						if err != nil || attachableVolumePlugin == nil {
 | 
				
			||||||
		return nil, deviceToDetach.GenerateErrorDetailed("UnmountDevice.FindAttachablePluginBySpec failed", err)
 | 
							return nil, "", deviceToDetach.GenerateErrorDetailed("UnmountDevice.FindAttachablePluginBySpec failed", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	volumeDetacher, err := attachableVolumePlugin.NewDetacher()
 | 
						volumeDetacher, err := attachableVolumePlugin.NewDetacher()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewDetacher failed", err)
 | 
							return nil, attachableVolumePlugin.GetPluginName(), deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewDetacher failed", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	volumeAttacher, err := attachableVolumePlugin.NewAttacher()
 | 
						volumeAttacher, err := attachableVolumePlugin.NewAttacher()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewAttacher failed", err)
 | 
							return nil, attachableVolumePlugin.GetPluginName(), deviceToDetach.GenerateErrorDetailed("UnmountDevice.NewAttacher failed", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
@@ -616,13 +621,19 @@ func (og *operationGenerator) GenerateUnmountDeviceFunc(
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}, nil
 | 
						}, attachableVolumePlugin.GetPluginName(), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (og *operationGenerator) GenerateVerifyControllerAttachedVolumeFunc(
 | 
					func (og *operationGenerator) GenerateVerifyControllerAttachedVolumeFunc(
 | 
				
			||||||
	volumeToMount VolumeToMount,
 | 
						volumeToMount VolumeToMount,
 | 
				
			||||||
	nodeName types.NodeName,
 | 
						nodeName types.NodeName,
 | 
				
			||||||
	actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, error) {
 | 
						actualStateOfWorld ActualStateOfWorldAttacherUpdater) (func() error, string, error) {
 | 
				
			||||||
 | 
						volumePlugin, err :=
 | 
				
			||||||
 | 
							og.volumePluginMgr.FindPluginBySpec(volumeToMount.VolumeSpec)
 | 
				
			||||||
 | 
						if err != nil || volumePlugin == nil {
 | 
				
			||||||
 | 
							return nil, "", volumeToMount.GenerateErrorDetailed("VerifyControllerAttachedVolume.FindPluginBySpec failed", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return func() error {
 | 
						return func() error {
 | 
				
			||||||
		if !volumeToMount.PluginIsAttachable {
 | 
							if !volumeToMount.PluginIsAttachable {
 | 
				
			||||||
			// If the volume does not implement the attacher interface, it is
 | 
								// If the volume does not implement the attacher interface, it is
 | 
				
			||||||
@@ -678,7 +689,7 @@ func (og *operationGenerator) GenerateVerifyControllerAttachedVolumeFunc(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Volume not attached, return error. Caller will log and retry.
 | 
							// Volume not attached, return error. Caller will log and retry.
 | 
				
			||||||
		return volumeToMount.GenerateErrorDetailed("Volume not attached according to node status", nil)
 | 
							return volumeToMount.GenerateErrorDetailed("Volume not attached according to node status", nil)
 | 
				
			||||||
	}, nil
 | 
						}, volumePlugin.GetPluginName(), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (og *operationGenerator) verifyVolumeIsSafeToDetach(
 | 
					func (og *operationGenerator) verifyVolumeIsSafeToDetach(
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user