Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add volume resizing support for windows #1207

Merged
Merged
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
2 changes: 1 addition & 1 deletion examples/kubernetes/resizing/manifests/pod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ spec:
- name: app
image: centos
command: ["/bin/sh"]
args: ["tail -f /dev/null"]
args: ["-c", "while true; do echo $(date -u) >> /data/out.txt; sleep 5; done"]
volumeMounts:
- name: persistent-storage
mountPath: /data
Expand Down
6 changes: 6 additions & 0 deletions pkg/driver/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,9 @@ const (
const (
DefaultCSIEndpoint = "unix://tmp/csi.sock"
)

// constants for disk block size
const (
//DefaultBlockSize represents the default block size (4KB)
DefaultBlockSize = 4096
)
59 changes: 56 additions & 3 deletions pkg/driver/mock_mount.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/driver/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ type Mounter interface {
NeedResize(devicePath string, deviceMountPath string) (bool, error)
Unpublish(path string) error
Unstage(path string) error
NewResizeFs() (Resizefs, error)
}

type Resizefs interface {
Resize(devicePath, deviceMountPath string) (bool, error)
}

// NodeMounter implements Mounter.
Expand Down
4 changes: 4 additions & 0 deletions pkg/driver/mount_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,7 @@ func (m *NodeMounter) Unpublish(path string) error {
func (m *NodeMounter) Unstage(path string) error {
return m.Unmount(path)
}

func (m *NodeMounter) NewResizeFs() (Resizefs, error) {
return mountutils.NewResizeFs(m.Exec), nil
}
35 changes: 30 additions & 5 deletions pkg/driver/mount_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ package driver

import (
"fmt"
"regexp"

"github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/mounter"
"github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/resizefs"
mountutils "k8s.io/mount-utils"
"regexp"
)

func (m NodeMounter) FormatAndMount(source string, target string, fstype string, options []string) error {
Expand Down Expand Up @@ -99,9 +99,26 @@ func (m *NodeMounter) PathExists(path string) (bool, error) {
return proxyMounter.ExistsPath(path)
}

func (m *NodeMounter) NeedResize(devicePath string, deviceMountPath string) (bool, error) {
// TODO this is called at NodeStage to ensure file system is the correct size
// Implement it to respect spec v1.4.0 https://github.com/container-storage-interface/spec/pull/452
// NeedResize called at NodeStage to ensure file system is the correct size
func (m *NodeMounter) NeedResize(devicePath, deviceMountPath string) (bool, error) {
proxyMounter, ok := m.SafeFormatAndMount.Interface.(*mounter.CSIProxyMounter)
if !ok {
return false, fmt.Errorf("failed to cast mounter to csi proxy mounter")
}

deviceSize, err := proxyMounter.GetDeviceSize(devicePath)
if err != nil {
return false, err
}

fsSize, err := proxyMounter.GetVolumeSizeInBytes(deviceMountPath)
if err != nil {
return false, err
}
// Tolerate one block difference (4096 bytes)
if deviceSize <= DefaultBlockSize+fsSize {
return true, nil
}
return false, nil
}

Expand Down Expand Up @@ -140,3 +157,11 @@ func (m *NodeMounter) Unstage(target string) error {
}
return nil
}

func (m *NodeMounter) NewResizeFs() (Resizefs, error) {
proxyMounter, ok := m.SafeFormatAndMount.Interface.(*mounter.CSIProxyMounter)
if !ok {
return nil, fmt.Errorf("failed to cast mounter to csi proxy mounter")
}
return resizefs.NewResizeFs(proxyMounter), nil
}
12 changes: 9 additions & 3 deletions pkg/driver/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"google.golang.org/grpc/status"
"k8s.io/klog"
"k8s.io/kubernetes/pkg/volume"
mountutils "k8s.io/mount-utils"
)

const (
Expand Down Expand Up @@ -217,8 +216,12 @@ func (d *nodeService) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not determine if volume %q (%q) need to be resized: %v", req.GetVolumeId(), source, err)
}

if needResize {
r := mountutils.NewResizeFs(d.mounter.(*NodeMounter).Exec)
r, err := d.mounter.NewResizeFs()
if err != nil {
return nil, status.Errorf(codes.Internal, "Error attempting to create new ResizeFs: %v", err)
}
klog.V(2).Infof("Volume %s needs resizing", source)
if _, err := r.Resize(source, target); err != nil {
return nil, status.Errorf(codes.Internal, "Could not resize volume %q (%q): %v", volumeID, source, err)
Expand Down Expand Up @@ -329,7 +332,10 @@ func (d *nodeService) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandV
return nil, status.Errorf(codes.Internal, "failed to find device path for device name %s for mount %s: %v", deviceName, req.GetVolumePath(), err)
}

r := mountutils.NewResizeFs(d.mounter.(*NodeMounter).Exec)
r, err := d.mounter.NewResizeFs()
if err != nil {
return nil, status.Errorf(codes.Internal, "Error attempting to create new ResizeFs: %v", err)
}

// TODO: lock per volume ID to have some idempotency
if _, err := r.Resize(devicePath, volumePath); err != nil {
Expand Down
18 changes: 14 additions & 4 deletions pkg/driver/node_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ package driver

import (
"context"
"errors"
"fmt"
"strconv"
"strings"
Expand Down Expand Up @@ -89,11 +88,22 @@ func (d *nodeService) preparePublishTarget(target string) error {
return nil
}

// IsBlock checks if the given path is a block device
// IsBlockDevice checks if the given path is a block device
func (d *nodeService) IsBlockDevice(fullPath string) (bool, error) {
return false, errors.New("unsupported")
return false, nil
}

// getBlockSizeBytes gets the size of the disk in bytes
func (d *nodeService) getBlockSizeBytes(devicePath string) (int64, error) {
return 0, errors.New("unsupported")
proxyMounter, ok := (d.mounter.(*NodeMounter)).SafeFormatAndMount.Interface.(*mounter.CSIProxyMounter)
if !ok {
return -1, fmt.Errorf("failed to cast mounter to csi proxy mounter")
}

sizeInBytes, err := proxyMounter.GetDeviceSize(devicePath)
if err != nil {
return -1, err
}

return sizeInBytes, nil
}
4 changes: 4 additions & 0 deletions pkg/driver/sanity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,10 @@ func (f *fakeMounter) Unpublish(target string) error {
return nil
}

func (f *fakeMounter) NewResizeFs() (Resizefs, error) {
return nil, nil
}

func (f *fakeMounter) List() ([]mount.MountPoint, error) {
return []mount.MountPoint{}, nil
}
Expand Down
63 changes: 53 additions & 10 deletions pkg/mounter/safe_mounter_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,23 +351,66 @@ func (mounter *CSIProxyMounter) FormatAndMount(source string, target string, fst
return nil
}

// ResizeVolume resizes the volume to the maximum available size.
func (mounter *CSIProxyMounter) ResizeVolume(devicePath string) error {
req := &volume.ResizeVolumeRequest{VolumeId: devicePath, SizeBytes: 0}
// ResizeVolume resizes the volume at given mount path
func (mounter *CSIProxyMounter) ResizeVolume(deviceMountPath string) (bool, error) {
// Find the volume id
getVolumeIdRequest := &volume.GetVolumeIDFromTargetPathRequest{
TargetPath: normalizeWindowsPath(deviceMountPath),
}
volumeIdResponse, err := mounter.VolumeClient.GetVolumeIDFromTargetPath(context.Background(), getVolumeIdRequest)
if err != nil {
return false, err
}
volumeId := volumeIdResponse.GetVolumeId()

_, err := mounter.VolumeClient.ResizeVolume(context.Background(), req)
// Resize volume
resizeVolumeRequest := &volume.ResizeVolumeRequest{
VolumeId: volumeId,
}
_, err = mounter.VolumeClient.ResizeVolume(context.Background(), resizeVolumeRequest)
if err != nil {
return err
return false, err
}

return nil
return true, nil
}

// GetVolumeSizeInBytes returns the size of the volume in bytes
func (mounter *CSIProxyMounter) GetVolumeSizeInBytes(deviceMountPath string) (int64, error) {
// Find the volume id
getVolumeIdRequest := &volume.GetVolumeIDFromTargetPathRequest{
TargetPath: normalizeWindowsPath(deviceMountPath),
}
volumeIdResponse, err := mounter.VolumeClient.GetVolumeIDFromTargetPath(context.Background(), getVolumeIdRequest)
if err != nil {
return -1, err
}
volumeId := volumeIdResponse.GetVolumeId()

// Get size of the volume
getVolumeStatsRequest := &volume.GetVolumeStatsRequest{
VolumeId: volumeId,
}
resp, err := mounter.VolumeClient.GetVolumeStats(context.Background(), getVolumeStatsRequest)
if err != nil {
return -1, err
}

return resp.TotalBytes, nil
}

// GetVolumeSizeInBytes returns the size of the volume in bytes.
func (mounter *CSIProxyMounter) GetVolumeSizeInBytes(devicePath string) (int64, error) {
req := &volume.GetVolumeStatsRequest{VolumeId: devicePath}
// GetDeviceSize returns the size of the disk in bytes
func (mounter *CSIProxyMounter) GetDeviceSize(devicePath string) (int64, error) {
diskNumber, err := strconv.Atoi(devicePath)
if err != nil {
return -1, err
}

resp, err := mounter.VolumeClient.GetVolumeStats(context.Background(), req)
//Get size of the disk
getDiskStatsRequest := &disk.GetDiskStatsRequest{
DiskNumber: uint32(diskNumber),
}
resp, err := mounter.DiskClient.GetDiskStats(context.Background(), getDiskStatsRequest)
if err != nil {
return -1, err
}
Expand Down
25 changes: 25 additions & 0 deletions pkg/resizefs/resizefs_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//go:build windows
// +build windows

package resizefs

import (
"github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/mounter"
"k8s.io/klog"
)

// resizeFs provides support for resizing file systems
type resizeFs struct {
proxy *mounter.CSIProxyMounter
}

// NewResizeFs returns an instance of resizeFs
func NewResizeFs(proxy *mounter.CSIProxyMounter) *resizeFs {
return &resizeFs{proxy: proxy}
}

// Resize performs resize of file system
func (r *resizeFs) Resize(_, deviceMountPath string) (bool, error) {
klog.V(3).Infof("Resize - Expanding mounted volume %s", deviceMountPath)
return r.proxy.ResizeVolume(deviceMountPath)
}