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 }