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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions driver/diskutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ type DiskUtils interface {
// GetStatfs return the statfs struct for the given path
GetStatfs(path string) (*unix.Statfs_t, error)

// Resize resizes the given volumes
Resize(targetPath string, devicePath string) error
// Resize resizes the given volumes, it will try to resize the LUKS device first if the passphrase is provided
Resize(targetPath string, devicePath, passphrase string) error

// IsEncrypted returns true if the device with the given path is encrypted with LUKS
IsEncrypted(devicePath string) (bool, error)

// EncryptAndOpenDevice encrypts the volume with the given ID with the given passphrase and open it
// If the device is already encrypted (LUKS header present), it will only open the device
Expand Down Expand Up @@ -162,7 +165,9 @@ func (d *diskUtils) GetMappedDevicePath(volumeID string) (string, error) {

// first line should look like
// /dev/mapper/<name> is active.
if !strings.HasSuffix(statusLines[0], "is active.") {
// or
// /dev/mapper/<name> is active and is in use.
if !strings.HasSuffix(statusLines[0], "is active.") && !strings.HasSuffix(statusLines[0], "is active and is in use.") {
// when a device is not active, an error exit code is thrown
// something went wrong if we reach here
return "", fmt.Errorf("luksStatus returned ok, but device %s is not active", diskLuksMapperPrefix+volumeID)
Expand Down Expand Up @@ -431,12 +436,25 @@ func (d *diskUtils) GetStatfs(path string) (*unix.Statfs_t, error) {
return fs, err
}

func (d *diskUtils) Resize(targetPath string, devicePath string) error {
func (d *diskUtils) IsEncrypted(devicePath string) (bool, error) {
return luksIsLuks(devicePath)
}

func (d *diskUtils) Resize(targetPath string, devicePath, passphrase string) error {
mountInfo, err := d.GetMountInfo(targetPath)
if err != nil {
return err
}

if passphrase != "" {
klog.V(4).Infof("resizing LUKS device %s", devicePath)
if err := luksResize(devicePath, passphrase); err != nil {
return err
}
}

klog.V(4).Infof("resizing filesystem %s on %s", mountInfo.fsType, devicePath)

switch mountInfo.fsType {
case "ext3", "ext4":
resize2fsPath, err := exec.LookPath("resize2fs")
Expand Down
22 changes: 22 additions & 0 deletions driver/luks_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package driver
import (
"bytes"
"errors"
"fmt"
"os/exec"
"strings"
)
Expand Down Expand Up @@ -56,6 +57,27 @@ func luksClose(mapperFile string) error {
return luksCloseCmd.Run()
}

func luksResize(mapperFile, passphrase string) error {
args := []string{
"resize", // resize
mapperFile, // mapper file to resize
"--key-file", "/dev/stdin", // read the passphrase from stdin
}

luksResizeCmd := exec.Command(cryptsetupCmd, args...)

luksResizeCmd.Stdin = strings.NewReader(passphrase)
o := &bytes.Buffer{}
e := &bytes.Buffer{}
luksResizeCmd.Stdout = o
luksResizeCmd.Stderr = e

if err := luksResizeCmd.Run(); err != nil {
return fmt.Errorf("luks resize failed: %v, stdout: %s, stderr: %s", err, o.String(), e.String())
}
return nil
}

func luksStatus(mapperFile string) ([]byte, error) {
args := []string{
"status", // status
Expand Down
22 changes: 20 additions & 2 deletions driver/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (
"strings"

"github.com/container-storage-interface/spec/lib/go/csi"
"github.com/scaleway/scaleway-csi/scaleway"
"github.com/scaleway/scaleway-sdk-go/scw"
"golang.org/x/sys/unix"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/klog/v2"

"github.com/scaleway/scaleway-csi/scaleway"
)

const (
Expand Down Expand Up @@ -573,8 +574,25 @@ func (d *nodeService) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandV
return &csi.NodeExpandVolumeResponse{}, nil
}

err = d.diskUtils.Resize(volumePath, devicePath)
klog.V(4).Infof("resizing volume %s mounted on %s", volumeID, volumePath)
encrypted, err := d.diskUtils.IsEncrypted(devicePath)
if err != nil {
return nil, status.Errorf(codes.Internal, "error checking if volume %s is encrypted: %s", volumeID, err.Error())
}

passphrase := req.GetSecrets()[encryptionPassphraseKey]
if encrypted {
devicePath, err = d.diskUtils.GetMappedDevicePath(volumeID)
if err != nil {
return nil, status.Errorf(codes.Internal, "error retrieving mapped device path for volume with ID %s: %s", volumeID, err.Error())
}
klog.V(4).Infof("mapped device path for volume %s is %s", volumeID, devicePath)
if passphrase == "" {
return nil, status.Errorf(codes.InvalidArgument, "device %s is LUKS encrypted, but no passphrase was provided", devicePath)
}
}

if err = d.diskUtils.Resize(volumePath, devicePath, passphrase); err != nil {
return nil, status.Errorf(codes.Internal, "failed to resize volume %s mounted on %s: %v", volumeID, volumePath, err)
}

Expand Down
9 changes: 7 additions & 2 deletions driver/sanity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ import (

"github.com/google/uuid"
"github.com/kubernetes-csi/csi-test/v5/pkg/sanity"
"github.com/scaleway/scaleway-csi/scaleway"
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
"golang.org/x/sys/unix"
kmount "k8s.io/mount-utils"
kexec "k8s.io/utils/exec"
utilsio "k8s.io/utils/io"

"github.com/scaleway/scaleway-csi/scaleway"
)

type fakeHelper struct {
Expand Down Expand Up @@ -526,10 +527,14 @@ func (s *fakeHelper) GetStatfs(path string) (*unix.Statfs_t, error) {
}, nil
}

func (s *fakeHelper) Resize(targetPath string, devicePath string) error {
func (s *fakeHelper) Resize(targetPath string, devicePath, passphrase string) error {
return nil
}

func (s *fakeHelper) IsEncrypted(devicePath string) (bool, error) {
return false, nil
}

func (s *fakeHelper) EncryptAndOpenDevice(volumeID string, passphrase string) (string, error) {
return "", nil
}
Expand Down
6 changes: 5 additions & 1 deletion examples/kubernetes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ data:

and the following StorageClass:
```yaml
allowVolumeExpansion: false # not yet supported
# Volume expansion is supported with CSINodeExpandSecret feature gate since v1.25.0 or by default since v1.27.0
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
Expand All @@ -257,6 +258,9 @@ parameters:
encrypted: "true"
csi.storage.k8s.io/node-stage-secret-name: "enc-secret"
csi.storage.k8s.io/node-stage-secret-namespace: "default"
# Required for volume expansion
csi.storage.k8s.io/node-expand-secret-name: "enc-secret"
csi.storage.k8s.io/node-expand-secret-namespace: "default"
```

all the PVC created with the StorageClass `scw-bssd-enc` will be encrypted at rest with the passphrase `myawesomepassphrase`.
Expand Down