...

Source file src/k8s.io/kubernetes/pkg/volume/csi/expander.go

Documentation: k8s.io/kubernetes/pkg/volume/csi

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package csi
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  
    23  	"google.golang.org/grpc/codes"
    24  	"google.golang.org/grpc/status"
    25  	api "k8s.io/api/core/v1"
    26  	"k8s.io/klog/v2"
    27  	"k8s.io/kubernetes/pkg/volume"
    28  	"k8s.io/kubernetes/pkg/volume/util"
    29  	volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
    30  )
    31  
    32  var _ volume.NodeExpandableVolumePlugin = &csiPlugin{}
    33  
    34  func (c *csiPlugin) RequiresFSResize() bool {
    35  	return true
    36  }
    37  
    38  func (c *csiPlugin) NodeExpand(resizeOptions volume.NodeResizeOptions) (bool, error) {
    39  	klog.V(4).Infof(log("Expander.NodeExpand(%s)", resizeOptions.DeviceMountPath))
    40  	csiSource, err := getCSISourceFromSpec(resizeOptions.VolumeSpec)
    41  	if err != nil {
    42  		return false, errors.New(log("Expander.NodeExpand failed to get CSI persistent source: %v", err))
    43  	}
    44  
    45  	csClient, err := newCsiDriverClient(csiDriverName(csiSource.Driver))
    46  	if err != nil {
    47  		// Treat the absence of the CSI driver as a transient error
    48  		// See https://github.com/kubernetes/kubernetes/issues/120268
    49  		return false, volumetypes.NewTransientOperationFailure(err.Error())
    50  	}
    51  	fsVolume, err := util.CheckVolumeModeFilesystem(resizeOptions.VolumeSpec)
    52  	if err != nil {
    53  		return false, errors.New(log("Expander.NodeExpand failed to check VolumeMode of source: %v", err))
    54  	}
    55  
    56  	return c.nodeExpandWithClient(resizeOptions, csiSource, csClient, fsVolume)
    57  }
    58  
    59  func (c *csiPlugin) nodeExpandWithClient(
    60  	resizeOptions volume.NodeResizeOptions,
    61  	csiSource *api.CSIPersistentVolumeSource,
    62  	csClient csiClient,
    63  	fsVolume bool) (bool, error) {
    64  	driverName := csiSource.Driver
    65  
    66  	ctx, cancel := createCSIOperationContext(resizeOptions.VolumeSpec, csiTimeout)
    67  	defer cancel()
    68  
    69  	nodeExpandSet, err := csClient.NodeSupportsNodeExpand(ctx)
    70  	if err != nil {
    71  		return false, fmt.Errorf("Expander.NodeExpand failed to check if node supports expansion : %v", err)
    72  	}
    73  
    74  	if !nodeExpandSet {
    75  		return false, volumetypes.NewOperationNotSupportedError(fmt.Sprintf("NodeExpand is not supported by the CSI driver %s", driverName))
    76  	}
    77  
    78  	pv := resizeOptions.VolumeSpec.PersistentVolume
    79  	if pv == nil {
    80  		return false, fmt.Errorf("Expander.NodeExpand failed to find associated PersistentVolume for plugin %s", c.GetPluginName())
    81  	}
    82  	nodeExpandSecrets := map[string]string{}
    83  	expandClient := c.host.GetKubeClient()
    84  
    85  	if csiSource.NodeExpandSecretRef != nil {
    86  		nodeExpandSecrets, err = getCredentialsFromSecret(expandClient, csiSource.NodeExpandSecretRef)
    87  		if err != nil {
    88  			return false, fmt.Errorf("expander.NodeExpand failed to get NodeExpandSecretRef %s/%s: %v",
    89  				csiSource.NodeExpandSecretRef.Namespace, csiSource.NodeExpandSecretRef.Name, err)
    90  		}
    91  	}
    92  
    93  	opts := csiResizeOptions{
    94  		volumePath:        resizeOptions.DeviceMountPath,
    95  		stagingTargetPath: resizeOptions.DeviceStagePath,
    96  		volumeID:          csiSource.VolumeHandle,
    97  		newSize:           resizeOptions.NewSize,
    98  		fsType:            csiSource.FSType,
    99  		accessMode:        api.ReadWriteOnce,
   100  		mountOptions:      pv.Spec.MountOptions,
   101  		secrets:           nodeExpandSecrets,
   102  	}
   103  
   104  	if !fsVolume {
   105  		// for block volumes the volumePath in CSI NodeExpandvolumeRequest is
   106  		// basically same as DevicePath because block devices are not mounted and hence
   107  		// DeviceMountPath does not get populated in resizeOptions.DeviceMountPath
   108  		opts.volumePath = resizeOptions.DevicePath
   109  		opts.fsType = fsTypeBlockName
   110  	}
   111  
   112  	if pv.Spec.AccessModes != nil {
   113  		opts.accessMode = pv.Spec.AccessModes[0]
   114  	}
   115  
   116  	_, err = csClient.NodeExpandVolume(ctx, opts)
   117  	if err != nil {
   118  		if inUseError(err) {
   119  			failedConditionErr := fmt.Errorf("Expander.NodeExpand failed to expand the volume : %w", volumetypes.NewFailedPreconditionError(err.Error()))
   120  			return false, failedConditionErr
   121  		}
   122  		return false, fmt.Errorf("Expander.NodeExpand failed to expand the volume : %w", err)
   123  	}
   124  	return true, nil
   125  }
   126  
   127  func inUseError(err error) bool {
   128  	st, ok := status.FromError(err)
   129  	if !ok {
   130  		// not a grpc error
   131  		return false
   132  	}
   133  	// if this is a failed precondition error then that means driver does not support expansion
   134  	// of in-use volumes
   135  	// More info - https://github.com/container-storage-interface/spec/blob/master/spec.md#controllerexpandvolume-errors
   136  	return st.Code() == codes.FailedPrecondition
   137  }
   138  

View as plain text