@@ -24,7 +24,7 @@ import (
24
24
"strings"
25
25
"time"
26
26
27
- v1 "k8s.io/api/core/v1"
27
+ "k8s.io/api/core/v1"
28
28
"k8s.io/apimachinery/pkg/types"
29
29
"k8s.io/apimachinery/pkg/util/wait"
30
30
"k8s.io/client-go/tools/record"
@@ -34,7 +34,7 @@ import (
34
34
"k8s.io/kubernetes/pkg/controller/volume/attachdetach/statusupdater"
35
35
kevents "k8s.io/kubernetes/pkg/kubelet/events"
36
36
"k8s.io/kubernetes/pkg/util/goroutinemap/exponentialbackoff"
37
- "k8s.io/kubernetes/pkg/volume/util "
37
+ "k8s.io/kubernetes/pkg/volume"
38
38
"k8s.io/kubernetes/pkg/volume/util/operationexecutor"
39
39
)
40
40
@@ -134,6 +134,42 @@ func (rc *reconciler) syncStates() {
134
134
rc .attacherDetacher .VerifyVolumesAreAttached (volumesPerNode , rc .actualStateOfWorld )
135
135
}
136
136
137
+ // isMultiAttachForbidden checks if attaching this volume to multiple nodes is definitely not allowed/possible.
138
+ // In its current form, this function can only reliably say for which volumes it's definitely forbidden. If it returns
139
+ // false, it is not guaranteed that multi-attach is actually supported by the volume type and we must rely on the
140
+ // attacher to fail fast in such cases.
141
+ // Please see https://github.com/kubernetes/kubernetes/issues/40669 and https://github.com/kubernetes/kubernetes/pull/40148#discussion_r98055047
142
+ func (rc * reconciler ) isMultiAttachForbidden (volumeSpec * volume.Spec ) bool {
143
+ if volumeSpec .Volume != nil {
144
+ // Check for volume types which are known to fail slow or cause trouble when trying to multi-attach
145
+ if volumeSpec .Volume .AzureDisk != nil ||
146
+ volumeSpec .Volume .Cinder != nil {
147
+ return true
148
+ }
149
+ }
150
+
151
+ // Only if this volume is a persistent volume, we have reliable information on whether it's allowed or not to
152
+ // multi-attach. We trust in the individual volume implementations to not allow unsupported access modes
153
+ if volumeSpec .PersistentVolume != nil {
154
+ // Check for persistent volume types which do not fail when trying to multi-attach
155
+ if len (volumeSpec .PersistentVolume .Spec .AccessModes ) == 0 {
156
+ // No access mode specified so we don't know for sure. Let the attacher fail if needed
157
+ return false
158
+ }
159
+
160
+ // check if this volume is allowed to be attached to multiple PODs/nodes, if yes, return false
161
+ for _ , accessMode := range volumeSpec .PersistentVolume .Spec .AccessModes {
162
+ if accessMode == v1 .ReadWriteMany || accessMode == v1 .ReadOnlyMany {
163
+ return false
164
+ }
165
+ }
166
+ return true
167
+ }
168
+
169
+ // we don't know if it's supported or not and let the attacher fail later in cases it's not supported
170
+ return false
171
+ }
172
+
137
173
func (rc * reconciler ) reconcile () {
138
174
// Detaches are triggered before attaches so that volumes referenced by
139
175
// pods that are rescheduled to a different node are detached first.
@@ -146,16 +182,9 @@ func (rc *reconciler) reconcile() {
146
182
// This check must be done before we do any other checks, as otherwise the other checks
147
183
// may pass while at the same time the volume leaves the pending state, resulting in
148
184
// double detach attempts
149
- if util .IsMultiAttachForbidden (attachedVolume .VolumeSpec ) {
150
- if rc .attacherDetacher .IsOperationPending (attachedVolume .VolumeName , "" /* podName */ , "" /* nodeName */ ) {
151
- klog .V (10 ).Infof ("Operation for volume %q is already running in the cluster. Can't start detach for %q" , attachedVolume .VolumeName , attachedVolume .NodeName )
152
- continue
153
- }
154
- } else {
155
- if rc .attacherDetacher .IsOperationPending (attachedVolume .VolumeName , "" /* podName */ , attachedVolume .NodeName ) {
156
- klog .V (10 ).Infof ("Operation for volume %q is already running for node %q. Can't start detach" , attachedVolume .VolumeName , attachedVolume .NodeName )
157
- continue
158
- }
185
+ if rc .attacherDetacher .IsOperationPending (attachedVolume .VolumeName , "" ) {
186
+ klog .V (10 ).Infof ("Operation for volume %q is already running. Can't start detach for %q" , attachedVolume .VolumeName , attachedVolume .NodeName )
187
+ continue
159
188
}
160
189
161
190
// Set the detach request time
@@ -231,17 +260,15 @@ func (rc *reconciler) attachDesiredVolumes() {
231
260
rc .actualStateOfWorld .ResetDetachRequestTime (volumeToAttach .VolumeName , volumeToAttach .NodeName )
232
261
continue
233
262
}
234
-
235
- if util .IsMultiAttachForbidden (volumeToAttach .VolumeSpec ) {
236
-
237
- // Don't even try to start an operation if there is already one running for the given volume
238
- if rc .attacherDetacher .IsOperationPending (volumeToAttach .VolumeName , "" /* podName */ , "" /* nodeName */ ) {
239
- if klog .V (10 ) {
240
- klog .Infof ("Operation for volume %q is already running. Can't start attach for %q" , volumeToAttach .VolumeName , volumeToAttach .NodeName )
241
- }
242
- continue
263
+ // Don't even try to start an operation if there is already one running
264
+ if rc .attacherDetacher .IsOperationPending (volumeToAttach .VolumeName , "" ) {
265
+ if klog .V (10 ) {
266
+ klog .Infof ("Operation for volume %q is already running. Can't start attach for %q" , volumeToAttach .VolumeName , volumeToAttach .NodeName )
243
267
}
268
+ continue
269
+ }
244
270
271
+ if rc .isMultiAttachForbidden (volumeToAttach .VolumeSpec ) {
245
272
nodes := rc .actualStateOfWorld .GetNodesForAttachedVolume (volumeToAttach .VolumeName )
246
273
if len (nodes ) > 0 {
247
274
if ! volumeToAttach .MultiAttachErrorReported {
@@ -250,17 +277,6 @@ func (rc *reconciler) attachDesiredVolumes() {
250
277
}
251
278
continue
252
279
}
253
-
254
- } else {
255
-
256
- // Don't even try to start an operation if there is already one running for the given volume and node.
257
- if rc .attacherDetacher .IsOperationPending (volumeToAttach .VolumeName , "" /* podName */ , volumeToAttach .NodeName ) {
258
- if klog .V (10 ) {
259
- klog .Infof ("Operation for volume %q is already running for node %q. Can't start attach" , volumeToAttach .VolumeName , volumeToAttach .NodeName )
260
- }
261
- continue
262
- }
263
-
264
280
}
265
281
266
282
// Volume/Node doesn't exist, spawn a goroutine to attach it
0 commit comments