From 96d499865fcb2bbc81f60bc7b9a6796444c41773 Mon Sep 17 00:00:00 2001
From: David White <david.white@seagate.com>
Date: Tue, 11 Apr 2023 09:57:59 -0600
Subject: [PATCH 1/5] refactor: New node gRPC server for initiator retrieval

The original version of this driver used the nodes iQN as nodeID, and
passed FC and SAS initiators through the topology map. This change
adds a new gRPC server to each node, and changes the Node ID to be the
node IP address.
---
 helm/csi-charts/templates/daemonset.yaml      |  11 +
 helm/csi-charts/templates/deployment.yaml     |   3 +
 pkg/common/identity.go                        |  14 +-
 pkg/controller/provisioner.go                 |  20 +-
 pkg/controller/publisher.go                   | 124 ++----
 pkg/node/node.go                              |  54 +--
 pkg/node_service/node_service_client.go       |  40 ++
 pkg/node_service/node_service_server.go       |  49 +++
 .../node_servicepb/node_rpc.pb.go             | 411 ++++++++++++++++++
 .../node_servicepb/node_rpc.proto             |  32 ++
 .../node_servicepb/node_rpc_grpc.pb.go        | 141 ++++++
 pkg/storage/iscsiNode.go                      |  31 +-
 12 files changed, 786 insertions(+), 144 deletions(-)
 create mode 100644 pkg/node_service/node_service_client.go
 create mode 100644 pkg/node_service/node_service_server.go
 create mode 100644 pkg/node_service/node_servicepb/node_rpc.pb.go
 create mode 100644 pkg/node_service/node_servicepb/node_rpc.proto
 create mode 100644 pkg/node_service/node_servicepb/node_rpc_grpc.pb.go

diff --git a/helm/csi-charts/templates/daemonset.yaml b/helm/csi-charts/templates/daemonset.yaml
index 21effbd4..d37176a4 100644
--- a/helm/csi-charts/templates/daemonset.yaml
+++ b/helm/csi-charts/templates/daemonset.yaml
@@ -38,6 +38,17 @@ spec:
             - -bind=unix://{{ .Values.kubeletPath }}/plugins/csi-exos-x.seagate.com/csi.sock
             - -chroot=/host
 {{- include "csidriver.extraArgs" .Values.node | indent 10 }}
+          env:
+            - name: EXOS-X-CSI-NODE-NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: spec.nodeName
+            - name: EXOS-X-CSI-NODE-IP
+              valueFrom:
+                fieldRef:
+                  fieldPath: status.podIP
+            - name: EXOS-X-CSI-NODE-SERVICE-PORT
+              value: "978"
           securityContext:
             privileged: true
           volumeMounts:
diff --git a/helm/csi-charts/templates/deployment.yaml b/helm/csi-charts/templates/deployment.yaml
index ad71994b..0f77cd6d 100644
--- a/helm/csi-charts/templates/deployment.yaml
+++ b/helm/csi-charts/templates/deployment.yaml
@@ -29,6 +29,9 @@ spec:
             - seagate-exos-x-csi-controller
             - -bind=unix:///csi/csi.sock
 {{- include "csidriver.extraArgs" .Values.controller | indent 10 }}
+          env:
+            - name: EXOS-X-CSI-NODE-SERVICE-PORT
+              value: "978"
           volumeMounts:
             - name: socket-dir
               mountPath: /csi
diff --git a/pkg/common/identity.go b/pkg/common/identity.go
index 236b2567..ec8569a7 100644
--- a/pkg/common/identity.go
+++ b/pkg/common/identity.go
@@ -32,13 +32,13 @@ func (driver *Driver) GetPluginCapabilities(ctx context.Context, req *csi.GetPlu
 					},
 				},
 			},
-			{
-				Type: &csi.PluginCapability_Service_{
-					Service: &csi.PluginCapability_Service{
-						Type: csi.PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS,
-					},
-				},
-			},
+			// {
+			// 	Type: &csi.PluginCapability_Service_{
+			// 		Service: &csi.PluginCapability_Service{
+			// 			Type: csi.PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS,
+			// 		},
+			// 	},
+			// },
 		},
 	}, nil
 }
diff --git a/pkg/controller/provisioner.go b/pkg/controller/provisioner.go
index d001c767..81b01a86 100644
--- a/pkg/controller/provisioner.go
+++ b/pkg/controller/provisioner.go
@@ -71,17 +71,6 @@ func (controller *Controller) CreateVolume(ctx context.Context, req *csi.CreateV
 	// Extract the storage interface protocol to be used for this volume (iscsi, fc, sas, etc)
 	storageProtocol := storage.ValidateStorageProtocol(parameters[common.StorageProtocolKey])
 
-	klog.Infof("Create Volume -- Requisite Topology: %v", req.GetAccessibilityRequirements().GetRequisite())
-	klog.Infof("Create Volume -- Preferred Topology: %v", req.GetAccessibilityRequirements().GetPreferred())
-
-	//insert topology keys into the parameters map, so they will be available in ControllerPublishVolume
-	accessibleTopology, err := parseTopology(req.GetAccessibilityRequirements().GetRequisite(), storageProtocol, &parameters)
-	if err != nil {
-		klog.Errorf("parseTopology() returned error: %v", err)
-		return nil, err
-	}
-	klog.V(5).Infof("accessibleTopology: %v", accessibleTopology)
-
 	if !common.ValidateName(volumeName) {
 		return nil, status.Error(codes.InvalidArgument, "volume name contains invalid characters")
 	}
@@ -164,11 +153,10 @@ func (controller *Controller) CreateVolume(ctx context.Context, req *csi.CreateV
 
 	volume := &csi.CreateVolumeResponse{
 		Volume: &csi.Volume{
-			VolumeId:           volumeId,
-			VolumeContext:      parameters,
-			AccessibleTopology: accessibleTopology,
-			CapacityBytes:      req.GetCapacityRange().GetRequiredBytes(),
-			ContentSource:      req.GetVolumeContentSource(),
+			VolumeId:      volumeId,
+			VolumeContext: parameters,
+			CapacityBytes: req.GetCapacityRange().GetRequiredBytes(),
+			ContentSource: req.GetVolumeContentSource(),
 		},
 	}
 
diff --git a/pkg/controller/publisher.go b/pkg/controller/publisher.go
index c9d1b2a9..72754489 100644
--- a/pkg/controller/publisher.go
+++ b/pkg/controller/publisher.go
@@ -2,64 +2,16 @@ package controller
 
 import (
 	"context"
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"strings"
 
 	"github.com/Seagate/seagate-exos-x-csi/pkg/common"
+	"github.com/Seagate/seagate-exos-x-csi/pkg/node_service"
+	pb "github.com/Seagate/seagate-exos-x-csi/pkg/node_service/node_servicepb"
 	"github.com/container-storage-interface/spec/lib/go/csi"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"k8s.io/klog/v2"
 )
 
-// getConnectorInfoPath
-func (driver *Controller) getConnectorInfoPath(volumeID string) string {
-	return fmt.Sprintf("%s/%s.json", driver.runPath, volumeID)
-}
-
-// Read connector json file and return initiator address info for the given volume
-func (driver *Controller) readInitiatorMapFromFile(filePath string, volumeID string) ([]string, error) {
-	klog.Infof("Reading initiator value for volume %v from file %v", volumeID, filePath)
-	f, err := ioutil.ReadFile(filePath)
-	if err != nil {
-		return nil, err
-	}
-	initiatorMap := make(map[string][]string)
-	err = json.Unmarshal(f, &initiatorMap)
-	if err != nil {
-		return nil, fmt.Errorf("error unmarshaling initiator info file for specified volume ID %v", volumeID)
-	}
-	initiators, found := initiatorMap[volumeID]
-	if found {
-		return initiators, nil
-	} else {
-		return nil, fmt.Errorf("initiator value for volume ID %v not found", volumeID)
-	}
-}
-
-// PersistConnector persists the provided Connector to the specified file
-func persistInitiatorMap(volumeID string, initiators []string, filePath string) error {
-	initiatorMap := map[string][]string{
-		volumeID: initiators,
-	}
-	f, err := os.Create(filePath)
-	if err != nil {
-		klog.Error("error encoding initiator info: %v", err)
-		return fmt.Errorf("error creating initiator map file %s: %s", filePath, err)
-	}
-	defer f.Close()
-	encoder := json.NewEncoder(f)
-	if err = encoder.Encode(initiatorMap); err != nil {
-		klog.Error("error encoding initiator info: %v", err)
-		return fmt.Errorf("error encoding initiator info: %v", err)
-	}
-	klog.Infof("wrote initiator persistence file at %s", filePath)
-	return nil
-}
-
 // ControllerPublishVolume attaches the given volume to the node
 func (driver *Controller) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) {
 	if len(req.GetVolumeId()) == 0 {
@@ -71,35 +23,31 @@ func (driver *Controller) ControllerPublishVolume(ctx context.Context, req *csi.
 	if req.GetVolumeCapability() == nil {
 		return nil, status.Error(codes.InvalidArgument, "cannot publish volume without capabilities")
 	}
+
+	nodeIP := req.GetNodeId()
 	parameters := req.GetVolumeContext()
 
-	initiatorMapNodeID := common.GetTopologyCompliantNodeID(req.GetNodeId())
-	var initiatorNames []string
+	var reqType pb.InitiatorType
+	switch parameters[common.StorageProtocolKey] {
+	case common.StorageProtocolSAS:
+		reqType = pb.InitiatorType_SAS
+	case common.StorageProtocolFC:
+		reqType = pb.InitiatorType_FC
+	case common.StorageProtocolISCSI:
+		reqType = pb.InitiatorType_ISCSI
+	}
 
-	// Available initiators for the node are provided in parameters through NodeGetInfo
-	if parameters[common.StorageProtocolKey] == common.StorageProtocolSAS {
-		for key, val := range parameters {
-			if strings.Contains(key, common.TopologySASInitiatorLabel) && strings.Contains(key, initiatorMapNodeID) {
-				initiatorNames = append(initiatorNames, val)
-			}
-		}
-	} else if parameters[common.StorageProtocolKey] == common.StorageProtocolFC {
-		for key, val := range parameters {
-			if strings.Contains(key, common.TopologyFCInitiatorLabel) && strings.Contains(key, initiatorMapNodeID) {
-				initiatorNames = append(initiatorNames, val)
-			}
-		}
-	} else {
-		initiatorNames = []string{req.GetNodeId()}
+	initiators, err := node_service.GetNodeInitiators(nodeIP, reqType)
+	if err != nil {
+		klog.ErrorS(err, "error getting node initiators", "node-ip", nodeIP, "storage-protocol", reqType)
+		return nil, err
 	}
 
 	volumeName, _ := common.VolumeIdGetName(req.GetVolumeId())
-	persistentInfoFilepath := driver.getConnectorInfoPath(req.GetVolumeId())
-	persistInitiatorMap(volumeName, initiatorNames, persistentInfoFilepath)
 
-	klog.Infof("attach request for initiator(s) %v, volume id: %s", initiatorNames, volumeName)
+	klog.Infof("attach request for initiator(s) %v, volume id: %s", initiators, volumeName)
 
-	lun, err := driver.client.PublishVolume(volumeName, initiatorNames)
+	lun, err := driver.client.PublishVolume(volumeName, initiators)
 
 	if err != nil {
 		return nil, err
@@ -119,17 +67,30 @@ func (driver *Controller) ControllerUnpublishVolume(ctx context.Context, req *cs
 	volumeName, _ := common.VolumeIdGetName(req.GetVolumeId())
 
 	var initiators []string
-	var err error
-	if protocol, _ := common.VolumeIdGetStorageProtocol(req.GetVolumeId()); protocol == common.StorageProtocolSAS {
-		initiators, err = driver.readInitiatorMapFromFile(driver.getConnectorInfoPath(req.GetVolumeId()), volumeName)
-		if err != nil {
-			return nil, fmt.Errorf("error retrieving initiator! cannot unpublish volume %v", volumeName)
-		}
-	} else {
-		initiators = []string{req.GetNodeId()}
+
+	nodeIP := req.GetNodeId()
+	storageProtocol, err := common.VolumeIdGetStorageProtocol(req.GetVolumeId())
+	if err != nil {
+		klog.ErrorS(err, "No storage protocol found in ControllerUnpublishVolume", "storage protocol", storageProtocol, "volume ID:", req.GetVolumeId())
+		return nil, err
+	}
+
+	var reqType pb.InitiatorType
+	switch storageProtocol {
+	case common.StorageProtocolSAS:
+		reqType = pb.InitiatorType_SAS
+	case common.StorageProtocolFC:
+		reqType = pb.InitiatorType_FC
+	case common.StorageProtocolISCSI:
+		reqType = pb.InitiatorType_ISCSI
 	}
 
-	klog.Infof("unmapping volume %s from initiator %s", volumeName, initiators)
+	initiators, err = node_service.GetNodeInitiators(nodeIP, reqType)
+	if err != nil {
+		klog.ErrorS(err, "error getting initiators from the node", "nodeIP", nodeIP, "storage-protocol", reqType)
+	}
+
+	klog.InfoS("unmapping volume from initiator", "volumeName", volumeName, "initiators", initiators)
 	for _, initiator := range initiators {
 		_, status, err := driver.client.UnmapVolume(volumeName, initiator)
 		if err != nil {
@@ -141,9 +102,6 @@ func (driver *Controller) ControllerUnpublishVolume(ctx context.Context, req *cs
 		}
 	}
 
-	persistentInfoFilepath := driver.getConnectorInfoPath(req.GetVolumeId())
-	os.Remove(persistentInfoFilepath)
-
 	klog.Infof("successfully unmapped volume %s from all initiators", volumeName)
 	return &csi.ControllerUnpublishVolumeResponse{}, nil
 }
diff --git a/pkg/node/node.go b/pkg/node/node.go
index 926f977b..8d78c131 100644
--- a/pkg/node/node.go
+++ b/pkg/node/node.go
@@ -10,6 +10,7 @@ import (
 
 	"github.com/Seagate/csi-lib-iscsi/iscsi"
 	"github.com/Seagate/seagate-exos-x-csi/pkg/common"
+	"github.com/Seagate/seagate-exos-x-csi/pkg/node_service"
 	"github.com/Seagate/seagate-exos-x-csi/pkg/storage"
 	"github.com/container-storage-interface/spec/lib/go/csi"
 	"github.com/golang/protobuf/ptypes/wrappers"
@@ -26,6 +27,8 @@ type Node struct {
 
 	semaphore *semaphore.Weighted
 	runPath   string
+	nodeName  string
+	nodeIP    string
 }
 
 // New is a convenience function for creating a node driver
@@ -34,10 +37,24 @@ func New() *Node {
 		iscsi.EnableDebugLogging(os.Stderr)
 	}
 
+	envNodeName, _ := os.LookupEnv("EXOS-X-CSI-NODE-NAME")
+	nodeIP, envFound := os.LookupEnv("EXOS-X-CSI-NODE-IP")
+	if !envFound {
+		klog.InfoS("no Node IP found in environment. Using default")
+		nodeIP = "127.0.0.1"
+	}
+	envServicePort, envFound := os.LookupEnv("EXOS-X-CSI-NODE-SERVICE-PORT")
+	if !envFound {
+		klog.InfoS("no Node service port found in environment. Using default")
+		envServicePort = "978"
+	}
+
 	node := &Node{
 		Driver:    common.NewDriver(),
 		semaphore: semaphore.NewWeighted(1),
 		runPath:   fmt.Sprintf("/var/run/%s", common.PluginName),
+		nodeName:  envNodeName,
+		nodeIP:    nodeIP,
 	}
 
 	if err := os.MkdirAll(node.runPath, 0755); err != nil {
@@ -96,46 +113,17 @@ func New() *Node {
 	csi.RegisterIdentityServer(node.Server, node)
 	csi.RegisterNodeServer(node.Server, node)
 
+	// initialize node communication service
+	go node_service.ListenAndServe(envServicePort)
+
 	return node
 }
 
 // NodeGetInfo returns info about the node
 func (node *Node) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {
-	initiatorName, err := readInitiatorName()
-	if err != nil {
-		return nil, status.Error(codes.FailedPrecondition, err.Error())
-	}
-
-	topology := map[string]string{}
-	sasAddresses, err := storage.GetSASInitiators()
-	if err != nil {
-		klog.Warningf("Error while searching for FC HBA Addresses: %s", err)
-	}
-	fcAddresses, err := storage.GetFCInitiators()
-	if err != nil {
-		klog.Warningf("Error while searching for FC HBA Addresses: %s", err)
-	}
-
-	for i, sasAddr := range sasAddresses {
-		//maximum value length 63 chars
-		topoKey := fmt.Sprintf("%s/%s-%d", common.TopologyInitiatorPrefix, common.TopologySASInitiatorLabel, i)
-		topology[topoKey] = sasAddr
-	}
-
-	for i, fcAddr := range fcAddresses {
-		topoKey := fmt.Sprintf("%s/%s-%d", common.TopologyInitiatorPrefix, common.TopologyFCInitiatorLabel, i)
-		topology[topoKey] = fcAddr
-	}
-
-	topology[common.TopologyNodeIDKey] = common.GetTopologyCompliantNodeID(initiatorName)
-
-	klog.Infof("Node Accessible Topology: %v", topology)
 	return &csi.NodeGetInfoResponse{
-		NodeId:            initiatorName,
+		NodeId:            node.nodeIP,
 		MaxVolumesPerNode: 255,
-		AccessibleTopology: &csi.Topology{
-			Segments: topology,
-		},
 	}, nil
 }
 
diff --git a/pkg/node_service/node_service_client.go b/pkg/node_service/node_service_client.go
new file mode 100644
index 00000000..f5e3a07f
--- /dev/null
+++ b/pkg/node_service/node_service_client.go
@@ -0,0 +1,40 @@
+package node_service
+
+import (
+	"context"
+	"os"
+	"time"
+
+	pb "github.com/Seagate/seagate-exos-x-csi/pkg/node_service/node_servicepb"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials/insecure"
+	"k8s.io/klog/v2"
+)
+
+func GetNodeInitiators(nodeIP string, reqType pb.InitiatorType) ([]string, error) {
+	port, envFound := os.LookupEnv("EXOS-X-CSI-NODE-SERVICE-PORT")
+	if !envFound {
+		port = "978"
+		klog.InfoS("no node service port found in environment. using default", "port", port)
+	}
+
+	nodeServiceAddr := nodeIP + ":" + port
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel()
+
+	conn, err := grpc.Dial(nodeServiceAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
+	if err != nil {
+		klog.ErrorS(err, "Error connecting to node service", "node ip", nodeIP, "port", port)
+		return nil, err
+	}
+	defer conn.Close()
+
+	client := pb.NewNodeServiceClient(conn)
+	initiatorReq := pb.InitiatorRequest{Type: reqType}
+	initiators, err := client.GetInitiators(ctx, &initiatorReq)
+	if err != nil {
+		klog.ErrorS(err, "Error during GetInitiators", "initiatorReq", initiatorReq)
+		return nil, err
+	}
+	return initiators.Initiators, nil
+}
diff --git a/pkg/node_service/node_service_server.go b/pkg/node_service/node_service_server.go
new file mode 100644
index 00000000..a4d734f6
--- /dev/null
+++ b/pkg/node_service/node_service_server.go
@@ -0,0 +1,49 @@
+package node_service
+
+import (
+	"context"
+	"net"
+
+	pb "github.com/Seagate/seagate-exos-x-csi/pkg/node_service/node_servicepb"
+	"github.com/Seagate/seagate-exos-x-csi/pkg/storage"
+	"google.golang.org/grpc"
+	"k8s.io/klog/v2"
+)
+
+type server struct {
+	pb.UnimplementedNodeServiceServer
+}
+
+func (s *server) GetInitiators(ctx context.Context, in *pb.InitiatorRequest) (*pb.Initiators, error) {
+	initiators := []string{}
+	var err error
+	switch in.GetType() {
+	case pb.InitiatorType_FC:
+		initiators, err = storage.GetFCInitiators()
+	case pb.InitiatorType_SAS:
+		initiators, err = storage.GetSASInitiators()
+	case pb.InitiatorType_ISCSI:
+		initiators, err = storage.GetISCSIInitiators()
+	case pb.InitiatorType_UNSPECIFIED:
+		klog.InfoS("Unspecified Initiator Type in Initiator Request")
+	}
+	if err != nil {
+		return nil, err
+	}
+	return &pb.Initiators{Initiators: initiators}, nil
+}
+
+func (s *server) NotifyUnmap(ctx context.Context, in *pb.UnmappedVolume) (*pb.Ack, error) {
+	return &pb.Ack{Ack: 1}, nil
+}
+
+func ListenAndServe(port string) {
+	lis, err := net.Listen("tcp", ":"+port)
+	if err != nil {
+		klog.ErrorS(err, "Node Service gRPC server failed to listen")
+	}
+	s := grpc.NewServer()
+	pb.RegisterNodeServiceServer(s, &server{})
+	klog.V(0).InfoS("Node Service gRPC server listening", "address", lis.Addr())
+	s.Serve(lis)
+}
diff --git a/pkg/node_service/node_servicepb/node_rpc.pb.go b/pkg/node_service/node_servicepb/node_rpc.pb.go
new file mode 100644
index 00000000..3275953e
--- /dev/null
+++ b/pkg/node_service/node_servicepb/node_rpc.pb.go
@@ -0,0 +1,411 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v4.22.2
+// source: node_servicepb/node_rpc.proto
+
+package node_servicepb
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type InitiatorType int32
+
+const (
+	InitiatorType_UNSPECIFIED InitiatorType = 0
+	InitiatorType_FC          InitiatorType = 1
+	InitiatorType_SAS         InitiatorType = 2
+	InitiatorType_ISCSI       InitiatorType = 3
+)
+
+// Enum value maps for InitiatorType.
+var (
+	InitiatorType_name = map[int32]string{
+		0: "UNSPECIFIED",
+		1: "FC",
+		2: "SAS",
+		3: "ISCSI",
+	}
+	InitiatorType_value = map[string]int32{
+		"UNSPECIFIED": 0,
+		"FC":          1,
+		"SAS":         2,
+		"ISCSI":       3,
+	}
+)
+
+func (x InitiatorType) Enum() *InitiatorType {
+	p := new(InitiatorType)
+	*p = x
+	return p
+}
+
+func (x InitiatorType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (InitiatorType) Descriptor() protoreflect.EnumDescriptor {
+	return file_node_servicepb_node_rpc_proto_enumTypes[0].Descriptor()
+}
+
+func (InitiatorType) Type() protoreflect.EnumType {
+	return &file_node_servicepb_node_rpc_proto_enumTypes[0]
+}
+
+func (x InitiatorType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use InitiatorType.Descriptor instead.
+func (InitiatorType) EnumDescriptor() ([]byte, []int) {
+	return file_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{0}
+}
+
+type InitiatorRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Type InitiatorType `protobuf:"varint,1,opt,name=type,proto3,enum=node_service.InitiatorType" json:"type,omitempty"`
+}
+
+func (x *InitiatorRequest) Reset() {
+	*x = InitiatorRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_node_servicepb_node_rpc_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *InitiatorRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InitiatorRequest) ProtoMessage() {}
+
+func (x *InitiatorRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_node_servicepb_node_rpc_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InitiatorRequest.ProtoReflect.Descriptor instead.
+func (*InitiatorRequest) Descriptor() ([]byte, []int) {
+	return file_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *InitiatorRequest) GetType() InitiatorType {
+	if x != nil {
+		return x.Type
+	}
+	return InitiatorType_UNSPECIFIED
+}
+
+type Initiators struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Initiators []string `protobuf:"bytes,1,rep,name=initiators,proto3" json:"initiators,omitempty"`
+}
+
+func (x *Initiators) Reset() {
+	*x = Initiators{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_node_servicepb_node_rpc_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Initiators) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Initiators) ProtoMessage() {}
+
+func (x *Initiators) ProtoReflect() protoreflect.Message {
+	mi := &file_node_servicepb_node_rpc_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Initiators.ProtoReflect.Descriptor instead.
+func (*Initiators) Descriptor() ([]byte, []int) {
+	return file_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Initiators) GetInitiators() []string {
+	if x != nil {
+		return x.Initiators
+	}
+	return nil
+}
+
+type UnmappedVolume struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	VolumeName string `protobuf:"bytes,1,opt,name=volumeName,proto3" json:"volumeName,omitempty"`
+}
+
+func (x *UnmappedVolume) Reset() {
+	*x = UnmappedVolume{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_node_servicepb_node_rpc_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UnmappedVolume) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnmappedVolume) ProtoMessage() {}
+
+func (x *UnmappedVolume) ProtoReflect() protoreflect.Message {
+	mi := &file_node_servicepb_node_rpc_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use UnmappedVolume.ProtoReflect.Descriptor instead.
+func (*UnmappedVolume) Descriptor() ([]byte, []int) {
+	return file_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *UnmappedVolume) GetVolumeName() string {
+	if x != nil {
+		return x.VolumeName
+	}
+	return ""
+}
+
+type Ack struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Ack int32 `protobuf:"varint,1,opt,name=ack,proto3" json:"ack,omitempty"`
+}
+
+func (x *Ack) Reset() {
+	*x = Ack{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_node_servicepb_node_rpc_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Ack) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Ack) ProtoMessage() {}
+
+func (x *Ack) ProtoReflect() protoreflect.Message {
+	mi := &file_node_servicepb_node_rpc_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Ack.ProtoReflect.Descriptor instead.
+func (*Ack) Descriptor() ([]byte, []int) {
+	return file_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *Ack) GetAck() int32 {
+	if x != nil {
+		return x.Ack
+	}
+	return 0
+}
+
+var File_node_servicepb_node_rpc_proto protoreflect.FileDescriptor
+
+var file_node_servicepb_node_rpc_proto_rawDesc = []byte{
+	0x0a, 0x1d, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x70, 0x62,
+	0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+	0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x43, 0x0a,
+	0x10, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x2f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
+	0x1b, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49,
+	0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79,
+	0x70, 0x65, 0x22, 0x2c, 0x0a, 0x0a, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x73,
+	0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x73,
+	0x22, 0x30, 0x0a, 0x0e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x56, 0x6f, 0x6c, 0x75,
+	0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x4e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x4e, 0x61,
+	0x6d, 0x65, 0x22, 0x17, 0x0a, 0x03, 0x41, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x6b,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x63, 0x6b, 0x2a, 0x3c, 0x0a, 0x0d, 0x49,
+	0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b,
+	0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x06, 0x0a,
+	0x02, 0x46, 0x43, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x41, 0x53, 0x10, 0x02, 0x12, 0x09,
+	0x0a, 0x05, 0x49, 0x53, 0x43, 0x53, 0x49, 0x10, 0x03, 0x32, 0x9c, 0x01, 0x0a, 0x0b, 0x4e, 0x6f,
+	0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x0d, 0x47, 0x65, 0x74,
+	0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x6e, 0x6f, 0x64,
+	0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61,
+	0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6e, 0x6f, 0x64,
+	0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61,
+	0x74, 0x6f, 0x72, 0x73, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0b, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79,
+	0x55, 0x6e, 0x6d, 0x61, 0x70, 0x12, 0x1c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72,
+	0x76, 0x69, 0x63, 0x65, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x56, 0x6f, 0x6c,
+	0x75, 0x6d, 0x65, 0x1a, 0x11, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
+	0x63, 0x65, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x57, 0x5a, 0x55, 0x67, 0x69, 0x74, 0x68,
+	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x65, 0x61, 0x67, 0x61, 0x74, 0x65, 0x2f, 0x73,
+	0x65, 0x61, 0x67, 0x61, 0x74, 0x65, 0x2d, 0x65, 0x78, 0x6f, 0x73, 0x2d, 0x78, 0x2d, 0x63, 0x73,
+	0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
+	0x63, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x62, 0x75, 0x66, 0x66, 0x65,
+	0x72, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x70,
+	0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_node_servicepb_node_rpc_proto_rawDescOnce sync.Once
+	file_node_servicepb_node_rpc_proto_rawDescData = file_node_servicepb_node_rpc_proto_rawDesc
+)
+
+func file_node_servicepb_node_rpc_proto_rawDescGZIP() []byte {
+	file_node_servicepb_node_rpc_proto_rawDescOnce.Do(func() {
+		file_node_servicepb_node_rpc_proto_rawDescData = protoimpl.X.CompressGZIP(file_node_servicepb_node_rpc_proto_rawDescData)
+	})
+	return file_node_servicepb_node_rpc_proto_rawDescData
+}
+
+var file_node_servicepb_node_rpc_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_node_servicepb_node_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_node_servicepb_node_rpc_proto_goTypes = []interface{}{
+	(InitiatorType)(0),       // 0: node_service.InitiatorType
+	(*InitiatorRequest)(nil), // 1: node_service.InitiatorRequest
+	(*Initiators)(nil),       // 2: node_service.Initiators
+	(*UnmappedVolume)(nil),   // 3: node_service.UnmappedVolume
+	(*Ack)(nil),              // 4: node_service.Ack
+}
+var file_node_servicepb_node_rpc_proto_depIdxs = []int32{
+	0, // 0: node_service.InitiatorRequest.type:type_name -> node_service.InitiatorType
+	1, // 1: node_service.NodeService.GetInitiators:input_type -> node_service.InitiatorRequest
+	3, // 2: node_service.NodeService.NotifyUnmap:input_type -> node_service.UnmappedVolume
+	2, // 3: node_service.NodeService.GetInitiators:output_type -> node_service.Initiators
+	4, // 4: node_service.NodeService.NotifyUnmap:output_type -> node_service.Ack
+	3, // [3:5] is the sub-list for method output_type
+	1, // [1:3] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_node_servicepb_node_rpc_proto_init() }
+func file_node_servicepb_node_rpc_proto_init() {
+	if File_node_servicepb_node_rpc_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_node_servicepb_node_rpc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*InitiatorRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_node_servicepb_node_rpc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Initiators); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_node_servicepb_node_rpc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UnmappedVolume); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_node_servicepb_node_rpc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Ack); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_node_servicepb_node_rpc_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   4,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_node_servicepb_node_rpc_proto_goTypes,
+		DependencyIndexes: file_node_servicepb_node_rpc_proto_depIdxs,
+		EnumInfos:         file_node_servicepb_node_rpc_proto_enumTypes,
+		MessageInfos:      file_node_servicepb_node_rpc_proto_msgTypes,
+	}.Build()
+	File_node_servicepb_node_rpc_proto = out.File
+	file_node_servicepb_node_rpc_proto_rawDesc = nil
+	file_node_servicepb_node_rpc_proto_goTypes = nil
+	file_node_servicepb_node_rpc_proto_depIdxs = nil
+}
diff --git a/pkg/node_service/node_servicepb/node_rpc.proto b/pkg/node_service/node_servicepb/node_rpc.proto
new file mode 100644
index 00000000..9a012a0e
--- /dev/null
+++ b/pkg/node_service/node_servicepb/node_rpc.proto
@@ -0,0 +1,32 @@
+syntax = "proto3";
+package node_service;
+
+option go_package = "github.com/Seagate/seagate-exos-x-csi/pkg/node_service/protocolbuffers/node_servicepb";
+
+service NodeService {
+    rpc GetInitiators(InitiatorRequest) returns (Initiators){}
+    rpc NotifyUnmap(UnmappedVolume) returns (Ack){}
+}
+
+enum InitiatorType{
+    UNSPECIFIED = 0;
+    FC = 1;
+    SAS = 2;
+    ISCSI = 3;
+}
+
+message InitiatorRequest {
+    InitiatorType type = 1;
+}
+
+message Initiators {
+    repeated string initiators = 1;
+}
+
+message UnmappedVolume {
+    string volumeName = 1;
+}
+
+message Ack {
+    int32 ack = 1;
+}
diff --git a/pkg/node_service/node_servicepb/node_rpc_grpc.pb.go b/pkg/node_service/node_servicepb/node_rpc_grpc.pb.go
new file mode 100644
index 00000000..512ad1ee
--- /dev/null
+++ b/pkg/node_service/node_servicepb/node_rpc_grpc.pb.go
@@ -0,0 +1,141 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.2.0
+// - protoc             v4.22.2
+// source: node_servicepb/node_rpc.proto
+
+package node_servicepb
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// NodeServiceClient is the client API for NodeService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type NodeServiceClient interface {
+	GetInitiators(ctx context.Context, in *InitiatorRequest, opts ...grpc.CallOption) (*Initiators, error)
+	NotifyUnmap(ctx context.Context, in *UnmappedVolume, opts ...grpc.CallOption) (*Ack, error)
+}
+
+type nodeServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewNodeServiceClient(cc grpc.ClientConnInterface) NodeServiceClient {
+	return &nodeServiceClient{cc}
+}
+
+func (c *nodeServiceClient) GetInitiators(ctx context.Context, in *InitiatorRequest, opts ...grpc.CallOption) (*Initiators, error) {
+	out := new(Initiators)
+	err := c.cc.Invoke(ctx, "/node_service.NodeService/GetInitiators", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *nodeServiceClient) NotifyUnmap(ctx context.Context, in *UnmappedVolume, opts ...grpc.CallOption) (*Ack, error) {
+	out := new(Ack)
+	err := c.cc.Invoke(ctx, "/node_service.NodeService/NotifyUnmap", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// NodeServiceServer is the server API for NodeService service.
+// All implementations must embed UnimplementedNodeServiceServer
+// for forward compatibility
+type NodeServiceServer interface {
+	GetInitiators(context.Context, *InitiatorRequest) (*Initiators, error)
+	NotifyUnmap(context.Context, *UnmappedVolume) (*Ack, error)
+	mustEmbedUnimplementedNodeServiceServer()
+}
+
+// UnimplementedNodeServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedNodeServiceServer struct {
+}
+
+func (UnimplementedNodeServiceServer) GetInitiators(context.Context, *InitiatorRequest) (*Initiators, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method GetInitiators not implemented")
+}
+func (UnimplementedNodeServiceServer) NotifyUnmap(context.Context, *UnmappedVolume) (*Ack, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method NotifyUnmap not implemented")
+}
+func (UnimplementedNodeServiceServer) mustEmbedUnimplementedNodeServiceServer() {}
+
+// UnsafeNodeServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to NodeServiceServer will
+// result in compilation errors.
+type UnsafeNodeServiceServer interface {
+	mustEmbedUnimplementedNodeServiceServer()
+}
+
+func RegisterNodeServiceServer(s grpc.ServiceRegistrar, srv NodeServiceServer) {
+	s.RegisterService(&NodeService_ServiceDesc, srv)
+}
+
+func _NodeService_GetInitiators_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(InitiatorRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(NodeServiceServer).GetInitiators(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/node_service.NodeService/GetInitiators",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(NodeServiceServer).GetInitiators(ctx, req.(*InitiatorRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _NodeService_NotifyUnmap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(UnmappedVolume)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(NodeServiceServer).NotifyUnmap(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/node_service.NodeService/NotifyUnmap",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(NodeServiceServer).NotifyUnmap(ctx, req.(*UnmappedVolume))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// NodeService_ServiceDesc is the grpc.ServiceDesc for NodeService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var NodeService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "node_service.NodeService",
+	HandlerType: (*NodeServiceServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "GetInitiators",
+			Handler:    _NodeService_GetInitiators_Handler,
+		},
+		{
+			MethodName: "NotifyUnmap",
+			Handler:    _NodeService_NotifyUnmap_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "node_servicepb/node_rpc.proto",
+}
diff --git a/pkg/storage/iscsiNode.go b/pkg/storage/iscsiNode.go
index a9eccd0b..9a463840 100644
--- a/pkg/storage/iscsiNode.go
+++ b/pkg/storage/iscsiNode.go
@@ -19,6 +19,7 @@
 package storage
 
 import (
+	"bufio"
 	"context"
 	"fmt"
 	"os"
@@ -310,11 +311,6 @@ func (iscsi *iscsiStorage) NodeExpandVolume(ctx context.Context, req *csi.NodeEx
 		return nil, status.Error(codes.NotFound, fmt.Sprintf("node expand volume path not found for volume id (%s)", volumeName))
 	}
 
-	// TODO: Is a rescan needed - rescan a scsi device by writing 1 in /sys/class/scsi_device/h:c:t:l/device/rescan
-	// for i := range connector.Devices {
-	// 	connector.Devices[i].Rescan()
-	// }
-
 	if connector.Multipath {
 		klog.V(2).Info("device is using multipath")
 		if err := iscsilib.ResizeMultipathDevice(connector.DevicePath); err != nil {
@@ -343,3 +339,28 @@ func (iscsi *iscsiStorage) NodeGetCapabilities(ctx context.Context, req *csi.Nod
 func (iscsi *iscsiStorage) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {
 	return nil, status.Error(codes.Unimplemented, "NodeGetInfo is not implemented")
 }
+
+func GetISCSIInitiators() ([]string, error) {
+	initiatorNameFilePath := "/etc/iscsi/initiatorname.iscsi"
+	file, err := os.Open(initiatorNameFilePath)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	for scanner.Scan() {
+		line := scanner.Text()
+		if equal := strings.Index(line, "="); equal >= 0 {
+			if strings.TrimSpace(line[:equal]) == "InitiatorName" {
+				return []string{strings.TrimSpace(line[equal+1:])}, nil
+			}
+		}
+	}
+
+	if err := scanner.Err(); err != nil {
+		return nil, err
+	}
+
+	return nil, fmt.Errorf("InitiatorName key is missing from %s", initiatorNameFilePath)
+}

From ef998bdc70d7f862da8e0baab8d374c3a730bad9 Mon Sep 17 00:00:00 2001
From: David White <david.white@seagate.com>
Date: Tue, 11 Apr 2023 17:56:18 -0600
Subject: [PATCH 2/5] refactor: Add protoc compilation to the Makefile

Add protocol buffer generation as part of the Makefile for
the node gRPC service
---
 Makefile                                      |   7 +-
 .../node_servicepb/node_rpc.pb.go             | 161 +++++++++---------
 .../node_servicepb/node_rpc_grpc.pb.go        |   4 +-
 3 files changed, 89 insertions(+), 83 deletions(-)

diff --git a/Makefile b/Makefile
index 5611f9aa..6da7a538 100644
--- a/Makefile
+++ b/Makefile
@@ -51,7 +51,12 @@ help:
 all: clean bin openshift push
 openshift-all: clean openshift push
 
-bin: controller node
+bin: protoc controller node
+
+protoc: 
+	@echo ""
+	@echo "[] protocol buffers"
+	protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./pkg/node_service/node_servicepb/node_rpc.proto
 
 controller:
 	@echo ""
diff --git a/pkg/node_service/node_servicepb/node_rpc.pb.go b/pkg/node_service/node_servicepb/node_rpc.pb.go
index 3275953e..934615a9 100644
--- a/pkg/node_service/node_servicepb/node_rpc.pb.go
+++ b/pkg/node_service/node_servicepb/node_rpc.pb.go
@@ -2,7 +2,7 @@
 // versions:
 // 	protoc-gen-go v1.28.1
 // 	protoc        v4.22.2
-// source: node_servicepb/node_rpc.proto
+// source: pkg/node_service/node_servicepb/node_rpc.proto
 
 package node_servicepb
 
@@ -56,11 +56,11 @@ func (x InitiatorType) String() string {
 }
 
 func (InitiatorType) Descriptor() protoreflect.EnumDescriptor {
-	return file_node_servicepb_node_rpc_proto_enumTypes[0].Descriptor()
+	return file_pkg_node_service_node_servicepb_node_rpc_proto_enumTypes[0].Descriptor()
 }
 
 func (InitiatorType) Type() protoreflect.EnumType {
-	return &file_node_servicepb_node_rpc_proto_enumTypes[0]
+	return &file_pkg_node_service_node_servicepb_node_rpc_proto_enumTypes[0]
 }
 
 func (x InitiatorType) Number() protoreflect.EnumNumber {
@@ -69,7 +69,7 @@ func (x InitiatorType) Number() protoreflect.EnumNumber {
 
 // Deprecated: Use InitiatorType.Descriptor instead.
 func (InitiatorType) EnumDescriptor() ([]byte, []int) {
-	return file_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{0}
+	return file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{0}
 }
 
 type InitiatorRequest struct {
@@ -83,7 +83,7 @@ type InitiatorRequest struct {
 func (x *InitiatorRequest) Reset() {
 	*x = InitiatorRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_node_servicepb_node_rpc_proto_msgTypes[0]
+		mi := &file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[0]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -96,7 +96,7 @@ func (x *InitiatorRequest) String() string {
 func (*InitiatorRequest) ProtoMessage() {}
 
 func (x *InitiatorRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_node_servicepb_node_rpc_proto_msgTypes[0]
+	mi := &file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[0]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -109,7 +109,7 @@ func (x *InitiatorRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use InitiatorRequest.ProtoReflect.Descriptor instead.
 func (*InitiatorRequest) Descriptor() ([]byte, []int) {
-	return file_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{0}
+	return file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{0}
 }
 
 func (x *InitiatorRequest) GetType() InitiatorType {
@@ -130,7 +130,7 @@ type Initiators struct {
 func (x *Initiators) Reset() {
 	*x = Initiators{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_node_servicepb_node_rpc_proto_msgTypes[1]
+		mi := &file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[1]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -143,7 +143,7 @@ func (x *Initiators) String() string {
 func (*Initiators) ProtoMessage() {}
 
 func (x *Initiators) ProtoReflect() protoreflect.Message {
-	mi := &file_node_servicepb_node_rpc_proto_msgTypes[1]
+	mi := &file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[1]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -156,7 +156,7 @@ func (x *Initiators) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Initiators.ProtoReflect.Descriptor instead.
 func (*Initiators) Descriptor() ([]byte, []int) {
-	return file_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{1}
+	return file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{1}
 }
 
 func (x *Initiators) GetInitiators() []string {
@@ -177,7 +177,7 @@ type UnmappedVolume struct {
 func (x *UnmappedVolume) Reset() {
 	*x = UnmappedVolume{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_node_servicepb_node_rpc_proto_msgTypes[2]
+		mi := &file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[2]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -190,7 +190,7 @@ func (x *UnmappedVolume) String() string {
 func (*UnmappedVolume) ProtoMessage() {}
 
 func (x *UnmappedVolume) ProtoReflect() protoreflect.Message {
-	mi := &file_node_servicepb_node_rpc_proto_msgTypes[2]
+	mi := &file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[2]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -203,7 +203,7 @@ func (x *UnmappedVolume) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use UnmappedVolume.ProtoReflect.Descriptor instead.
 func (*UnmappedVolume) Descriptor() ([]byte, []int) {
-	return file_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{2}
+	return file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{2}
 }
 
 func (x *UnmappedVolume) GetVolumeName() string {
@@ -224,7 +224,7 @@ type Ack struct {
 func (x *Ack) Reset() {
 	*x = Ack{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_node_servicepb_node_rpc_proto_msgTypes[3]
+		mi := &file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[3]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -237,7 +237,7 @@ func (x *Ack) String() string {
 func (*Ack) ProtoMessage() {}
 
 func (x *Ack) ProtoReflect() protoreflect.Message {
-	mi := &file_node_servicepb_node_rpc_proto_msgTypes[3]
+	mi := &file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[3]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -250,7 +250,7 @@ func (x *Ack) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use Ack.ProtoReflect.Descriptor instead.
 func (*Ack) Descriptor() ([]byte, []int) {
-	return file_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{3}
+	return file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescGZIP(), []int{3}
 }
 
 func (x *Ack) GetAck() int32 {
@@ -260,68 +260,69 @@ func (x *Ack) GetAck() int32 {
 	return 0
 }
 
-var File_node_servicepb_node_rpc_proto protoreflect.FileDescriptor
-
-var file_node_servicepb_node_rpc_proto_rawDesc = []byte{
-	0x0a, 0x1d, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x70, 0x62,
-	0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
-	0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x43, 0x0a,
-	0x10, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x12, 0x2f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32,
-	0x1b, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49,
-	0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79,
-	0x70, 0x65, 0x22, 0x2c, 0x0a, 0x0a, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x73,
-	0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18, 0x01,
-	0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x73,
-	0x22, 0x30, 0x0a, 0x0e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x56, 0x6f, 0x6c, 0x75,
-	0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x4e, 0x61, 0x6d, 0x65,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x4e, 0x61,
-	0x6d, 0x65, 0x22, 0x17, 0x0a, 0x03, 0x41, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x6b,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x63, 0x6b, 0x2a, 0x3c, 0x0a, 0x0d, 0x49,
-	0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b,
-	0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x06, 0x0a,
-	0x02, 0x46, 0x43, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x41, 0x53, 0x10, 0x02, 0x12, 0x09,
-	0x0a, 0x05, 0x49, 0x53, 0x43, 0x53, 0x49, 0x10, 0x03, 0x32, 0x9c, 0x01, 0x0a, 0x0b, 0x4e, 0x6f,
-	0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x0d, 0x47, 0x65, 0x74,
-	0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x6e, 0x6f, 0x64,
-	0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61,
-	0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6e, 0x6f, 0x64,
-	0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61,
-	0x74, 0x6f, 0x72, 0x73, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0b, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79,
-	0x55, 0x6e, 0x6d, 0x61, 0x70, 0x12, 0x1c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72,
-	0x76, 0x69, 0x63, 0x65, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x56, 0x6f, 0x6c,
-	0x75, 0x6d, 0x65, 0x1a, 0x11, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
-	0x63, 0x65, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x57, 0x5a, 0x55, 0x67, 0x69, 0x74, 0x68,
-	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x65, 0x61, 0x67, 0x61, 0x74, 0x65, 0x2f, 0x73,
-	0x65, 0x61, 0x67, 0x61, 0x74, 0x65, 0x2d, 0x65, 0x78, 0x6f, 0x73, 0x2d, 0x78, 0x2d, 0x63, 0x73,
-	0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
-	0x63, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x62, 0x75, 0x66, 0x66, 0x65,
-	0x72, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x70,
-	0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+var File_pkg_node_service_node_servicepb_node_rpc_proto protoreflect.FileDescriptor
+
+var file_pkg_node_service_node_servicepb_node_rpc_proto_rawDesc = []byte{
+	0x0a, 0x2e, 0x70, 0x6b, 0x67, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69,
+	0x63, 0x65, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x70,
+	0x62, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x12, 0x0c, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x43,
+	0x0a, 0x10, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x12, 0x2f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
+	0x32, 0x1b, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e,
+	0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74,
+	0x79, 0x70, 0x65, 0x22, 0x2c, 0x0a, 0x0a, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72,
+	0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x18,
+	0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72,
+	0x73, 0x22, 0x30, 0x0a, 0x0e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x56, 0x6f, 0x6c,
+	0x75, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x4e, 0x61, 0x6d,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x6f, 0x6c, 0x75, 0x6d, 0x65, 0x4e,
+	0x61, 0x6d, 0x65, 0x22, 0x17, 0x0a, 0x03, 0x41, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63,
+	0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x63, 0x6b, 0x2a, 0x3c, 0x0a, 0x0d,
+	0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a,
+	0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x06,
+	0x0a, 0x02, 0x46, 0x43, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x41, 0x53, 0x10, 0x02, 0x12,
+	0x09, 0x0a, 0x05, 0x49, 0x53, 0x43, 0x53, 0x49, 0x10, 0x03, 0x32, 0x9c, 0x01, 0x0a, 0x0b, 0x4e,
+	0x6f, 0x64, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x0d, 0x47, 0x65,
+	0x74, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x6e, 0x6f,
+	0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69,
+	0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6e, 0x6f,
+	0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x69, 0x74, 0x69,
+	0x61, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0b, 0x4e, 0x6f, 0x74, 0x69, 0x66,
+	0x79, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x12, 0x1c, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65,
+	0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x64, 0x56, 0x6f,
+	0x6c, 0x75, 0x6d, 0x65, 0x1a, 0x11, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76,
+	0x69, 0x63, 0x65, 0x2e, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x42, 0x57, 0x5a, 0x55, 0x67, 0x69, 0x74,
+	0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x53, 0x65, 0x61, 0x67, 0x61, 0x74, 0x65, 0x2f,
+	0x73, 0x65, 0x61, 0x67, 0x61, 0x74, 0x65, 0x2d, 0x65, 0x78, 0x6f, 0x73, 0x2d, 0x78, 0x2d, 0x63,
+	0x73, 0x69, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76,
+	0x69, 0x63, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x62, 0x75, 0x66, 0x66,
+	0x65, 0x72, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
+	0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
-	file_node_servicepb_node_rpc_proto_rawDescOnce sync.Once
-	file_node_servicepb_node_rpc_proto_rawDescData = file_node_servicepb_node_rpc_proto_rawDesc
+	file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescOnce sync.Once
+	file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescData = file_pkg_node_service_node_servicepb_node_rpc_proto_rawDesc
 )
 
-func file_node_servicepb_node_rpc_proto_rawDescGZIP() []byte {
-	file_node_servicepb_node_rpc_proto_rawDescOnce.Do(func() {
-		file_node_servicepb_node_rpc_proto_rawDescData = protoimpl.X.CompressGZIP(file_node_servicepb_node_rpc_proto_rawDescData)
+func file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescGZIP() []byte {
+	file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescOnce.Do(func() {
+		file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescData)
 	})
-	return file_node_servicepb_node_rpc_proto_rawDescData
+	return file_pkg_node_service_node_servicepb_node_rpc_proto_rawDescData
 }
 
-var file_node_servicepb_node_rpc_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_node_servicepb_node_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
-var file_node_servicepb_node_rpc_proto_goTypes = []interface{}{
+var file_pkg_node_service_node_servicepb_node_rpc_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_pkg_node_service_node_servicepb_node_rpc_proto_goTypes = []interface{}{
 	(InitiatorType)(0),       // 0: node_service.InitiatorType
 	(*InitiatorRequest)(nil), // 1: node_service.InitiatorRequest
 	(*Initiators)(nil),       // 2: node_service.Initiators
 	(*UnmappedVolume)(nil),   // 3: node_service.UnmappedVolume
 	(*Ack)(nil),              // 4: node_service.Ack
 }
-var file_node_servicepb_node_rpc_proto_depIdxs = []int32{
+var file_pkg_node_service_node_servicepb_node_rpc_proto_depIdxs = []int32{
 	0, // 0: node_service.InitiatorRequest.type:type_name -> node_service.InitiatorType
 	1, // 1: node_service.NodeService.GetInitiators:input_type -> node_service.InitiatorRequest
 	3, // 2: node_service.NodeService.NotifyUnmap:input_type -> node_service.UnmappedVolume
@@ -334,13 +335,13 @@ var file_node_servicepb_node_rpc_proto_depIdxs = []int32{
 	0, // [0:1] is the sub-list for field type_name
 }
 
-func init() { file_node_servicepb_node_rpc_proto_init() }
-func file_node_servicepb_node_rpc_proto_init() {
-	if File_node_servicepb_node_rpc_proto != nil {
+func init() { file_pkg_node_service_node_servicepb_node_rpc_proto_init() }
+func file_pkg_node_service_node_servicepb_node_rpc_proto_init() {
+	if File_pkg_node_service_node_servicepb_node_rpc_proto != nil {
 		return
 	}
 	if !protoimpl.UnsafeEnabled {
-		file_node_servicepb_node_rpc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*InitiatorRequest); i {
 			case 0:
 				return &v.state
@@ -352,7 +353,7 @@ func file_node_servicepb_node_rpc_proto_init() {
 				return nil
 			}
 		}
-		file_node_servicepb_node_rpc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*Initiators); i {
 			case 0:
 				return &v.state
@@ -364,7 +365,7 @@ func file_node_servicepb_node_rpc_proto_init() {
 				return nil
 			}
 		}
-		file_node_servicepb_node_rpc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*UnmappedVolume); i {
 			case 0:
 				return &v.state
@@ -376,7 +377,7 @@ func file_node_servicepb_node_rpc_proto_init() {
 				return nil
 			}
 		}
-		file_node_servicepb_node_rpc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+		file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*Ack); i {
 			case 0:
 				return &v.state
@@ -393,19 +394,19 @@ func file_node_servicepb_node_rpc_proto_init() {
 	out := protoimpl.TypeBuilder{
 		File: protoimpl.DescBuilder{
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
-			RawDescriptor: file_node_servicepb_node_rpc_proto_rawDesc,
+			RawDescriptor: file_pkg_node_service_node_servicepb_node_rpc_proto_rawDesc,
 			NumEnums:      1,
 			NumMessages:   4,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
-		GoTypes:           file_node_servicepb_node_rpc_proto_goTypes,
-		DependencyIndexes: file_node_servicepb_node_rpc_proto_depIdxs,
-		EnumInfos:         file_node_servicepb_node_rpc_proto_enumTypes,
-		MessageInfos:      file_node_servicepb_node_rpc_proto_msgTypes,
+		GoTypes:           file_pkg_node_service_node_servicepb_node_rpc_proto_goTypes,
+		DependencyIndexes: file_pkg_node_service_node_servicepb_node_rpc_proto_depIdxs,
+		EnumInfos:         file_pkg_node_service_node_servicepb_node_rpc_proto_enumTypes,
+		MessageInfos:      file_pkg_node_service_node_servicepb_node_rpc_proto_msgTypes,
 	}.Build()
-	File_node_servicepb_node_rpc_proto = out.File
-	file_node_servicepb_node_rpc_proto_rawDesc = nil
-	file_node_servicepb_node_rpc_proto_goTypes = nil
-	file_node_servicepb_node_rpc_proto_depIdxs = nil
+	File_pkg_node_service_node_servicepb_node_rpc_proto = out.File
+	file_pkg_node_service_node_servicepb_node_rpc_proto_rawDesc = nil
+	file_pkg_node_service_node_servicepb_node_rpc_proto_goTypes = nil
+	file_pkg_node_service_node_servicepb_node_rpc_proto_depIdxs = nil
 }
diff --git a/pkg/node_service/node_servicepb/node_rpc_grpc.pb.go b/pkg/node_service/node_servicepb/node_rpc_grpc.pb.go
index 512ad1ee..ebfbc97d 100644
--- a/pkg/node_service/node_servicepb/node_rpc_grpc.pb.go
+++ b/pkg/node_service/node_servicepb/node_rpc_grpc.pb.go
@@ -2,7 +2,7 @@
 // versions:
 // - protoc-gen-go-grpc v1.2.0
 // - protoc             v4.22.2
-// source: node_servicepb/node_rpc.proto
+// source: pkg/node_service/node_servicepb/node_rpc.proto
 
 package node_servicepb
 
@@ -137,5 +137,5 @@ var NodeService_ServiceDesc = grpc.ServiceDesc{
 		},
 	},
 	Streams:  []grpc.StreamDesc{},
-	Metadata: "node_servicepb/node_rpc.proto",
+	Metadata: "pkg/node_service/node_servicepb/node_rpc.proto",
 }

From 1a7fb637a8a3521d7a94a1f514948409709ebfbd Mon Sep 17 00:00:00 2001
From: David White <david.white@seagate.com>
Date: Wed, 12 Apr 2023 13:38:38 -0600
Subject: [PATCH 3/5] fix: Remove commented code

---
 pkg/common/identity.go | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/pkg/common/identity.go b/pkg/common/identity.go
index ec8569a7..4eb5f9d0 100644
--- a/pkg/common/identity.go
+++ b/pkg/common/identity.go
@@ -32,13 +32,6 @@ func (driver *Driver) GetPluginCapabilities(ctx context.Context, req *csi.GetPlu
 					},
 				},
 			},
-			// {
-			// 	Type: &csi.PluginCapability_Service_{
-			// 		Service: &csi.PluginCapability_Service{
-			// 			Type: csi.PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS,
-			// 		},
-			// 	},
-			// },
 		},
 	}, nil
 }

From 58b36b55e25f09caead656fd7468f1461f74bacd Mon Sep 17 00:00:00 2001
From: David White <david.white@seagate.com>
Date: Wed, 12 Apr 2023 15:05:03 -0600
Subject: [PATCH 4/5] fix: Remove hyphens from environment variables

Remove hyphens from environment variable names and add names
into the configuration constants of the common driver code
---
 helm/csi-charts/templates/daemonset.yaml  |  6 +++---
 helm/csi-charts/templates/deployment.yaml |  2 +-
 pkg/common/driver.go                      |  5 +++++
 pkg/node/node.go                          |  8 ++++----
 pkg/node_service/node_service_client.go   | 10 ++++++----
 pkg/node_service/node_service_server.go   |  2 +-
 6 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/helm/csi-charts/templates/daemonset.yaml b/helm/csi-charts/templates/daemonset.yaml
index d37176a4..6d4a6de8 100644
--- a/helm/csi-charts/templates/daemonset.yaml
+++ b/helm/csi-charts/templates/daemonset.yaml
@@ -39,15 +39,15 @@ spec:
             - -chroot=/host
 {{- include "csidriver.extraArgs" .Values.node | indent 10 }}
           env:
-            - name: EXOS-X-CSI-NODE-NAME
+            - name: CSI_NODE_NAME
               valueFrom:
                 fieldRef:
                   fieldPath: spec.nodeName
-            - name: EXOS-X-CSI-NODE-IP
+            - name: CSI_NODE_IP
               valueFrom:
                 fieldRef:
                   fieldPath: status.podIP
-            - name: EXOS-X-CSI-NODE-SERVICE-PORT
+            - name: CSI_NODE_SERVICE_PORT
               value: "978"
           securityContext:
             privileged: true
diff --git a/helm/csi-charts/templates/deployment.yaml b/helm/csi-charts/templates/deployment.yaml
index 0f77cd6d..464f02d9 100644
--- a/helm/csi-charts/templates/deployment.yaml
+++ b/helm/csi-charts/templates/deployment.yaml
@@ -30,7 +30,7 @@ spec:
             - -bind=unix:///csi/csi.sock
 {{- include "csidriver.extraArgs" .Values.controller | indent 10 }}
           env:
-            - name: EXOS-X-CSI-NODE-SERVICE-PORT
+            - name: CSI_NODE_SERVICE_PORT
               value: "978"
           volumeMounts:
             - name: socket-dir
diff --git a/pkg/common/driver.go b/pkg/common/driver.go
index 52b511a5..d536771b 100644
--- a/pkg/common/driver.go
+++ b/pkg/common/driver.go
@@ -47,6 +47,11 @@ const (
 	MaximumLUN            = 255
 	VolumeNameMaxLength   = 31
 	VolumePrefixMaxLength = 3
+
+	//If changed, must also be updated in helm charts
+	NodeIPEnvVar          = "CSI_NODE_IP"
+	NodeNameEnvVar        = "CSI_NODE_NAME"
+	NodeServicePortEnvVar = "CSI_NODE_SERVICE_PORT"
 )
 
 // Driver contains main resources needed by the driver and references the underlying specific driver
diff --git a/pkg/node/node.go b/pkg/node/node.go
index 8d78c131..e29f41c4 100644
--- a/pkg/node/node.go
+++ b/pkg/node/node.go
@@ -37,15 +37,15 @@ func New() *Node {
 		iscsi.EnableDebugLogging(os.Stderr)
 	}
 
-	envNodeName, _ := os.LookupEnv("EXOS-X-CSI-NODE-NAME")
-	nodeIP, envFound := os.LookupEnv("EXOS-X-CSI-NODE-IP")
+	envNodeName, _ := os.LookupEnv(common.NodeNameEnvVar)
+	nodeIP, envFound := os.LookupEnv(common.NodeIPEnvVar)
 	if !envFound {
 		klog.InfoS("no Node IP found in environment. Using default")
 		nodeIP = "127.0.0.1"
 	}
-	envServicePort, envFound := os.LookupEnv("EXOS-X-CSI-NODE-SERVICE-PORT")
+	envServicePort, envFound := os.LookupEnv(common.NodeServicePortEnvVar)
 	if !envFound {
-		klog.InfoS("no Node service port found in environment. Using default")
+		klog.InfoS("no node service port found in environment. Using default")
 		envServicePort = "978"
 	}
 
diff --git a/pkg/node_service/node_service_client.go b/pkg/node_service/node_service_client.go
index f5e3a07f..438e700f 100644
--- a/pkg/node_service/node_service_client.go
+++ b/pkg/node_service/node_service_client.go
@@ -5,26 +5,28 @@ import (
 	"os"
 	"time"
 
+	"github.com/Seagate/seagate-exos-x-csi/pkg/common"
 	pb "github.com/Seagate/seagate-exos-x-csi/pkg/node_service/node_servicepb"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials/insecure"
 	"k8s.io/klog/v2"
 )
 
-func GetNodeInitiators(nodeIP string, reqType pb.InitiatorType) ([]string, error) {
-	port, envFound := os.LookupEnv("EXOS-X-CSI-NODE-SERVICE-PORT")
+// Connect to the node_service gRPC server at the given address and retrieve initiators
+func GetNodeInitiators(nodeAddress string, reqType pb.InitiatorType) ([]string, error) {
+	port, envFound := os.LookupEnv(common.NodeServicePortEnvVar)
 	if !envFound {
 		port = "978"
 		klog.InfoS("no node service port found in environment. using default", "port", port)
 	}
 
-	nodeServiceAddr := nodeIP + ":" + port
+	nodeServiceAddr := nodeAddress + ":" + port
 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 	defer cancel()
 
 	conn, err := grpc.Dial(nodeServiceAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
 	if err != nil {
-		klog.ErrorS(err, "Error connecting to node service", "node ip", nodeIP, "port", port)
+		klog.ErrorS(err, "Error connecting to node service", "node ip", nodeAddress, "port", port)
 		return nil, err
 	}
 	defer conn.Close()
diff --git a/pkg/node_service/node_service_server.go b/pkg/node_service/node_service_server.go
index a4d734f6..91f1aa57 100644
--- a/pkg/node_service/node_service_server.go
+++ b/pkg/node_service/node_service_server.go
@@ -25,7 +25,7 @@ func (s *server) GetInitiators(ctx context.Context, in *pb.InitiatorRequest) (*p
 	case pb.InitiatorType_ISCSI:
 		initiators, err = storage.GetISCSIInitiators()
 	case pb.InitiatorType_UNSPECIFIED:
-		klog.InfoS("Unspecified Initiator Type in Initiator Request")
+		klog.InfoS("Unspecified initiator type in initiator request")
 	}
 	if err != nil {
 		return nil, err

From 2de2a6ccf2171543bb61772b3104ef3159aa858f Mon Sep 17 00:00:00 2001
From: David White <david.white@seagate.com>
Date: Fri, 21 Apr 2023 12:46:18 -0600
Subject: [PATCH 5/5] chore: update log message to structured logging

---
 pkg/controller/publisher.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pkg/controller/publisher.go b/pkg/controller/publisher.go
index 72754489..bfd756b7 100644
--- a/pkg/controller/publisher.go
+++ b/pkg/controller/publisher.go
@@ -45,7 +45,7 @@ func (driver *Controller) ControllerPublishVolume(ctx context.Context, req *csi.
 
 	volumeName, _ := common.VolumeIdGetName(req.GetVolumeId())
 
-	klog.Infof("attach request for initiator(s) %v, volume id: %s", initiators, volumeName)
+	klog.InfoS("attach request", "initiator(s)", initiators, "volume", volumeName)
 
 	lun, err := driver.client.PublishVolume(volumeName, initiators)