@@ -20,6 +20,7 @@ package driver
2020import (
2121 "fmt"
2222 "os"
23+ "path/filepath"
2324 "strconv"
2425 "strings"
2526 "time"
@@ -32,7 +33,9 @@ import (
3233 "github.com/googlecloudplatform/gcs-fuse-csi-driver/pkg/webhook"
3334 "golang.org/x/net/context"
3435 "golang.org/x/time/rate"
36+ "google.golang.org/grpc"
3537 "google.golang.org/grpc/codes"
38+ "google.golang.org/grpc/credentials/insecure"
3639 "google.golang.org/grpc/status"
3740 corev1 "k8s.io/api/core/v1"
3841 apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -727,13 +730,75 @@ func (s *nodeServer) executeNodeStageVolume(ctx context.Context, req *csi.NodeSt
727730 }
728731
729732 // Wait for the mounter pod grpc server to be ready.
730- if err := waitForMounterServer (ctx , clientset , podNamespace , podName , string (pod .UID ), s .driver .config .EmptyDirBasePath ); err != nil {
733+ if err := waitForMounterServer (ctx , clientset , podNamespace , podName , string (pod .UID ), s .driver .config .FeatureOptions .SharedMountOptions .EmptyDirBasePath ); err != nil {
734+ return nil , err
735+ }
736+
737+ podUID := string (pod .UID )
738+
739+ // Send GRPC to mounter pod to start GCSFuse.
740+ if err := s .mountToNode (ctx , podUID , stagingPath , req .GetVolumeId ()); err != nil {
731741 return nil , err
732742 }
733743
734- // TODO(FUECHR) Add start gcsfuse flow.
735744 klog .Infof ("Mounter pod %s/%s is running and staging path %s is mounted" , podNamespace , podName , stagingPath )
736745
737746 klog .Infof ("NodeStageVolume succeeded on staging path %q for volume %q" , stagingPath , req .GetVolumeId ())
738747 return & csi.NodeStageVolumeResponse {}, nil
739748}
749+
750+ // mountToNode connects to the mounter server, at which point it initializes the GCSFuse process.
751+ func (s * nodeServer ) mountToNode (ctx context.Context , podUID , stagingPath , volumeID string ) error {
752+ if s .driver .config .FeatureOptions == nil || s .driver .config .FeatureOptions .SharedMountOptions == nil {
753+ return status .Errorf (codes .Internal , "shared mount options are not fully configured" )
754+ }
755+
756+ if s .driver .config .FeatureOptions .SharedMountOptions .EmptyDirBasePath == nil {
757+ return status .Errorf (codes .Internal , "empty dir base path must be provided for shared mount" )
758+ }
759+ emptyDirBasePath := s .driver .config .FeatureOptions .SharedMountOptions .EmptyDirBasePath (podUID )
760+ socketFile := filepath .Join (emptyDirBasePath , mounterPodSocketFile )
761+
762+ // Create a symlink to bypass the 108-character limit for Unix domain sockets
763+ // when dialing the connection from the Node Server.
764+ if s .driver .config .FeatureOptions .SharedMountOptions .FuseSocketDir == "" {
765+ return status .Errorf (codes .Internal , "fuse socket dir must be provided for shared mount" )
766+ }
767+ symlink := filepath .Join (s .driver .config .FeatureOptions .SharedMountOptions .FuseSocketDir , mounterPodSocketDir , podUID )
768+ if err := os .MkdirAll (filepath .Dir (symlink ), 0750 ); err != nil {
769+ return status .Errorf (codes .Internal , "failed to create dir for symlink %q: %v" , symlink , err )
770+ }
771+
772+ if err := os .Remove (symlink ); err != nil && ! os .IsNotExist (err ) {
773+ klog .Errorf ("failed to remove stale symlink %q: %v" , symlink , err )
774+ }
775+
776+ if err := os .Symlink (socketFile , symlink ); err != nil {
777+ return status .Errorf (codes .Internal , "failed to create symlink to %q: %v" , socketFile , err )
778+ }
779+ defer os .Remove (symlink )
780+
781+ // Connect to the socket using the short symlink path.
782+ socketPath := fmt .Sprintf ("unix:%s" , symlink )
783+ conn , err := grpc .NewClient (socketPath , grpc .WithTransportCredentials (insecure .NewCredentials ()))
784+ if err != nil {
785+ klog .Errorf ("Failed to connect to the server: %v" , err )
786+ return status .Errorf (codes .Internal , "failed to connect to the mounter pod grpc server: %v" , err )
787+ }
788+ klog .Infof ("Connected to MounterServer at %s" , socketPath )
789+ defer conn .Close ()
790+
791+ /*
792+ TODO(FUECHR): Implement the mounter client and mount request once we have a mounter service defined.
793+ c := mounter.NewMounterClient(conn)
794+ if _, err := c.Mount(ctx, &mounter.MountRequest{
795+ Mountpoint: stagingPath,
796+ VolumeID: volumeID,
797+ }); err != nil {
798+ return status.Errorf(codes.Internal, "failed to mount: %v", err)
799+ }
800+ */
801+
802+ klog .Infof ("Mount succeeded at staging target path %s" , stagingPath )
803+ return nil
804+ }
0 commit comments