Skip to content

Commit 30ed68b

Browse files
authored
Merge pull request #3 from serverscom/fix-cleanup-target
Fix cleanup iscsi target
2 parents 10065cc + 4b408bf commit 30ed68b

File tree

5 files changed

+91
-27
lines changed

5 files changed

+91
-27
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@ Labels merge with priority: **System > PVC > StorageClass**
6868
Example:
6969
```yaml
7070
# StorageClass labels
71-
metadata:
72-
labels:
73-
environment: production
71+
parameters:
72+
rbs.csi.servers.com/labels: |
73+
{
74+
"managed-by": "kubernetes"
75+
}
7476
7577
---
7678
# PVC labels

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
go.uber.org/mock v0.6.0
1212
google.golang.org/grpc v1.75.0
1313
google.golang.org/protobuf v1.36.10
14+
k8s.io/api v0.34.2
1415
k8s.io/apimachinery v0.34.2
1516
k8s.io/client-go v0.34.2
1617
k8s.io/klog/v2 v2.130.1
@@ -52,7 +53,6 @@ require (
5253
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
5354
gopkg.in/inf.v0 v0.9.1 // indirect
5455
gopkg.in/yaml.v3 v3.0.1 // indirect
55-
k8s.io/api v0.34.2 // indirect
5656
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
5757
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
5858
sigs.k8s.io/randfill v1.0.0 // indirect

pkg/csi/helpers.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,19 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"os"
8+
"path/filepath"
79
"strconv"
810
"time"
911

12+
"github.com/serverscom/rbs-csi-driver/pkg/iscsi"
1013
serverscom "github.com/serverscom/serverscom-go-client/pkg"
1114
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1215
"k8s.io/klog/v2"
1316
)
1417

18+
const targetInfoFile = ".target-info"
19+
1520
// getLocationID gets location ID from parameters, supporting both ID and name
1621
func (s *ControllerService) getLocationID(ctx context.Context, parameters map[string]string) (int, error) {
1722
locationStr, ok := parameters["rbs.csi.servers.com/location"]
@@ -113,3 +118,38 @@ func (s *ControllerService) waitForVolumeActive(ctx context.Context, volumeID st
113118
}
114119
}
115120
}
121+
122+
func targetInfoPath(stagingPath string) string {
123+
return filepath.Join(stagingPath, targetInfoFile)
124+
}
125+
126+
func SaveTargetInfo(stagingPath string, target *iscsi.TargetInfo) error {
127+
data, err := json.Marshal(target)
128+
if err != nil {
129+
return err
130+
}
131+
132+
return os.WriteFile(targetInfoPath(stagingPath), data, 0600)
133+
}
134+
135+
func LoadTargetInfo(stagingPath string) (*iscsi.TargetInfo, error) {
136+
data, err := os.ReadFile(targetInfoPath(stagingPath))
137+
if err != nil {
138+
return nil, err
139+
}
140+
141+
var target iscsi.TargetInfo
142+
if err := json.Unmarshal(data, &target); err != nil {
143+
return nil, err
144+
}
145+
146+
return &target, nil
147+
}
148+
149+
func DeleteTargetInfo(stagingPath string) error {
150+
err := os.Remove(targetInfoPath(stagingPath))
151+
if err != nil && !os.IsNotExist(err) {
152+
return err
153+
}
154+
return nil
155+
}

pkg/csi/node.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"fmt"
66
"os"
7-
"strings"
87
"time"
98

109
"github.com/container-storage-interface/spec/lib/go/csi"
@@ -86,6 +85,11 @@ func (s *NodeService) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
8685
}
8786
klog.V(2).InfoS("Prepared iSCSI target", "portal", portal, "iqn", targetIQN)
8887

88+
if err := SaveTargetInfo(stagingPath, target); err != nil {
89+
klog.ErrorS(err, "Failed to save target info")
90+
return nil, status.Errorf(codes.Internal, "failed to save target info: %v", err)
91+
}
92+
8993
// Check if already logged in
9094
klog.V(2).InfoS("Checking iscsi login status")
9195
loggedIn, err := s.iscsiManager.IsLoggedIn(ctx, target)
@@ -158,37 +162,33 @@ func (s *NodeService) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstag
158162

159163
stagingPath := req.GetStagingTargetPath()
160164

161-
// Check if staging path is mounted
162165
mounted, err := s.mountManager.IsMounted(stagingPath)
163166
if err != nil {
164-
return nil, status.Errorf(codes.Internal, "failed to check if staging path is mounted: %v", err)
167+
return nil, status.Errorf(codes.Internal, "failed to check mount: %v", err)
165168
}
166169

167170
if mounted {
168-
// Get mount info to determine device
169-
mountInfo, err := s.mountManager.GetMountInfo(stagingPath)
170-
if err != nil {
171-
return nil, status.Errorf(codes.Internal, "failed to get mount info: %v", err)
172-
}
173-
174-
// Unmount the staging path
175-
klog.V(1).InfoS("Unmounting staging path", "staging_path", stagingPath)
171+
klog.V(2).InfoS("Unmounting staging path", "staging_path", stagingPath)
176172
if err := s.mountManager.Unmount(ctx, stagingPath); err != nil {
177173
return nil, status.Errorf(codes.Internal, "failed to unmount staging path: %v", err)
178174
}
175+
}
179176

180-
// Try to logout from iSCSI target
181-
if strings.Contains(mountInfo.Device, "/dev/") {
182-
klog.V(1).InfoS("Device unmounted", "device", mountInfo.Device)
177+
// Load target info and cleanup iSCSI
178+
target, err := LoadTargetInfo(stagingPath)
179+
if err == nil {
180+
if err := s.iscsiManager.CleanupTarget(ctx, target); err != nil {
181+
return nil, status.Errorf(codes.Internal, "iscsi cleanup failed: %v", err)
183182
}
184183
}
185184

186-
// Remove staging directory
185+
_ = DeleteTargetInfo(stagingPath)
186+
187187
if err := os.RemoveAll(stagingPath); err != nil {
188-
klog.ErrorS(err, "Failed to remove staging directory")
188+
klog.ErrorS(err, "Failed to remove staging directory", "path", stagingPath)
189189
}
190190

191-
klog.InfoS("Volume unstaged successfully", "volume_id", req.GetVolumeId())
191+
klog.V(1).InfoS("Volume unstaged successfully", "volume_id", req.GetVolumeId())
192192
return &csi.NodeUnstageVolumeResponse{}, nil
193193
}
194194

pkg/csi/node_test.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package csi
22

33
import (
44
"context"
5+
"encoding/json"
56
"errors"
7+
"os"
8+
"path/filepath"
69
"testing"
710
"time"
811

@@ -221,7 +224,7 @@ func TestNodeUnstageVolume_Success(t *testing.T) {
221224
ctrl := gomock.NewController(t)
222225
defer ctrl.Finish()
223226

224-
svc, _, mmount := newTestNode(ctrl)
227+
svc, iscsiMgr, mmount := newTestNode(ctrl)
225228
ctx := context.Background()
226229

227230
req := &csi.NodeUnstageVolumeRequest{
@@ -230,24 +233,32 @@ func TestNodeUnstageVolume_Success(t *testing.T) {
230233
}
231234

232235
mmount.EXPECT().IsMounted("/tmp/staging").Return(true, nil)
233-
mmount.EXPECT().GetMountInfo("/tmp/staging").Return(&mount.MountInfo{
234-
Device: "/dev/sdb",
235-
FSType: "ext4",
236-
}, nil)
237236
mmount.EXPECT().Unmount(ctx, "/tmp/staging").Return(nil)
238237

238+
target := &iscsi.TargetInfo{
239+
IQN: "iqn.test",
240+
Portal: "127.0.0.1:3260",
241+
}
242+
data, _ := json.Marshal(target)
243+
_ = os.MkdirAll(req.StagingTargetPath, 0755)
244+
_ = os.WriteFile(filepath.Join(req.StagingTargetPath, ".target-info"), data, 0600)
245+
246+
iscsiMgr.EXPECT().CleanupTarget(ctx, target).Return(nil)
247+
239248
resp, err := svc.NodeUnstageVolume(ctx, req)
240249

241250
g.Expect(err).To(BeNil())
242251
g.Expect(resp).NotTo(BeNil())
252+
253+
_ = os.RemoveAll(req.StagingTargetPath)
243254
}
244255

245256
func TestNodeUnstageVolume_NotMounted(t *testing.T) {
246257
g := NewGomegaWithT(t)
247258
ctrl := gomock.NewController(t)
248259
defer ctrl.Finish()
249260

250-
svc, _, mmount := newTestNode(ctrl)
261+
svc, iscsiMgr, mmount := newTestNode(ctrl)
251262
ctx := context.Background()
252263

253264
req := &csi.NodeUnstageVolumeRequest{
@@ -257,10 +268,21 @@ func TestNodeUnstageVolume_NotMounted(t *testing.T) {
257268

258269
mmount.EXPECT().IsMounted("/tmp/staging").Return(false, nil)
259270

271+
target := &iscsi.TargetInfo{
272+
IQN: "iqn.test",
273+
Portal: "127.0.0.1:3260",
274+
}
275+
_ = os.MkdirAll(req.StagingTargetPath, 0755)
276+
_ = os.WriteFile(filepath.Join(req.StagingTargetPath, ".target-info"), []byte(`{"IQN":"iqn.test","Portal":"127.0.0.1:3260"}`), 0600)
277+
278+
iscsiMgr.EXPECT().CleanupTarget(ctx, target).Return(nil)
279+
260280
resp, err := svc.NodeUnstageVolume(ctx, req)
261281

262282
g.Expect(err).To(BeNil())
263283
g.Expect(resp).NotTo(BeNil())
284+
285+
_ = os.RemoveAll(req.StagingTargetPath)
264286
}
265287

266288
func TestNodePublishVolume_Success(t *testing.T) {

0 commit comments

Comments
 (0)