Skip to content

Commit 4aeb1dc

Browse files
committed
record csi mount config to sandbox annotation
Signed-off-by: jicheng.sk <jicheng.sk@alibaba-inc.com>
1 parent c0bd69a commit 4aeb1dc

File tree

3 files changed

+201
-5
lines changed

3 files changed

+201
-5
lines changed

pkg/servers/e2b/create.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ func (sc *Controller) createSandboxWithClaim(ctx context.Context, request models
6060
ClaimTimeout: time.Duration(request.Extensions.TimeoutSeconds) * time.Second,
6161
Modifier: func(sbx infra.Sandbox) {
6262
sc.basicSandboxCreateModifier(ctx, sbx, request)
63+
sc.csiMountOptionsConfigRecord(ctx, sbx, request)
6364
},
6465
ReserveFailedSandbox: request.Extensions.ReserveFailedSandbox,
6566
CreateOnNoStock: request.Extensions.CreateOnNoStock,
@@ -257,3 +258,24 @@ func (sc *Controller) basicSandboxCreateModifier(ctx context.Context, sbx infra.
257258
}
258259
sbx.SetAnnotations(annotations)
259260
}
261+
262+
func (sc *Controller) csiMountOptionsConfigRecord(ctx context.Context, sbx infra.Sandbox, request models.NewSandboxRequest) {
263+
log := klog.FromContext(ctx)
264+
// fetch the csi mount config from request
265+
if len(request.Extensions.CSIMount.MountConfigs) == 0 {
266+
return
267+
}
268+
// marshal the csi mount confit to json
269+
csiMountConfigRaw, err := json.Marshal(request.Extensions.CSIMount.MountConfigs)
270+
if err != nil {
271+
log.Info("failed to marshal csi mount config", err)
272+
return
273+
}
274+
annotations := sbx.GetAnnotations()
275+
if annotations == nil {
276+
annotations = make(map[string]string)
277+
}
278+
// record the csi mount config to annotation
279+
annotations[models.ExtensionKeyClaimWithCSIMount_MountConfig] = string(csiMountConfigRaw)
280+
sbx.SetAnnotations(annotations)
281+
}

pkg/servers/e2b/create_test.go

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package e2b
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"reflect"
7+
"testing"
8+
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
11+
agentsv1alpha1 "github.com/openkruise/agents/api/v1alpha1"
12+
"github.com/openkruise/agents/pkg/sandbox-manager/infra/sandboxcr"
13+
"github.com/openkruise/agents/pkg/servers/e2b/models"
14+
)
15+
16+
// TestCsiMountOptionsConfigRecord tests the csiMountOptionsConfigRecord function
17+
func TestCsiMountOptionsConfigRecord(t *testing.T) {
18+
tests := []struct {
19+
name string
20+
request models.NewSandboxRequest
21+
initialAnnotations map[string]string
22+
expectedAnnotationKey string
23+
expectedAnnotationVal string
24+
shouldSet bool
25+
}{
26+
{
27+
name: "empty mount configs",
28+
request: models.NewSandboxRequest{
29+
Extensions: models.NewSandboxRequestExtension{
30+
CSIMount: models.CSIMountExtension{
31+
MountConfigs: []models.CSIMountConfig{},
32+
},
33+
},
34+
},
35+
shouldSet: false,
36+
},
37+
{
38+
name: "single mount config with all fields",
39+
request: models.NewSandboxRequest{
40+
Extensions: models.NewSandboxRequestExtension{
41+
CSIMount: models.CSIMountExtension{
42+
MountConfigs: []models.CSIMountConfig{
43+
{
44+
MountID: "mount-123",
45+
PvName: "pv-nas-001",
46+
MountPath: "/data",
47+
SubPath: "subdir",
48+
ReadOnly: true,
49+
},
50+
},
51+
},
52+
},
53+
Metadata: map[string]string{
54+
"user-id": "user-456",
55+
},
56+
},
57+
initialAnnotations: map[string]string{},
58+
expectedAnnotationKey: models.ExtensionKeyClaimWithCSIMount_MountConfig,
59+
expectedAnnotationVal: `[{"mountID":"mount-123","pvName":"pv-nas-001","mountPath":"/data","subPath":"subdir","readOnly":true}]`,
60+
shouldSet: true,
61+
},
62+
{
63+
name: "multiple mount configs with optional fields omitted",
64+
request: models.NewSandboxRequest{
65+
Extensions: models.NewSandboxRequestExtension{
66+
CSIMount: models.CSIMountExtension{
67+
MountConfigs: []models.CSIMountConfig{
68+
{
69+
PvName: "pv-nas-001",
70+
MountPath: "/data",
71+
},
72+
{
73+
PvName: "pv-oss-002",
74+
MountPath: "/models",
75+
ReadOnly: true,
76+
},
77+
},
78+
},
79+
},
80+
},
81+
initialAnnotations: map[string]string{"existing-key": "existing-val"},
82+
expectedAnnotationKey: models.ExtensionKeyClaimWithCSIMount_MountConfig,
83+
expectedAnnotationVal: `[{"pvName":"pv-nas-001","mountPath":"/data"},{"pvName":"pv-oss-002","mountPath":"/models","readOnly":true}]`,
84+
shouldSet: true,
85+
},
86+
{
87+
name: "with metadata merging",
88+
request: models.NewSandboxRequest{
89+
Extensions: models.NewSandboxRequestExtension{
90+
CSIMount: models.CSIMountExtension{
91+
MountConfigs: []models.CSIMountConfig{
92+
{
93+
PvName: "pv-test",
94+
MountPath: "/workspace",
95+
},
96+
},
97+
},
98+
},
99+
},
100+
initialAnnotations: map[string]string{
101+
"old-key": "old-val",
102+
},
103+
expectedAnnotationKey: models.ExtensionKeyClaimWithCSIMount_MountConfig,
104+
expectedAnnotationVal: `[{"pvName":"pv-test","mountPath":"/workspace"}]`,
105+
shouldSet: true,
106+
},
107+
}
108+
109+
for _, tt := range tests {
110+
t.Run(tt.name, func(t *testing.T) {
111+
// Create mock sandbox
112+
mockSbx := &sandboxcr.Sandbox{
113+
Sandbox: &agentsv1alpha1.Sandbox{
114+
ObjectMeta: metav1.ObjectMeta{
115+
Name: "test-sandbox",
116+
Namespace: "default",
117+
Annotations: tt.initialAnnotations,
118+
},
119+
},
120+
}
121+
122+
// Create controller instance
123+
ctrl := &Controller{}
124+
125+
// Call the function
126+
ctx := context.Background()
127+
ctrl.csiMountOptionsConfigRecord(ctx, mockSbx, tt.request)
128+
129+
// Verify results
130+
annotations := mockSbx.GetAnnotations()
131+
132+
if !tt.shouldSet {
133+
// Should not set any annotation when mount configs are empty
134+
if len(annotations) != len(tt.initialAnnotations) {
135+
t.Errorf("expected no annotations to be added, got %d", len(annotations))
136+
}
137+
return
138+
}
139+
140+
// Check if expected annotation is set
141+
val, exists := annotations[tt.expectedAnnotationKey]
142+
if !exists {
143+
t.Errorf("expected annotation %q to exist", tt.expectedAnnotationKey)
144+
return
145+
}
146+
147+
// Verify the annotation value (parse JSON for comparison to avoid ordering issues)
148+
var expectedConfigs, actualConfigs []models.CSIMountConfig
149+
if err := json.Unmarshal([]byte(tt.expectedAnnotationVal), &expectedConfigs); err != nil {
150+
t.Fatalf("failed to unmarshal expected value: %v", err)
151+
}
152+
if err := json.Unmarshal([]byte(val), &actualConfigs); err != nil {
153+
t.Fatalf("failed to unmarshal actual value: %v", err)
154+
}
155+
156+
if !reflect.DeepEqual(expectedConfigs, actualConfigs) {
157+
t.Errorf("csi mount config mismatch:\nexpected: %#v\ngot: %#v", expectedConfigs, actualConfigs)
158+
}
159+
160+
if !reflect.DeepEqual(expectedConfigs, actualConfigs) {
161+
t.Errorf("csi mount config mismatch:\nexpected: %#v\ngot: %#v", expectedConfigs, actualConfigs)
162+
}
163+
164+
// Verify existing annotations are preserved
165+
if tt.initialAnnotations != nil {
166+
for k, v := range tt.initialAnnotations {
167+
if annotations[k] != v {
168+
t.Errorf("expected existing annotation %q=%q, got %q", k, v, annotations[k])
169+
}
170+
}
171+
}
172+
})
173+
}
174+
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package models
22

33
type CSIMountConfig struct {
4-
MountID string `json:"mountID"` // mount id
5-
PvName string `json:"pvName"` // persistent volume name for mounting
6-
MountPath string `json:"mountPath"` // mount target in container to mount the persistent volume
7-
SubPath string `json:"subPath"` // sub path address in persistent volume
8-
ReadOnly bool `json:"readOnly"` // whether to mount the persistent volume as read-only
4+
MountID string `json:"mountID,omitempty"` // mount id
5+
PvName string `json:"pvName"` // persistent volume name for mounting
6+
MountPath string `json:"mountPath"` // mount target in container to mount the persistent volume
7+
SubPath string `json:"subPath,omitempty"` // sub path address in persistent volume
8+
ReadOnly bool `json:"readOnly,omitempty"` // whether to mount the persistent volume as read-only
99
}

0 commit comments

Comments
 (0)