Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pkg/mounter/oss/oss_fuse_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ const (

// Options contains options for target oss
type Options struct {
// DirectAssigned indicates the volume should be directly assigned to the pod.
// When DirectAssigned is True, it means the runtime is either rund or coco:
// - Controller server should skip the controller publish phase
// - Node server should check the skipAttach field to determine if it's rund (skipAttach=true) or coco (skipAttach=false)
// Otherwise, the runtime is runc
DirectAssigned bool
CNFSName string

Expand Down
18 changes: 12 additions & 6 deletions pkg/oss/controllerserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol

func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) {
klog.Infof("ControllerUnpublishVolume: volume %s on node %s", req.VolumeId, req.NodeId)
// Note: For scenarios with mixed deployment of rund/coco and runc,
// since we cannot determine by req parameters,
// all need to attempt pod deletion for compatibility

// To maintain the compatibility, all kinds of fuseType Pod share the same globalmount path as ossfs.
if err := cs.fusePodManagers[unifiedFsType].Delete(&mounter.FusePodContext{
Context: ctx,
Expand Down Expand Up @@ -123,6 +127,14 @@ func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *cs
if err := setCNFSOptions(ctx, cs.cnfsGetter, opts); err != nil {
return nil, err
}

// Note: Skip controller publish for direct=true.
// The actual mounting of these volumes will be handled by rund/coco.
if opts.DirectAssigned {
klog.Infof("ControllerPublishVolume: skip DirectVolume: %s", req.VolumeId)
return &csi.ControllerPublishVolumeResponse{}, nil
}

// options validation
if err := checkOssOptions(opts, cs.fusePodManagers[opts.FuseType]); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
Expand All @@ -134,12 +146,6 @@ func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *cs
}
// make pod template config
ptCfg := makePodTemplateConfig(opts)
// Skip controller publish for PVs with attribute direct=true.
// The actual mounting of these volumes will be handled by rund.
if opts.DirectAssigned {
klog.Infof("ControllerPublishVolume: skip DirectVolume: %s", req.VolumeId)
return &csi.ControllerPublishVolumeResponse{}, nil
}
// make mount options
controllerPublishPath := mounter.GetAttachPath(req.VolumeId)

Expand Down
2 changes: 1 addition & 1 deletion pkg/oss/csi_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func NewCSIAgent(m metadata.MetadataProvider, socketPath string) *CSIAgent {
metadata: m,
locks: utils.NewVolumeLocks(),
rawMounter: mountutils.NewWithoutSystemd(""),
skipAttach: true,
skipAttach: true, // label for csi-agent environment
fusePodManagers: fusePodManagers,
ossfsPaths: map[string]string{
OssFsType: ossfsExecPath,
Expand Down
23 changes: 12 additions & 11 deletions pkg/oss/nodeserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
return &csi.NodePublishVolumeResponse{}, nil
}

// rund 3.0 protocol
// Note: In rund 3.0 node server (non csi-agent), skip all parameter validation and exit directly
if features.FunctionalMutableFeatureGate.Enabled(features.RundCSIProtocol3) {
if ns.clientset != nil && utils.GetPodRunTime(ctx, req, ns.clientset) == utils.RundRunTimeTag {
klog.Infof("NodePublishVolume: skip as %s enabled", features.RundCSIProtocol3)
return &csi.NodePublishVolumeResponse{}, nil
}
}

// parse options
// ensure fuseType is not empty
opts := parseOptions(req.GetVolumeContext(), req.GetSecrets(), []*csi.VolumeCapability{req.GetVolumeCapability()}, req.GetReadonly(), "", true, ns.metadata)
Expand All @@ -125,9 +134,9 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
return nil, status.Error(codes.InvalidArgument, err.Error())
}

// PVs with attribute direct=true will by mounted in rund guest os.
// csi need only to prepare the direct-volume mountinfo in /run/kata-containers/shared/direct-volumes directory.
if opts.DirectAssigned {
// Note: In non-csi-agent environment (!ns.skipAttach),
// if DirectAssigned is True, it's a confidential container scenario (coco)
if opts.DirectAssigned && !ns.skipAttach {
return ns.publishDirectVolume(ctx, req, opts)
}

Expand All @@ -140,14 +149,6 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
}
mountOptions = ns.fusePodManagers[opts.FuseType].AddDefaultMountOptions(mountOptions)

// rund 3.0 protocol
if features.FunctionalMutableFeatureGate.Enabled(features.RundCSIProtocol3) {
if ns.clientset != nil && utils.GetPodRunTime(ctx, req, ns.clientset) == utils.RundRunTimeTag {
klog.Infof("NodePublishVolume: skip as %s enabled", features.RundCSIProtocol3)
return &csi.NodePublishVolumeResponse{}, nil
}
}

// get mount proxy socket path
socketPath := req.PublishContext[mountProxySocket]
if socketPath == "" && !ns.skipAttach {
Expand Down
35 changes: 31 additions & 4 deletions pkg/oss/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,11 @@ func parseOptions(volOptions, secrets map[string]string, volCaps []*csi.VolumeCa
}

opts := &oss.Options{
UseSharedPath: true,
Path: "/",
AkID: strings.TrimSpace(secrets[AkID]),
AkSecret: strings.TrimSpace(secrets[AkSecret]),
UseSharedPath: true,
Path: "/",
AkID: strings.TrimSpace(secrets[AkID]),
AkSecret: strings.TrimSpace(secrets[AkSecret]),
DirectAssigned: getDirectAssignedValue(),
}

var volumeAsSubpath bool
Expand Down Expand Up @@ -444,3 +445,29 @@ func makeMountOptions(opt *oss.Options, fpm *oss.OSSFusePodManager, m metadata.M
mountOptions = append(mountOptions, ops...)
return
}

// getDirectAssignedValue returns the default value for DirectAssigned option based on the runtime class.
// The function reads DEFAULT_RUNTIME_CLASS environment variable and determines the appropriate default value:
// - For "rund" runtime, returns true (direct assignment enabled by default)
// - For "runc" runtime or empty value, returns false (direct assignment disabled by default)
// - For any other value, logs a warning and returns false
func getDirectAssignedValue() bool {
// Get runtime class from environment variable
runtimeClass := os.Getenv("DEFAULT_RUNTIME_CLASS")

// Validate runtime class, only allow "runc", "rund" or empty (treated as "runc")
// Note: Do not consider the confidential container scenario (coco),
// because in this scenario, PV.attributes must explicitly specify whether directAssigned
switch strings.ToLower(runtimeClass) {
case strings.ToLower(utils.RundRunTimeTag):
// For rund, default value is true
return true
case strings.ToLower(utils.RuncRunTimeTag), "":
// For runc or empty (default to runc), default value is false
return false
default:
// Invalid runtime class, see as rund and return error
klog.Warningf("invalid DEFAULT_RUNTIME_CLASS value: %q, only %s and %s are allowed", runtimeClass, utils.RuncRunTimeTag, utils.RundRunTimeTag)
return false
}
}
121 changes: 121 additions & 0 deletions pkg/oss/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -740,3 +740,124 @@ func TestMakePodTemplateConfig(t *testing.T) {

assert.Equal(t, &mounter.PodTemplateConfig{}, makePodTemplateConfig(&oss.Options{}))
}

func TestGetDirectAssignedValue(t *testing.T) {
tests := []struct {
name string
runtimeClass string
expected bool
}{
{
name: "Test with rund runtime class",
runtimeClass: "rund",
expected: true,
},
{
name: "Test with runc runtime class",
runtimeClass: "runc",
expected: false,
},
{
name: "Test with empty runtime class",
runtimeClass: "",
expected: false,
},
{
name: "Test with invalid runtime class",
runtimeClass: "invalid",
expected: false,
},
{
name: "Test with Rund runtime class (case insensitive)",
runtimeClass: "Rund",
expected: true,
},
{
name: "Test with runC runtime class (case insensitive)",
runtimeClass: "runC",
expected: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Setenv("DEFAULT_RUNTIME_CLASS", tt.runtimeClass)
result := getDirectAssignedValue()
assert.Equal(t, tt.expected, result)
})
}
}

func TestParseOptions_DirectAssigned(t *testing.T) {
tests := []struct {
name string
default_runtime_class string
volOptions map[string]string
wantDirectAssigned bool
}{
{
name: "empty runtime, empty volOptions",
default_runtime_class: "",
volOptions: map[string]string{},
wantDirectAssigned: false,
},
{
name: "invalid runtime, empty volOptions",
default_runtime_class: "invalid",
volOptions: map[string]string{},
wantDirectAssigned: false,
},
{
name: "default rund, empty volOptions",
default_runtime_class: "rund",
volOptions: map[string]string{},
wantDirectAssigned: true,
},
{
name: "default runc, empty volOptions",
default_runtime_class: "runc",
volOptions: map[string]string{},
wantDirectAssigned: false,
},
{
name: "empty runtime, vol true",
default_runtime_class: "",
volOptions: map[string]string{
optDirectAssigned: "true",
},
wantDirectAssigned: true,
},
{
name: "invalid runtime, vol false",
default_runtime_class: "invalid",
volOptions: map[string]string{
optDirectAssigned: "false",
},
wantDirectAssigned: false,
},
{
name: "default rund, invalid volOptions",
default_runtime_class: "rund",
volOptions: map[string]string{
optDirectAssigned: "invalid",
},
wantDirectAssigned: true,
},
{
name: "default runc, vol true",
default_runtime_class: "runc",
volOptions: map[string]string{
optDirectAssigned: "true",
},
wantDirectAssigned: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
fakeMeta := metadata.NewMetadata()
t.Setenv("DEFAULT_RUNTIME_CLASS", tt.default_runtime_class)
opt := parseOptions(tt.volOptions, nil, nil, false, "", false, fakeMeta)
assert.Equal(t, tt.wantDirectAssigned, opt.DirectAssigned)
})
}
}