@@ -29,45 +29,73 @@ import (
29
29
"sync"
30
30
31
31
"k8s.io/api/core/v1"
32
+ "k8s.io/apimachinery/pkg/types"
32
33
k8sRuntime "k8s.io/apimachinery/pkg/util/runtime"
33
34
"k8s.io/klog"
34
35
"k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff"
35
- "k8s.io/kubernetes/pkg/volume/util/types"
36
+ volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
36
37
)
37
38
38
39
const (
39
40
// EmptyUniquePodName is a UniquePodName for empty string.
40
- EmptyUniquePodName types .UniquePodName = types .UniquePodName ("" )
41
+ EmptyUniquePodName volumetypes .UniquePodName = volumetypes .UniquePodName ("" )
41
42
42
43
// EmptyUniqueVolumeName is a UniqueVolumeName for empty string
43
44
EmptyUniqueVolumeName v1.UniqueVolumeName = v1 .UniqueVolumeName ("" )
45
+
46
+ // EmptyNodeName is a NodeName for empty string
47
+ EmptyNodeName types.NodeName = types .NodeName ("" )
44
48
)
45
49
46
50
// NestedPendingOperations defines the supported set of operations.
47
51
type NestedPendingOperations interface {
48
- // Run adds the concatenation of volumeName and podName to the list of
49
- // running operations and spawns a new go routine to execute operationFunc.
50
- // If an operation with the same volumeName, same or empty podName
51
- // and same operationName exits, an AlreadyExists or ExponentialBackoff
52
- // error is returned. If an operation with same volumeName and podName
53
- // has ExponentialBackoff error but operationName is different, exponential
54
- // backoff is reset and operation is allowed to proceed.
55
- // This enables multiple operations to execute in parallel for the same
56
- // volumeName as long as they have different podName.
52
+
53
+ // Run adds the concatenation of volumeName and one of podName or nodeName to
54
+ // the list of running operations and spawns a new go routine to execute
55
+ // OperationFunc inside generatedOperations.
56
+
57
+ // volumeName, podName, and nodeName collectively form the operation key.
58
+ // The following forms of operation keys are supported:
59
+ // - volumeName empty, podName empty, nodeName empty
60
+ // This key does not have any conflicting keys.
61
+ // - volumeName exists, podName empty, nodeName empty
62
+ // This key conflicts with all other keys with the same volumeName.
63
+ // - volumeName exists, podName exists, nodeName empty
64
+ // This key conflicts with:
65
+ // - the same volumeName and podName
66
+ // - the same volumeName, but no podName
67
+ // - volumeName exists, podName empty, nodeName exists
68
+ // This key conflicts with:
69
+ // - the same volumeName and nodeName
70
+ // - the same volumeName but no nodeName
71
+
72
+ // If an operation with the same operationName and a conflicting key exists,
73
+ // an AlreadyExists or ExponentialBackoff error is returned.
74
+ // If an operation with a conflicting key has ExponentialBackoff error but
75
+ // operationName is different, exponential backoff is reset and operation is
76
+ // allowed to proceed.
77
+
57
78
// Once the operation is complete, the go routine is terminated and the
58
- // concatenation of volumeName and podName is removed from the list of
59
- // executing operations allowing a new operation to be started with the
60
- // volumeName without error.
61
- Run (volumeName v1.UniqueVolumeName , podName types.UniquePodName , generatedOperations types.GeneratedOperations ) error
79
+ // concatenation of volumeName and (podName or nodeName) is removed from the
80
+ // list of executing operations allowing a new operation to be started with
81
+ // the volumeName without error.
82
+ Run (
83
+ volumeName v1.UniqueVolumeName ,
84
+ podName volumetypes.UniquePodName ,
85
+ nodeName types.NodeName ,
86
+ generatedOperations volumetypes.GeneratedOperations ) error
62
87
63
88
// Wait blocks until all operations are completed. This is typically
64
89
// necessary during tests - the test should wait until all operations finish
65
90
// and evaluate results after that.
66
91
Wait ()
67
92
68
- // IsOperationPending returns true if an operation for the given volumeName and podName is pending,
69
- // otherwise it returns false
70
- IsOperationPending (volumeName v1.UniqueVolumeName , podName types.UniquePodName ) bool
93
+ // IsOperationPending returns true if an operation for the given volumeName
94
+ // and one of podName or nodeName is pending, otherwise it returns false
95
+ IsOperationPending (
96
+ volumeName v1.UniqueVolumeName ,
97
+ podName volumetypes.UniquePodName ,
98
+ nodeName types.NodeName ) bool
71
99
}
72
100
73
101
// NewNestedPendingOperations returns a new instance of NestedPendingOperations.
@@ -96,12 +124,13 @@ type operation struct {
96
124
97
125
func (grm * nestedPendingOperations ) Run (
98
126
volumeName v1.UniqueVolumeName ,
99
- podName types.UniquePodName ,
100
- generatedOperations types.GeneratedOperations ) error {
127
+ podName volumetypes.UniquePodName ,
128
+ nodeName types.NodeName ,
129
+ generatedOperations volumetypes.GeneratedOperations ) error {
101
130
grm .lock .Lock ()
102
131
defer grm .lock .Unlock ()
103
132
104
- opKey := operationKey {volumeName , podName }
133
+ opKey := operationKey {volumeName , podName , nodeName }
105
134
106
135
opExists , previousOpIndex := grm .isOperationExists (opKey )
107
136
if opExists {
@@ -149,12 +178,13 @@ func (grm *nestedPendingOperations) Run(
149
178
150
179
func (grm * nestedPendingOperations ) IsOperationPending (
151
180
volumeName v1.UniqueVolumeName ,
152
- podName types.UniquePodName ) bool {
181
+ podName volumetypes.UniquePodName ,
182
+ nodeName types.NodeName ) bool {
153
183
154
184
grm .lock .RLock ()
155
185
defer grm .lock .RUnlock ()
156
186
157
- opKey := operationKey {volumeName , podName }
187
+ opKey := operationKey {volumeName , podName , nodeName }
158
188
exist , previousOpIndex := grm .isOperationExists (opKey )
159
189
if exist && grm .operations [previousOpIndex ].operationPending {
160
190
return true
@@ -177,8 +207,11 @@ func (grm *nestedPendingOperations) isOperationExists(key operationKey) (bool, i
177
207
key .podName == EmptyUniquePodName ||
178
208
previousOp .key .podName == key .podName
179
209
210
+ nodeNameMatch := previousOp .key .nodeName == EmptyNodeName ||
211
+ key .nodeName == EmptyNodeName ||
212
+ previousOp .key .nodeName == key .nodeName
180
213
181
- if volumeNameMatch && podNameMatch {
214
+ if volumeNameMatch && podNameMatch && nodeNameMatch {
182
215
return true , previousOpIndex
183
216
}
184
217
}
@@ -264,15 +297,15 @@ func (grm *nestedPendingOperations) Wait() {
264
297
265
298
type operationKey struct {
266
299
volumeName v1.UniqueVolumeName
267
- podName types.UniquePodName
300
+ podName volumetypes.UniquePodName
301
+ nodeName types.NodeName
268
302
}
269
303
270
304
func (key operationKey ) String () string {
271
- podNameStr := fmt .Sprintf (" (%q)" , key .podName )
272
-
273
- return fmt .Sprintf ("%q%s" ,
305
+ return fmt .Sprintf ("{volumeName=%q, podName=%q, nodeName=%q}" ,
274
306
key .volumeName ,
275
- podNameStr )
307
+ key .podName ,
308
+ key .nodeName )
276
309
}
277
310
278
311
// NewAlreadyExistsError returns a new instance of AlreadyExists error.
0 commit comments