github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edge/pkg/edged/volume/csi/csi_client.go (about)

     1  /*
     2  Copyright 2017 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  @CHANGELOG
    17  KubeEdge Authors: To create mini-kubelet for edge deployment scenario,
    18  this file is derived from kubernetes v1.15.3,
    19  and the full file path is k8s.io/kubernetes/pkg/volume/csi/csi_client.go
    20  and make some modifications including:
    21  1. add controllerV1ClientCreator
    22  2. add CreateVolume function.
    23  3. add DeleteVolume function.
    24  4. add ControllerPublishVolume function.
    25  5. add ControllerUnpublishVolume function.
    26  6. add ControllerGetCapabilities function.
    27  */
    28  
    29  package csi
    30  
    31  import (
    32  	"context"
    33  	"errors"
    34  	"fmt"
    35  	"io"
    36  	"net"
    37  	"strings"
    38  	"sync"
    39  	"time"
    40  
    41  	csipbv1 "github.com/container-storage-interface/spec/lib/go/csi"
    42  	"google.golang.org/grpc"
    43  	api "k8s.io/api/core/v1"
    44  	"k8s.io/apimachinery/pkg/api/resource"
    45  	utilversion "k8s.io/apimachinery/pkg/util/version"
    46  	"k8s.io/apimachinery/pkg/util/wait"
    47  	"k8s.io/klog"
    48  	"k8s.io/kubernetes/pkg/volume"
    49  )
    50  
    51  type csiClient interface {
    52  	NodeGetInfo(ctx context.Context) (
    53  		nodeID string,
    54  		maxVolumePerNode int64,
    55  		accessibleTopology map[string]string,
    56  		err error)
    57  	NodePublishVolume(
    58  		ctx context.Context,
    59  		volumeid string,
    60  		readOnly bool,
    61  		stagingTargetPath string,
    62  		targetPath string,
    63  		accessMode api.PersistentVolumeAccessMode,
    64  		publishContext map[string]string,
    65  		volumeContext map[string]string,
    66  		secrets map[string]string,
    67  		fsType string,
    68  		mountOptions []string,
    69  	) error
    70  	NodeExpandVolume(ctx context.Context, volumeid, volumePath string, newSize resource.Quantity) (resource.Quantity, error)
    71  	NodeUnpublishVolume(
    72  		ctx context.Context,
    73  		volID string,
    74  		targetPath string,
    75  	) error
    76  	NodeStageVolume(ctx context.Context,
    77  		volID string,
    78  		publishVolumeInfo map[string]string,
    79  		stagingTargetPath string,
    80  		fsType string,
    81  		accessMode api.PersistentVolumeAccessMode,
    82  		secrets map[string]string,
    83  		volumeContext map[string]string,
    84  	) error
    85  
    86  	NodeGetVolumeStats(
    87  		ctx context.Context,
    88  		volID string,
    89  		targetPath string,
    90  	) (*volume.Metrics, error)
    91  	NodeUnstageVolume(ctx context.Context, volID, stagingTargetPath string) error
    92  	NodeSupportsStageUnstage(ctx context.Context) (bool, error)
    93  	NodeSupportsNodeExpand(ctx context.Context) (bool, error)
    94  	NodeSupportsVolumeStats(ctx context.Context) (bool, error)
    95  	CreateVolume(ctx context.Context, req *csipbv1.CreateVolumeRequest) (*csipbv1.CreateVolumeResponse, error)
    96  	DeleteVolume(ctx context.Context, req *csipbv1.DeleteVolumeRequest) (*csipbv1.DeleteVolumeResponse, error)
    97  	ControllerPublishVolume(ctx context.Context, req *csipbv1.ControllerPublishVolumeRequest) (*csipbv1.ControllerPublishVolumeResponse, error)
    98  	ControllerUnpublishVolume(ctx context.Context, req *csipbv1.ControllerUnpublishVolumeRequest) (*csipbv1.ControllerUnpublishVolumeResponse, error)
    99  	ControllerGetCapabilities(ctx context.Context, req *csipbv1.ControllerGetCapabilitiesRequest) (*csipbv1.ControllerGetCapabilitiesResponse, error)
   100  }
   101  
   102  // Strongly typed address
   103  type csiAddr string
   104  
   105  // Strongly typed driver name
   106  type csiDriverName string
   107  
   108  // csiClient encapsulates all csi-plugin methods
   109  type csiDriverClient struct {
   110  	driverName                csiDriverName
   111  	addr                      csiAddr
   112  	nodeV1ClientCreator       nodeV1ClientCreator
   113  	controllerV1ClientCreator controllerV1ClientCreator
   114  }
   115  
   116  var _ csiClient = &csiDriverClient{}
   117  
   118  type nodeV1ClientCreator func(addr csiAddr) (
   119  	nodeClient csipbv1.NodeClient,
   120  	closer io.Closer,
   121  	err error,
   122  )
   123  
   124  type controllerV1ClientCreator func(addr csiAddr) (
   125  	controllerClient csipbv1.ControllerClient,
   126  	closer io.Closer,
   127  	err error,
   128  )
   129  
   130  const (
   131  	initialDuration = 1 * time.Second
   132  	factor          = 2.0
   133  	steps           = 5
   134  )
   135  
   136  func newV1ControllerClient(addr csiAddr) (controllerClient csipbv1.ControllerClient, closer io.Closer, err error) {
   137  	var conn *grpc.ClientConn
   138  	conn, err = newGrpcConn(addr)
   139  	if err != nil {
   140  		return nil, nil, err
   141  	}
   142  
   143  	controllerClient = csipbv1.NewControllerClient(conn)
   144  	return controllerClient, conn, nil
   145  }
   146  
   147  // newV1NodeClient creates a new NodeClient with the internally used gRPC
   148  // connection set up. It also returns a closer which must to be called to close
   149  // the gRPC connection when the NodeClient is not used anymore.
   150  // This is the default implementation for the nodeV1ClientCreator, used in
   151  // newCsiDriverClient.
   152  func newV1NodeClient(addr csiAddr) (nodeClient csipbv1.NodeClient, closer io.Closer, err error) {
   153  	var conn *grpc.ClientConn
   154  	conn, err = newGrpcConn(addr)
   155  	if err != nil {
   156  		return nil, nil, err
   157  	}
   158  
   159  	nodeClient = csipbv1.NewNodeClient(conn)
   160  	return nodeClient, conn, nil
   161  }
   162  
   163  // newV0NodeClient creates a new NodeClient with the internally used gRPC
   164  // connection set up. It also returns a closer which must to be called to close
   165  // the gRPC connection when the NodeClient is not used anymore.
   166  // This is the default implementation for the nodeV1ClientCreator, used in
   167  // newCsiDriverClient.
   168  func newV0NodeClient(addr csiAddr) (nodeClient csipbv1.NodeClient, closer io.Closer, err error) {
   169  	var conn *grpc.ClientConn
   170  	conn, err = newGrpcConn(addr)
   171  	if err != nil {
   172  		return nil, nil, err
   173  	}
   174  
   175  	nodeClient = csipbv1.NewNodeClient(conn)
   176  	return nodeClient, conn, nil
   177  }
   178  
   179  func newCsiDriverClient(driverName csiDriverName) (*csiDriverClient, error) {
   180  	if driverName == "" {
   181  		return nil, fmt.Errorf("driver name is empty")
   182  	}
   183  
   184  	addr := fmt.Sprintf(csiAddrTemplate, driverName)
   185  	requiresV0Client := true
   186  
   187  	existingDriver, driverExists := csiDrivers.Get(string(driverName))
   188  	if !driverExists {
   189  		return nil, fmt.Errorf("driver name %s not found in the list of registered CSI drivers", driverName)
   190  	}
   191  
   192  	addr = existingDriver.endpoint
   193  	requiresV0Client = versionRequiresV0Client(existingDriver.highestSupportedVersion)
   194  
   195  	nodeV1ClientCreator := newV1NodeClient
   196  	if requiresV0Client {
   197  		nodeV1ClientCreator = nil
   198  	}
   199  
   200  	return &csiDriverClient{
   201  		driverName:                driverName,
   202  		addr:                      csiAddr(addr),
   203  		nodeV1ClientCreator:       nodeV1ClientCreator,
   204  		controllerV1ClientCreator: newV1ControllerClient,
   205  	}, nil
   206  }
   207  
   208  func (c *csiDriverClient) NodeGetInfo(ctx context.Context) (
   209  	nodeID string,
   210  	maxVolumePerNode int64,
   211  	accessibleTopology map[string]string,
   212  	err error) {
   213  	klog.V(4).Info(log("calling NodeGetInfo rpc"))
   214  
   215  	// TODO retries should happen at a lower layer (issue #73371)
   216  	backoff := wait.Backoff{Duration: initialDuration, Factor: factor, Steps: steps}
   217  	err = wait.ExponentialBackoff(backoff, func() (bool, error) {
   218  		var getNodeInfoError error
   219  		if c.nodeV1ClientCreator != nil {
   220  			nodeID, maxVolumePerNode, accessibleTopology, getNodeInfoError = c.nodeGetInfoV1(ctx)
   221  		} else if c.nodeV1ClientCreator != nil {
   222  			nodeID, maxVolumePerNode, accessibleTopology, getNodeInfoError = c.nodeGetInfoV0(ctx)
   223  		}
   224  		if nodeID != "" {
   225  			return true, nil
   226  		}
   227  		// kubelet plugin registration service not implemented is a terminal error, no need to retry
   228  		if strings.Contains(getNodeInfoError.Error(), "no handler registered for plugin type") {
   229  			return false, getNodeInfoError
   230  		}
   231  		// Continue with exponential backoff
   232  		return false, nil
   233  	})
   234  
   235  	return nodeID, maxVolumePerNode, accessibleTopology, err
   236  }
   237  
   238  func (c *csiDriverClient) nodeGetInfoV1(ctx context.Context) (
   239  	nodeID string,
   240  	maxVolumePerNode int64,
   241  	accessibleTopology map[string]string,
   242  	err error) {
   243  
   244  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   245  	if err != nil {
   246  		return "", 0, nil, err
   247  	}
   248  	defer closer.Close()
   249  
   250  	res, err := nodeClient.NodeGetInfo(ctx, &csipbv1.NodeGetInfoRequest{})
   251  	if err != nil {
   252  		return "", 0, nil, err
   253  	}
   254  
   255  	topology := res.GetAccessibleTopology()
   256  	if topology != nil {
   257  		accessibleTopology = topology.Segments
   258  	}
   259  	return res.GetNodeId(), res.GetMaxVolumesPerNode(), accessibleTopology, nil
   260  }
   261  
   262  func (c *csiDriverClient) nodeGetInfoV0(ctx context.Context) (
   263  	nodeID string,
   264  	maxVolumePerNode int64,
   265  	accessibleTopology map[string]string,
   266  	err error) {
   267  
   268  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   269  	if err != nil {
   270  		return "", 0, nil, err
   271  	}
   272  	defer closer.Close()
   273  
   274  	res, err := nodeClient.NodeGetInfo(ctx, &csipbv1.NodeGetInfoRequest{})
   275  	if err != nil {
   276  		return "", 0, nil, err
   277  	}
   278  
   279  	topology := res.GetAccessibleTopology()
   280  	if topology != nil {
   281  		accessibleTopology = topology.Segments
   282  	}
   283  	return res.GetNodeId(), res.GetMaxVolumesPerNode(), accessibleTopology, nil
   284  }
   285  
   286  func (c *csiDriverClient) NodePublishVolume(
   287  	ctx context.Context,
   288  	volID string,
   289  	readOnly bool,
   290  	stagingTargetPath string,
   291  	targetPath string,
   292  	accessMode api.PersistentVolumeAccessMode,
   293  	publishContext map[string]string,
   294  	volumeContext map[string]string,
   295  	secrets map[string]string,
   296  	fsType string,
   297  	mountOptions []string,
   298  ) error {
   299  	klog.V(4).Info(log("calling NodePublishVolume rpc [volid=%s,target_path=%s]", volID, targetPath))
   300  	if volID == "" {
   301  		return errors.New("missing volume id")
   302  	}
   303  	if targetPath == "" {
   304  		return errors.New("missing target path")
   305  	}
   306  	if c.nodeV1ClientCreator != nil {
   307  		return c.nodePublishVolumeV1(
   308  			ctx,
   309  			volID,
   310  			readOnly,
   311  			stagingTargetPath,
   312  			targetPath,
   313  			accessMode,
   314  			publishContext,
   315  			volumeContext,
   316  			secrets,
   317  			fsType,
   318  			mountOptions,
   319  		)
   320  	}
   321  
   322  	return fmt.Errorf("failed to call NodePublishVolume. Both nodeV1ClientCreator and nodeV0ClientCreator are nil")
   323  
   324  }
   325  
   326  func (c *csiDriverClient) NodeExpandVolume(ctx context.Context, volumeID, volumePath string, newSize resource.Quantity) (resource.Quantity, error) {
   327  	if c.nodeV1ClientCreator == nil {
   328  		return newSize, fmt.Errorf("version of CSI driver does not support volume expansion")
   329  	}
   330  
   331  	if volumeID == "" {
   332  		return newSize, errors.New("missing volume id")
   333  	}
   334  	if volumePath == "" {
   335  		return newSize, errors.New("missing volume path")
   336  	}
   337  
   338  	if newSize.Value() < 0 {
   339  		return newSize, errors.New("size can not be less than 0")
   340  	}
   341  
   342  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   343  	if err != nil {
   344  		return newSize, err
   345  	}
   346  	defer closer.Close()
   347  
   348  	req := &csipbv1.NodeExpandVolumeRequest{
   349  		VolumeId:      volumeID,
   350  		VolumePath:    volumePath,
   351  		CapacityRange: &csipbv1.CapacityRange{RequiredBytes: newSize.Value()},
   352  	}
   353  	resp, err := nodeClient.NodeExpandVolume(ctx, req)
   354  	if err != nil {
   355  		return newSize, err
   356  	}
   357  	updatedQuantity := resource.NewQuantity(resp.CapacityBytes, resource.BinarySI)
   358  	return *updatedQuantity, nil
   359  }
   360  
   361  func (c *csiDriverClient) nodePublishVolumeV1(
   362  	ctx context.Context,
   363  	volID string,
   364  	readOnly bool,
   365  	stagingTargetPath string,
   366  	targetPath string,
   367  	accessMode api.PersistentVolumeAccessMode,
   368  	publishContext map[string]string,
   369  	volumeContext map[string]string,
   370  	secrets map[string]string,
   371  	fsType string,
   372  	mountOptions []string,
   373  ) error {
   374  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   375  	if err != nil {
   376  		return err
   377  	}
   378  	defer closer.Close()
   379  
   380  	req := &csipbv1.NodePublishVolumeRequest{
   381  		VolumeId:       volID,
   382  		TargetPath:     targetPath,
   383  		Readonly:       readOnly,
   384  		PublishContext: publishContext,
   385  		VolumeContext:  volumeContext,
   386  		Secrets:        secrets,
   387  		VolumeCapability: &csipbv1.VolumeCapability{
   388  			AccessMode: &csipbv1.VolumeCapability_AccessMode{
   389  				Mode: asCSIAccessModeV1(accessMode),
   390  			},
   391  		},
   392  	}
   393  	if stagingTargetPath != "" {
   394  		req.StagingTargetPath = stagingTargetPath
   395  	}
   396  
   397  	if fsType == fsTypeBlockName {
   398  		req.VolumeCapability.AccessType = &csipbv1.VolumeCapability_Block{
   399  			Block: &csipbv1.VolumeCapability_BlockVolume{},
   400  		}
   401  	} else {
   402  		req.VolumeCapability.AccessType = &csipbv1.VolumeCapability_Mount{
   403  			Mount: &csipbv1.VolumeCapability_MountVolume{
   404  				FsType:     fsType,
   405  				MountFlags: mountOptions,
   406  			},
   407  		}
   408  	}
   409  
   410  	_, err = nodeClient.NodePublishVolume(ctx, req)
   411  	return err
   412  }
   413  
   414  func (c *csiDriverClient) NodeUnpublishVolume(ctx context.Context, volID string, targetPath string) error {
   415  	klog.V(4).Info(log("calling NodeUnpublishVolume rpc: [volid=%s, target_path=%s", volID, targetPath))
   416  	if volID == "" {
   417  		return errors.New("missing volume id")
   418  	}
   419  	if targetPath == "" {
   420  		return errors.New("missing target path")
   421  	}
   422  
   423  	if c.nodeV1ClientCreator != nil {
   424  		return c.nodeUnpublishVolumeV1(ctx, volID, targetPath)
   425  	}
   426  
   427  	return fmt.Errorf("failed to call NodeUnpublishVolume. Both nodeV1ClientCreator and nodeV0ClientCreator are nil")
   428  }
   429  
   430  func (c *csiDriverClient) nodeUnpublishVolumeV1(ctx context.Context, volID string, targetPath string) error {
   431  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   432  	if err != nil {
   433  		return err
   434  	}
   435  	defer closer.Close()
   436  
   437  	req := &csipbv1.NodeUnpublishVolumeRequest{
   438  		VolumeId:   volID,
   439  		TargetPath: targetPath,
   440  	}
   441  
   442  	_, err = nodeClient.NodeUnpublishVolume(ctx, req)
   443  	return err
   444  }
   445  
   446  func (c *csiDriverClient) nodeUnpublishVolumeV0(ctx context.Context, volID string, targetPath string) error {
   447  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   448  	if err != nil {
   449  		return err
   450  	}
   451  	defer closer.Close()
   452  
   453  	req := &csipbv1.NodeUnpublishVolumeRequest{
   454  		VolumeId:   volID,
   455  		TargetPath: targetPath,
   456  	}
   457  
   458  	_, err = nodeClient.NodeUnpublishVolume(ctx, req)
   459  	return err
   460  }
   461  
   462  func (c *csiDriverClient) NodeStageVolume(ctx context.Context,
   463  	volID string,
   464  	publishContext map[string]string,
   465  	stagingTargetPath string,
   466  	fsType string,
   467  	accessMode api.PersistentVolumeAccessMode,
   468  	secrets map[string]string,
   469  	volumeContext map[string]string,
   470  ) error {
   471  	klog.V(4).Info(log("calling NodeStageVolume rpc [volid=%s,staging_target_path=%s]", volID, stagingTargetPath))
   472  	if volID == "" {
   473  		return errors.New("missing volume id")
   474  	}
   475  	if stagingTargetPath == "" {
   476  		return errors.New("missing staging target path")
   477  	}
   478  
   479  	if c.nodeV1ClientCreator != nil {
   480  		return c.nodeStageVolumeV1(ctx, volID, publishContext, stagingTargetPath, fsType, accessMode, secrets, volumeContext)
   481  	}
   482  
   483  	return fmt.Errorf("failed to call NodeStageVolume. Both nodeV1ClientCreator and nodeV0ClientCreator are nil")
   484  }
   485  
   486  func (c *csiDriverClient) nodeStageVolumeV1(
   487  	ctx context.Context,
   488  	volID string,
   489  	publishContext map[string]string,
   490  	stagingTargetPath string,
   491  	fsType string,
   492  	accessMode api.PersistentVolumeAccessMode,
   493  	secrets map[string]string,
   494  	volumeContext map[string]string,
   495  ) error {
   496  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   497  	if err != nil {
   498  		return err
   499  	}
   500  	defer closer.Close()
   501  
   502  	req := &csipbv1.NodeStageVolumeRequest{
   503  		VolumeId:          volID,
   504  		PublishContext:    publishContext,
   505  		StagingTargetPath: stagingTargetPath,
   506  		VolumeCapability: &csipbv1.VolumeCapability{
   507  			AccessMode: &csipbv1.VolumeCapability_AccessMode{
   508  				Mode: asCSIAccessModeV1(accessMode),
   509  			},
   510  		},
   511  		Secrets:       secrets,
   512  		VolumeContext: volumeContext,
   513  	}
   514  
   515  	if fsType == fsTypeBlockName {
   516  		req.VolumeCapability.AccessType = &csipbv1.VolumeCapability_Block{
   517  			Block: &csipbv1.VolumeCapability_BlockVolume{},
   518  		}
   519  	} else {
   520  		req.VolumeCapability.AccessType = &csipbv1.VolumeCapability_Mount{
   521  			Mount: &csipbv1.VolumeCapability_MountVolume{
   522  				FsType: fsType,
   523  			},
   524  		}
   525  	}
   526  
   527  	_, err = nodeClient.NodeStageVolume(ctx, req)
   528  	return err
   529  }
   530  
   531  func (c *csiDriverClient) NodeUnstageVolume(ctx context.Context, volID, stagingTargetPath string) error {
   532  	klog.V(4).Info(log("calling NodeUnstageVolume rpc [volid=%s,staging_target_path=%s]", volID, stagingTargetPath))
   533  	if volID == "" {
   534  		return errors.New("missing volume id")
   535  	}
   536  	if stagingTargetPath == "" {
   537  		return errors.New("missing staging target path")
   538  	}
   539  
   540  	if c.nodeV1ClientCreator != nil {
   541  		return c.nodeUnstageVolumeV1(ctx, volID, stagingTargetPath)
   542  	}
   543  
   544  	return fmt.Errorf("failed to call NodeUnstageVolume. Both nodeV1ClientCreator and nodeV0ClientCreator are nil")
   545  }
   546  
   547  func (c *csiDriverClient) nodeUnstageVolumeV1(ctx context.Context, volID, stagingTargetPath string) error {
   548  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   549  	if err != nil {
   550  		return err
   551  	}
   552  	defer closer.Close()
   553  
   554  	req := &csipbv1.NodeUnstageVolumeRequest{
   555  		VolumeId:          volID,
   556  		StagingTargetPath: stagingTargetPath,
   557  	}
   558  	_, err = nodeClient.NodeUnstageVolume(ctx, req)
   559  	return err
   560  }
   561  
   562  func (c *csiDriverClient) NodeSupportsNodeExpand(ctx context.Context) (bool, error) {
   563  	klog.V(4).Info(log("calling NodeGetCapabilities rpc to determine if Node has EXPAND_VOLUME capability"))
   564  
   565  	if c.nodeV1ClientCreator != nil {
   566  		nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   567  		if err != nil {
   568  			return false, err
   569  		}
   570  		defer closer.Close()
   571  
   572  		req := &csipbv1.NodeGetCapabilitiesRequest{}
   573  		resp, err := nodeClient.NodeGetCapabilities(ctx, req)
   574  		if err != nil {
   575  			return false, err
   576  		}
   577  
   578  		capabilities := resp.GetCapabilities()
   579  
   580  		if capabilities == nil {
   581  			return false, nil
   582  		}
   583  		for _, capability := range capabilities {
   584  			if capability.GetRpc().GetType() == csipbv1.NodeServiceCapability_RPC_EXPAND_VOLUME {
   585  				return true, nil
   586  			}
   587  		}
   588  		return false, nil
   589  	}
   590  
   591  	return false, fmt.Errorf("failed to call NodeSupportsNodeExpand. Both nodeV1ClientCreator and nodeV0ClientCreator are nil")
   592  
   593  }
   594  
   595  func (c *csiDriverClient) NodeSupportsStageUnstage(ctx context.Context) (bool, error) {
   596  	klog.V(4).Info(log("calling NodeGetCapabilities rpc to determine if NodeSupportsStageUnstage"))
   597  
   598  	if c.nodeV1ClientCreator != nil {
   599  		return c.nodeSupportsStageUnstageV1(ctx)
   600  	}
   601  
   602  	return false, fmt.Errorf("failed to call NodeSupportsStageUnstage. Both nodeV1ClientCreator and nodeV0ClientCreator are nil")
   603  }
   604  
   605  func (c *csiDriverClient) nodeSupportsStageUnstageV1(ctx context.Context) (bool, error) {
   606  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   607  	if err != nil {
   608  		return false, err
   609  	}
   610  	defer closer.Close()
   611  
   612  	req := &csipbv1.NodeGetCapabilitiesRequest{}
   613  	resp, err := nodeClient.NodeGetCapabilities(ctx, req)
   614  	if err != nil {
   615  		return false, err
   616  	}
   617  
   618  	capabilities := resp.GetCapabilities()
   619  
   620  	stageUnstageSet := false
   621  	if capabilities == nil {
   622  		return false, nil
   623  	}
   624  	for _, capability := range capabilities {
   625  		if capability.GetRpc().GetType() == csipbv1.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME {
   626  			stageUnstageSet = true
   627  		}
   628  	}
   629  	return stageUnstageSet, nil
   630  }
   631  
   632  func (c *csiDriverClient) nodeSupportsStageUnstageV0(ctx context.Context) (bool, error) {
   633  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   634  	if err != nil {
   635  		return false, err
   636  	}
   637  	defer closer.Close()
   638  
   639  	req := &csipbv1.NodeGetCapabilitiesRequest{}
   640  	resp, err := nodeClient.NodeGetCapabilities(ctx, req)
   641  	if err != nil {
   642  		return false, err
   643  	}
   644  
   645  	capabilities := resp.GetCapabilities()
   646  
   647  	stageUnstageSet := false
   648  	if capabilities == nil {
   649  		return false, nil
   650  	}
   651  	for _, capability := range capabilities {
   652  		if capability.GetRpc().GetType() == csipbv1.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME {
   653  			stageUnstageSet = true
   654  		}
   655  	}
   656  	return stageUnstageSet, nil
   657  }
   658  
   659  func asCSIAccessModeV1(am api.PersistentVolumeAccessMode) csipbv1.VolumeCapability_AccessMode_Mode {
   660  	switch am {
   661  	case api.ReadWriteOnce:
   662  		return csipbv1.VolumeCapability_AccessMode_SINGLE_NODE_WRITER
   663  	case api.ReadOnlyMany:
   664  		return csipbv1.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY
   665  	case api.ReadWriteMany:
   666  		return csipbv1.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER
   667  	}
   668  	return csipbv1.VolumeCapability_AccessMode_UNKNOWN
   669  }
   670  
   671  func asCSIAccessModeV0(am api.PersistentVolumeAccessMode) csipbv1.VolumeCapability_AccessMode_Mode {
   672  	switch am {
   673  	case api.ReadWriteOnce:
   674  		return csipbv1.VolumeCapability_AccessMode_SINGLE_NODE_WRITER
   675  	case api.ReadOnlyMany:
   676  		return csipbv1.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY
   677  	case api.ReadWriteMany:
   678  		return csipbv1.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER
   679  	}
   680  	return csipbv1.VolumeCapability_AccessMode_UNKNOWN
   681  }
   682  
   683  func newGrpcConn(addr csiAddr) (*grpc.ClientConn, error) {
   684  	network := "unix"
   685  	klog.V(4).Infof(log("creating new gRPC connection for [%s://%s]", network, addr))
   686  
   687  	return grpc.Dial(
   688  		string(addr),
   689  		grpc.WithInsecure(),
   690  		grpc.WithDialer(func(target string, timeout time.Duration) (net.Conn, error) {
   691  			return net.Dial(network, target)
   692  		}),
   693  	)
   694  }
   695  
   696  func versionRequiresV0Client(version *utilversion.Version) bool {
   697  	if version != nil && version.Major() == 0 {
   698  		return true
   699  	}
   700  
   701  	return false
   702  }
   703  
   704  // CSI client getter with cache.
   705  // This provides a method to initialize CSI client with driver name and caches
   706  // it for later use. When CSI clients have not been discovered yet (e.g.
   707  // on kubelet restart), client initialization will fail. Users of CSI client (e.g.
   708  // mounter manager and block mapper) can use this to delay CSI client
   709  // initialization until needed.
   710  type csiClientGetter struct {
   711  	sync.RWMutex
   712  	csiClient  csiClient
   713  	driverName csiDriverName
   714  }
   715  
   716  func (c *csiClientGetter) Get() (csiClient, error) {
   717  	c.RLock()
   718  	if c.csiClient != nil {
   719  		c.RUnlock()
   720  		return c.csiClient, nil
   721  	}
   722  	c.RUnlock()
   723  	c.Lock()
   724  	defer c.Unlock()
   725  	// Double-checking locking criterion.
   726  	if c.csiClient != nil {
   727  		return c.csiClient, nil
   728  	}
   729  	csi, err := newCsiDriverClient(c.driverName)
   730  	if err != nil {
   731  		return nil, err
   732  	}
   733  	c.csiClient = csi
   734  	return c.csiClient, nil
   735  }
   736  
   737  func (c *csiDriverClient) NodeSupportsVolumeStats(ctx context.Context) (bool, error) {
   738  	klog.V(5).Info(log("calling NodeGetCapabilities rpc to determine if NodeSupportsVolumeStats"))
   739  	if c.nodeV1ClientCreator != nil {
   740  		return c.nodeSupportsVolumeStatsV1(ctx)
   741  	}
   742  	return false, fmt.Errorf("failed to call NodeSupportsVolumeStats. nodeV1ClientCreator is nil")
   743  }
   744  
   745  func (c *csiDriverClient) nodeSupportsVolumeStatsV1(ctx context.Context) (bool, error) {
   746  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   747  	if err != nil {
   748  		return false, err
   749  	}
   750  	defer closer.Close()
   751  	req := &csipbv1.NodeGetCapabilitiesRequest{}
   752  	resp, err := nodeClient.NodeGetCapabilities(ctx, req)
   753  	if err != nil {
   754  		return false, err
   755  	}
   756  	capabilities := resp.GetCapabilities()
   757  	if capabilities == nil {
   758  		return false, nil
   759  	}
   760  	for _, capability := range capabilities {
   761  		if capability.GetRpc().GetType() == csipbv1.NodeServiceCapability_RPC_GET_VOLUME_STATS {
   762  			return true, nil
   763  		}
   764  	}
   765  	return false, nil
   766  }
   767  
   768  func (c *csiDriverClient) NodeGetVolumeStats(ctx context.Context, volID string, targetPath string) (*volume.Metrics, error) {
   769  	klog.V(4).Info(log("calling NodeGetVolumeStats rpc: [volid=%s, target_path=%s", volID, targetPath))
   770  	if volID == "" {
   771  		return nil, errors.New("missing volume id")
   772  	}
   773  	if targetPath == "" {
   774  		return nil, errors.New("missing target path")
   775  	}
   776  
   777  	if c.nodeV1ClientCreator != nil {
   778  		return c.nodeGetVolumeStatsV1(ctx, volID, targetPath)
   779  	}
   780  
   781  	return nil, fmt.Errorf("failed to call NodeGetVolumeStats. nodeV1ClientCreator is nil")
   782  }
   783  
   784  func (c *csiDriverClient) nodeGetVolumeStatsV1(
   785  	ctx context.Context,
   786  	volID string,
   787  	targetPath string,
   788  ) (*volume.Metrics, error) {
   789  	nodeClient, closer, err := c.nodeV1ClientCreator(c.addr)
   790  	if err != nil {
   791  		return nil, err
   792  	}
   793  	defer closer.Close()
   794  
   795  	req := &csipbv1.NodeGetVolumeStatsRequest{
   796  		VolumeId:   volID,
   797  		VolumePath: targetPath,
   798  	}
   799  
   800  	resp, err := nodeClient.NodeGetVolumeStats(ctx, req)
   801  	if err != nil {
   802  		return nil, err
   803  	}
   804  	usages := resp.GetUsage()
   805  	if usages == nil {
   806  		return nil, fmt.Errorf("failed to get usage from response. usage is nil")
   807  	}
   808  	metrics := &volume.Metrics{
   809  		Used:       resource.NewQuantity(int64(0), resource.BinarySI),
   810  		Capacity:   resource.NewQuantity(int64(0), resource.BinarySI),
   811  		Available:  resource.NewQuantity(int64(0), resource.BinarySI),
   812  		InodesUsed: resource.NewQuantity(int64(0), resource.BinarySI),
   813  		Inodes:     resource.NewQuantity(int64(0), resource.BinarySI),
   814  		InodesFree: resource.NewQuantity(int64(0), resource.BinarySI),
   815  	}
   816  	for _, usage := range usages {
   817  		unit := usage.GetUnit()
   818  		switch unit {
   819  		case csipbv1.VolumeUsage_BYTES:
   820  			metrics.Available = resource.NewQuantity(usage.GetAvailable(), resource.BinarySI)
   821  			metrics.Capacity = resource.NewQuantity(usage.GetTotal(), resource.BinarySI)
   822  			metrics.Used = resource.NewQuantity(usage.GetUsed(), resource.BinarySI)
   823  		case csipbv1.VolumeUsage_INODES:
   824  			metrics.InodesFree = resource.NewQuantity(usage.GetAvailable(), resource.BinarySI)
   825  			metrics.Inodes = resource.NewQuantity(usage.GetTotal(), resource.BinarySI)
   826  			metrics.InodesUsed = resource.NewQuantity(usage.GetUsed(), resource.BinarySI)
   827  		default:
   828  			klog.Errorf("unknown key %s in usage", unit.String())
   829  		}
   830  
   831  	}
   832  	return metrics, nil
   833  }
   834  
   835  func (c *csiDriverClient) CreateVolume(ctx context.Context, req *csipbv1.CreateVolumeRequest) (*csipbv1.CreateVolumeResponse, error) {
   836  	controllerClient, closer, err := c.controllerV1ClientCreator(c.addr)
   837  	if err != nil {
   838  		return nil, err
   839  	}
   840  	defer closer.Close()
   841  
   842  	return controllerClient.CreateVolume(ctx, req)
   843  }
   844  
   845  func (c *csiDriverClient) DeleteVolume(ctx context.Context, req *csipbv1.DeleteVolumeRequest) (*csipbv1.DeleteVolumeResponse, error) {
   846  	controllerClient, closer, err := c.controllerV1ClientCreator(c.addr)
   847  	if err != nil {
   848  		return nil, err
   849  	}
   850  	defer closer.Close()
   851  
   852  	return controllerClient.DeleteVolume(ctx, req)
   853  }
   854  
   855  func (c *csiDriverClient) ControllerPublishVolume(ctx context.Context, req *csipbv1.ControllerPublishVolumeRequest) (*csipbv1.ControllerPublishVolumeResponse, error) {
   856  	controllerClient, closer, err := c.controllerV1ClientCreator(c.addr)
   857  	if err != nil {
   858  		return nil, err
   859  	}
   860  	defer closer.Close()
   861  
   862  	return controllerClient.ControllerPublishVolume(ctx, req)
   863  }
   864  
   865  func (c *csiDriverClient) ControllerUnpublishVolume(ctx context.Context, req *csipbv1.ControllerUnpublishVolumeRequest) (*csipbv1.ControllerUnpublishVolumeResponse, error) {
   866  	controllerClient, closer, err := c.controllerV1ClientCreator(c.addr)
   867  	if err != nil {
   868  		return nil, err
   869  	}
   870  	defer closer.Close()
   871  
   872  	return controllerClient.ControllerUnpublishVolume(ctx, req)
   873  }
   874  
   875  func (c *csiDriverClient) ControllerGetCapabilities(ctx context.Context, req *csipbv1.ControllerGetCapabilitiesRequest) (*csipbv1.ControllerGetCapabilitiesResponse, error) {
   876  	controllerClient, closer, err := c.controllerV1ClientCreator(c.addr)
   877  	if err != nil {
   878  		return nil, err
   879  	}
   880  	defer closer.Close()
   881  
   882  	return controllerClient.ControllerGetCapabilities(ctx, req)
   883  }