From d5df689a445b48dfa26e356f53772b3f829322f3 Mon Sep 17 00:00:00 2001 From: Prankul <84079249+prankulmahajan@users.noreply.github.com> Date: Mon, 13 May 2024 10:13:44 +0530 Subject: [PATCH] Add MountEITBasedFileShare to mounter interface (#88) * Add MountEITBasedFileShare to Mounter interface that calls MHC server over unix socket --- go.mod | 2 +- go.sum | 4 +- pkg/messages/messages_en.go | 18 ++++++ pkg/messages/reason_code.go | 9 +++ pkg/mountmanager/fake-safe-mounter.go | 13 ++++- pkg/mountmanager/mount_linux.go | 83 +++++++++++++++++++++++++++ pkg/mountmanager/mount_unsupported.go | 5 ++ pkg/mountmanager/safe-mounter.go | 1 + 8 files changed, 130 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index e4cf87f8..a3d21533 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/IBM/ibm-csi-common go 1.20 require ( - github.com/IBM/ibmcloud-volume-interface v1.2.2 + github.com/IBM/ibmcloud-volume-interface v1.2.4 github.com/IBM/ibmcloud-volume-vpc v1.1.7 github.com/IBM/secret-utils-lib v1.1.8 github.com/container-storage-interface/spec v1.8.0 diff --git a/go.sum b/go.sum index 748f7a0c..a1a77cea 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,8 @@ github.com/IBM-Cloud/ibm-cloud-cli-sdk v0.6.7 h1:eHgfQl6IeSmzWUyiSi13CvoFYsovoyq github.com/IBM-Cloud/ibm-cloud-cli-sdk v0.6.7/go.mod h1:RiUvKuHKTBmBApDMUQzBL14pQUGKcx/IioKQPIcRQjs= github.com/IBM/go-sdk-core/v5 v5.9.1 h1:06pXbD9Rgmqqe2HA5YAeQbB4eYRRFgIoOT+Kh3cp1zo= github.com/IBM/go-sdk-core/v5 v5.9.1/go.mod h1:axE2JrRq79gIJTjKPBwV6gWHswvVptBjbcvvCPIxARM= -github.com/IBM/ibmcloud-volume-interface v1.2.2 h1:BHF9grjuyUZEbKHgw/XZQhDztZfFpBkdQEEY1ticYlk= -github.com/IBM/ibmcloud-volume-interface v1.2.2/go.mod h1:PMe4wOp+EEkVNwlo/iJahh+6/aIvjWo+nAdHB1oGBFE= +github.com/IBM/ibmcloud-volume-interface v1.2.4 h1:4ULPklSo9ZN7S8d2bS/eBSV99HDowju55bnKT6pt+S0= +github.com/IBM/ibmcloud-volume-interface v1.2.4/go.mod h1:PMe4wOp+EEkVNwlo/iJahh+6/aIvjWo+nAdHB1oGBFE= github.com/IBM/ibmcloud-volume-vpc v1.1.7 h1:j8X2swP5mDMiLPFZDge3zZwPTHqNQS6apvWaCX0oXas= github.com/IBM/ibmcloud-volume-vpc v1.1.7/go.mod h1:BLszLIqjzttg15YEw2JcbdnMUReYm7t+lagmGsUEikQ= github.com/IBM/secret-common-lib v1.1.8 h1:FX/fSN108phDwlMF9YhFdVCULTWCcHneeuT+dBH6wnk= diff --git a/pkg/messages/messages_en.go b/pkg/messages/messages_en.go index 5b2d7114..2c606d38 100644 --- a/pkg/messages/messages_en.go +++ b/pkg/messages/messages_en.go @@ -275,6 +275,24 @@ var messagesEn = map[string]Message{ Type: codes.Internal, Action: "Please check if volume is used by POD properly", }, + MountingTargetFailed: { + Code: MountingTargetFailed, + Description: "Failed to mount target.", + Type: codes.Internal, + Action: "Check node server logs for more details on mount failure.", + }, + UnresponsiveMountHelperContainerUtility: { + Code: UnresponsiveMountHelperContainerUtility, + Description: "Failed to mount target because unable to make connection to mount helper container service.", + Type: codes.Unavailable, + Action: "Check if EIT is enabled from storage operator. Run command 'kubectl edit configmap addon-vpc-file-csi-driver-configmap -n kube-system' and set 'ENABLE_EIT' flag to 'true'.", + }, + MetadataServiceNotEnabled: { + Code: MetadataServiceNotEnabled, + Description: "Failed to mount target.", + Type: codes.Internal, + Action: "Metadata service might not be enabled for worker node. Make sure to use IKS>=1.30 or ROKS>=4.16 cluster.", + }, ListVolumesFailed: { Code: ListVolumesFailed, Description: "Failed to list volumes", diff --git a/pkg/messages/reason_code.go b/pkg/messages/reason_code.go index b0f4cfb9..8e5e5d45 100644 --- a/pkg/messages/reason_code.go +++ b/pkg/messages/reason_code.go @@ -144,6 +144,15 @@ const ( // CreateMountTargetFailed ... CreateMountTargetFailed = "CreateMountTargetFailed" + // MountingTargetFailed ... + MountingTargetFailed = "MountingTargetFailed" + + // UnresponsiveMountHelperContainerUtility ... + UnresponsiveMountHelperContainerUtility = "UnresponsiveMountHelperContainerUtility" + + // MetadataServiceNotEnabled ... + MetadataServiceNotEnabled = "MetadataServiceNotEnabled" + // ListVolumesFailed ... ListVolumesFailed = "ListVolumesFailed" diff --git a/pkg/mountmanager/fake-safe-mounter.go b/pkg/mountmanager/fake-safe-mounter.go index fd5f952c..64a5ab9b 100644 --- a/pkg/mountmanager/fake-safe-mounter.go +++ b/pkg/mountmanager/fake-safe-mounter.go @@ -22,7 +22,6 @@ import ( mount "k8s.io/mount-utils" exec "k8s.io/utils/exec" - testExec "k8s.io/utils/exec/testing" testingexec "k8s.io/utils/exec/testing" ) @@ -31,6 +30,11 @@ type FakeNodeMounter struct { *mount.SafeFormatAndMount } +// MountEITBasedFileShare implements Mounter. +func (*FakeNodeMounter) MountEITBasedFileShare(mountPath string, targetPath string, fsType string, requestID string) (string, error) { + return "", nil +} + // NewFakeNodeMounter ... func NewFakeNodeMounter() Mounter { //Have to make changes here to pass the Mock functions @@ -50,7 +54,7 @@ func NewFakeSafeMounter() *mount.SafeFormatAndMount { }}, } - var fakeExec exec.Interface = &testExec.FakeExec{ + var fakeExec exec.Interface = &testingexec.FakeExec{ DisableScripts: true, } @@ -92,6 +96,11 @@ type FakeNodeMounterWithCustomActions struct { actionList []testingexec.FakeCommandAction } +// MountEITBasedFileShare implements Mounter. +func (*FakeNodeMounterWithCustomActions) MountEITBasedFileShare(mountPath string, targetPath string, fsType string, requestID string) (string, error) { + return "", nil +} + // NewFakeNodeMounterWithCustomActions ... func NewFakeNodeMounterWithCustomActions(actionList []testingexec.FakeCommandAction) Mounter { fakeSafeMounter := NewFakeSafeMounterWithCustomActions(actionList) diff --git a/pkg/mountmanager/mount_linux.go b/pkg/mountmanager/mount_linux.go index 2fa01fe8..0219baef 100644 --- a/pkg/mountmanager/mount_linux.go +++ b/pkg/mountmanager/mount_linux.go @@ -21,11 +21,42 @@ package mountmanager import ( + "context" + "encoding/json" + "fmt" + "io" + "net" + "net/http" "os" + "strings" + "time" mount "k8s.io/mount-utils" ) +const ( + //socket path + defaultSocketPath = "/tmp/mysocket.sock" + // mount url + urlMountPath = "http://unix/api/mount" + // debug url + urlDebugPath = "http://unix/api/debugLogs" + // http timeout + timeout = 3 * time.Minute +) + +// MountEITBasedFileShare mounts EIT based FileShare on host system +func (m *NodeMounter) MountEITBasedFileShare(mountPath string, targetPath string, fsType string, requestID string) (string, error) { + // Create payload + payload := fmt.Sprintf(`{"mountPath":"%s","targetPath":"%s","fsType":"%s","requestID":"%s"}`, mountPath, targetPath, fsType, requestID) + errResponse, err := createMountHelperContainerRequest(payload, urlMountPath) + + if err != nil { + return errResponse, err + } + return "", nil +} + // MakeFile creates an empty file. func (m *NodeMounter) MakeFile(path string) error { f, err := os.OpenFile(path, os.O_CREATE, os.FileMode(0644)) @@ -75,3 +106,55 @@ func (m *NodeMounter) Resize(devicePath string, deviceMountPath string) (bool, e } return true, nil } + +// createMountHelperContainerRequest creates a request to mount-helper-container server over UNIX socket and returns errors if any. +func createMountHelperContainerRequest(payload string, url string) (string, error) { + // Get socket path + socketPath := os.Getenv("SOCKET_PATH") + if socketPath == "" { + socketPath = defaultSocketPath + } + // Create a custom dialer function for Unix socket connection + dialer := func(ctx context.Context, network, addr string) (net.Conn, error) { + return net.Dial("unix", socketPath) + } + + // Create an HTTP client with the Unix socket transport + client := &http.Client{ + Transport: &http.Transport{ + DialContext: dialer, + }, + Timeout: timeout, + } + + //Create POST request + req, err := http.NewRequest("POST", url, strings.NewReader(payload)) + if err != nil { + return "", err + } + req.Header.Set("Content-Type", "application/json") + response, err := client.Do(req) + if err != nil { + return "", err + } + defer response.Body.Close() + body, err := io.ReadAll(response.Body) + if err != nil { + return "", err + } + + // Unmarshell json response + var responseBody struct { + MountExitCode string `json:"MountExitCode"` + ExitDescription string `json:"Description"` + } + err = json.Unmarshal(body, &responseBody) + if err != nil { + return "", err + } + + if response.StatusCode != http.StatusOK { + return responseBody.ExitDescription, fmt.Errorf("Response from mount-helper-container -> Exit Status Code: %s ,ResponseCode: %v", responseBody.MountExitCode, response.StatusCode) + } + return "", nil +} diff --git a/pkg/mountmanager/mount_unsupported.go b/pkg/mountmanager/mount_unsupported.go index 87c35c54..95f6f288 100644 --- a/pkg/mountmanager/mount_unsupported.go +++ b/pkg/mountmanager/mount_unsupported.go @@ -52,3 +52,8 @@ func (m *NodeMounter) GetSafeFormatAndMount() *mount.SafeFormatAndMount { func (m *NodeMounter) Resize(devicePath string, deviceMountPath string) (bool, error) { return true, errors.New("not implemented") } + +// MountEITBasedFileShare ... +func (m *NodeMounter) MountEITBasedFileShare(mountPath string, targetPath string, fsType string, requestID string) (string, error) { + return "", nil +} diff --git a/pkg/mountmanager/safe-mounter.go b/pkg/mountmanager/safe-mounter.go index b664b836..b406a82d 100644 --- a/pkg/mountmanager/safe-mounter.go +++ b/pkg/mountmanager/safe-mounter.go @@ -28,6 +28,7 @@ type mountInterface = mount.Interface type Mounter interface { mountInterface + MountEITBasedFileShare(mountPath string, targetPath string, fsType string, requestID string) (string, error) GetSafeFormatAndMount() *mount.SafeFormatAndMount MakeFile(path string) error MakeDir(path string) error