Implement CSI volume expansion
Test / buildenv (push) Successful in 7s
Details
Test / build (push) Successful in 3m12s
Details
Test / test_cas (push) Successful in 8s
Details
Test / make_test (push) Successful in 40s
Details
Test / test_change_pg_size (push) Successful in 7s
Details
Test / test_create_nomaxid (push) Successful in 8s
Details
Test / test_change_pg_count_ec (push) Successful in 42s
Details
Test / test_change_pg_count (push) Successful in 44s
Details
Test / test_etcd_fail (push) Successful in 1m9s
Details
Test / test_interrupted_rebalance_imm (push) Successful in 1m27s
Details
Test / test_add_osd (push) Successful in 3m14s
Details
Test / test_failure_domain (push) Successful in 10s
Details
Test / test_interrupted_rebalance (push) Successful in 2m30s
Details
Test / test_interrupted_rebalance_ec_imm (push) Successful in 1m31s
Details
Test / test_interrupted_rebalance_ec (push) Successful in 2m9s
Details
Test / test_snapshot (push) Successful in 34s
Details
Test / test_snapshot_ec (push) Successful in 35s
Details
Test / test_minsize_1 (push) Successful in 16s
Details
Test / test_rm (push) Successful in 15s
Details
Test / test_snapshot_down (push) Successful in 22s
Details
Test / test_move_reappear (push) Failing after 50s
Details
Test / test_snapshot_down_ec (push) Successful in 23s
Details
Test / test_splitbrain (push) Successful in 19s
Details
Test / test_snapshot_chain (push) Successful in 2m24s
Details
Test / test_snapshot_chain_ec (push) Failing after 3m6s
Details
Test / test_rebalance_verify_imm (push) Successful in 3m15s
Details
Test / test_write (push) Successful in 41s
Details
Test / test_rebalance_verify (push) Successful in 4m13s
Details
Test / test_write_no_same (push) Successful in 13s
Details
Test / test_write_xor (push) Successful in 50s
Details
Test / test_rebalance_verify_ec_imm (push) Successful in 4m28s
Details
Test / test_rebalance_verify_ec (push) Successful in 5m30s
Details
Test / test_heal_pg_size_2 (push) Successful in 4m5s
Details
Test / test_heal_ec (push) Successful in 4m57s
Details
Test / test_heal_csum_32k_dmj (push) Successful in 6m13s
Details
Test / test_heal_csum_32k_dj (push) Successful in 6m10s
Details
Test / test_heal_csum_32k (push) Successful in 6m40s
Details
Test / test_heal_csum_4k_dmj (push) Successful in 6m24s
Details
Test / test_scrub (push) Successful in 1m7s
Details
Test / test_scrub_xor (push) Successful in 47s
Details
Test / test_scrub_zero_osd_2 (push) Successful in 53s
Details
Test / test_scrub_pg_size_6_pg_minsize_4_osd_count_6_ec (push) Successful in 1m25s
Details
Test / test_scrub_pg_size_3 (push) Successful in 1m59s
Details
Test / test_heal_csum_4k_dj (push) Successful in 6m10s
Details
Test / test_heal_csum_4k (push) Successful in 6m2s
Details
Test / test_scrub_ec (push) Successful in 40s
Details
Test / buildenv (push) Successful in 7s
Details
Test / build (push) Successful in 3m12s
Details
Test / test_cas (push) Successful in 8s
Details
Test / make_test (push) Successful in 40s
Details
Test / test_change_pg_size (push) Successful in 7s
Details
Test / test_create_nomaxid (push) Successful in 8s
Details
Test / test_change_pg_count_ec (push) Successful in 42s
Details
Test / test_change_pg_count (push) Successful in 44s
Details
Test / test_etcd_fail (push) Successful in 1m9s
Details
Test / test_interrupted_rebalance_imm (push) Successful in 1m27s
Details
Test / test_add_osd (push) Successful in 3m14s
Details
Test / test_failure_domain (push) Successful in 10s
Details
Test / test_interrupted_rebalance (push) Successful in 2m30s
Details
Test / test_interrupted_rebalance_ec_imm (push) Successful in 1m31s
Details
Test / test_interrupted_rebalance_ec (push) Successful in 2m9s
Details
Test / test_snapshot (push) Successful in 34s
Details
Test / test_snapshot_ec (push) Successful in 35s
Details
Test / test_minsize_1 (push) Successful in 16s
Details
Test / test_rm (push) Successful in 15s
Details
Test / test_snapshot_down (push) Successful in 22s
Details
Test / test_move_reappear (push) Failing after 50s
Details
Test / test_snapshot_down_ec (push) Successful in 23s
Details
Test / test_splitbrain (push) Successful in 19s
Details
Test / test_snapshot_chain (push) Successful in 2m24s
Details
Test / test_snapshot_chain_ec (push) Failing after 3m6s
Details
Test / test_rebalance_verify_imm (push) Successful in 3m15s
Details
Test / test_write (push) Successful in 41s
Details
Test / test_rebalance_verify (push) Successful in 4m13s
Details
Test / test_write_no_same (push) Successful in 13s
Details
Test / test_write_xor (push) Successful in 50s
Details
Test / test_rebalance_verify_ec_imm (push) Successful in 4m28s
Details
Test / test_rebalance_verify_ec (push) Successful in 5m30s
Details
Test / test_heal_pg_size_2 (push) Successful in 4m5s
Details
Test / test_heal_ec (push) Successful in 4m57s
Details
Test / test_heal_csum_32k_dmj (push) Successful in 6m13s
Details
Test / test_heal_csum_32k_dj (push) Successful in 6m10s
Details
Test / test_heal_csum_32k (push) Successful in 6m40s
Details
Test / test_heal_csum_4k_dmj (push) Successful in 6m24s
Details
Test / test_scrub (push) Successful in 1m7s
Details
Test / test_scrub_xor (push) Successful in 47s
Details
Test / test_scrub_zero_osd_2 (push) Successful in 53s
Details
Test / test_scrub_pg_size_6_pg_minsize_4_osd_count_6_ec (push) Successful in 1m25s
Details
Test / test_scrub_pg_size_3 (push) Successful in 1m59s
Details
Test / test_heal_csum_4k_dj (push) Successful in 6m10s
Details
Test / test_heal_csum_4k (push) Successful in 6m2s
Details
Test / test_scrub_ec (push) Successful in 40s
Details
parent
37653abe4b
commit
64388788c1
|
@ -17,3 +17,4 @@ parameters:
|
||||||
# multiple etcdUrls may be specified, delimited by comma
|
# multiple etcdUrls may be specified, delimited by comma
|
||||||
#etcdUrl: "http://192.168.7.2:2379"
|
#etcdUrl: "http://192.168.7.2:2379"
|
||||||
#etcdPrefix: "/vitastor"
|
#etcdPrefix: "/vitastor"
|
||||||
|
allowVolumeExpansion: true
|
||||||
|
|
|
@ -361,6 +361,7 @@ func (cs *ControllerServer) ControllerGetCapabilities(ctx context.Context, req *
|
||||||
for _, capability := range []csi.ControllerServiceCapability_RPC_Type{
|
for _, capability := range []csi.ControllerServiceCapability_RPC_Type{
|
||||||
csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
|
csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
|
||||||
csi.ControllerServiceCapability_RPC_LIST_VOLUMES,
|
csi.ControllerServiceCapability_RPC_LIST_VOLUMES,
|
||||||
|
csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
|
||||||
csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
|
csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
|
||||||
csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS,
|
csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS,
|
||||||
// TODO: csi.ControllerServiceCapability_RPC_CLONE_VOLUME,
|
// TODO: csi.ControllerServiceCapability_RPC_CLONE_VOLUME,
|
||||||
|
@ -534,10 +535,53 @@ func (cs *ControllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnap
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ControllerExpandVolume resizes a volume
|
// ControllerExpandVolume increases the size of a volume
|
||||||
func (cs *ControllerServer) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error)
|
func (cs *ControllerServer) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error)
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Unimplemented, "")
|
klog.Infof("received controller expand volume request %+v", protosanitizer.StripSecrets(req))
|
||||||
|
if (req == nil)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "request cannot be empty")
|
||||||
|
}
|
||||||
|
if (req.VolumeId == "" || req.CapacityRange == nil || req.CapacityRange.RequiredBytes == 0)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "VolumeId, CapacityRange and RequiredBytes are required fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
volVars := make(map[string]string)
|
||||||
|
err := json.Unmarshal([]byte(req.VolumeId), &volVars)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
||||||
|
}
|
||||||
|
volName := volVars["name"]
|
||||||
|
ctxVars, _, _ := GetConnectionParams(volVars)
|
||||||
|
|
||||||
|
inodeCfg, err := invokeList(ctxVars, volName, true)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.CapacityRange.RequiredBytes > 0 && inodeCfg[0].Size < uint64(req.CapacityRange.RequiredBytes))
|
||||||
|
{
|
||||||
|
sz := ((req.CapacityRange.RequiredBytes+4095)/4096)*4096
|
||||||
|
_, err := invokeCLI(ctxVars, []string{ "modify", "--inc_size", "1", "--resize", fmt.Sprintf("%d", sz), volName })
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
inodeCfg, err = invokeList(ctxVars, volName, true)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &csi.ControllerExpandVolumeResponse{
|
||||||
|
CapacityBytes: int64(inodeCfg[0].Size),
|
||||||
|
NodeExpansionRequired: false,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ControllerGetVolume get volume info
|
// ControllerGetVolume get volume info
|
||||||
|
|
|
@ -49,6 +49,13 @@ func (is *IdentityServer) GetPluginCapabilities(ctx context.Context, req *csi.Ge
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Type: &csi.PluginCapability_VolumeExpansion_{
|
||||||
|
VolumeExpansion: &csi.PluginCapability_VolumeExpansion{
|
||||||
|
Type: csi.PluginCapability_VolumeExpansion_OFFLINE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,10 +70,10 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
||||||
isBlock := req.GetVolumeCapability().GetBlock() != nil
|
isBlock := req.GetVolumeCapability().GetBlock() != nil
|
||||||
|
|
||||||
// Check that it's not already mounted
|
// Check that it's not already mounted
|
||||||
_, error := mount.IsNotMountPoint(ns.mounter, targetPath)
|
_, err := mount.IsNotMountPoint(ns.mounter, targetPath)
|
||||||
if (error != nil)
|
if (err != nil)
|
||||||
{
|
{
|
||||||
if (os.IsNotExist(error))
|
if (os.IsNotExist(err))
|
||||||
{
|
{
|
||||||
if (isBlock)
|
if (isBlock)
|
||||||
{
|
{
|
||||||
|
@ -102,12 +102,12 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Internal, error.Error())
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxVars := make(map[string]string)
|
ctxVars := make(map[string]string)
|
||||||
err := json.Unmarshal([]byte(req.VolumeId), &ctxVars)
|
err = json.Unmarshal([]byte(req.VolumeId), &ctxVars)
|
||||||
if (err != nil)
|
if (err != nil)
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
||||||
|
@ -147,70 +147,74 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
||||||
}
|
}
|
||||||
devicePath := strings.TrimSpace(stdoutStr)
|
devicePath := strings.TrimSpace(stdoutStr)
|
||||||
|
|
||||||
// Check existing format
|
|
||||||
diskMounter := &mount.SafeFormatAndMount{Interface: ns.mounter, Exec: utilexec.New()}
|
diskMounter := &mount.SafeFormatAndMount{Interface: ns.mounter, Exec: utilexec.New()}
|
||||||
existingFormat, err := diskMounter.GetDiskFormat(devicePath)
|
|
||||||
if (err != nil)
|
|
||||||
{
|
|
||||||
klog.Errorf("failed to get disk format for path %s, error: %v", err)
|
|
||||||
// unmap NBD device
|
|
||||||
unmapOut, unmapErr := exec.Command("/usr/bin/vitastor-nbd", "unmap", devicePath).CombinedOutput()
|
|
||||||
if (unmapErr != nil)
|
|
||||||
{
|
|
||||||
klog.Errorf("failed to unmap NBD device %s: %s, error: %v", devicePath, unmapOut, unmapErr)
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format the device (ext4 or xfs)
|
|
||||||
fsType := req.GetVolumeCapability().GetMount().GetFsType()
|
|
||||||
opt := req.GetVolumeCapability().GetMount().GetMountFlags()
|
|
||||||
opt = append(opt, "_netdev")
|
|
||||||
if ((req.VolumeCapability.AccessMode.Mode == csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY ||
|
|
||||||
req.VolumeCapability.AccessMode.Mode == csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY) &&
|
|
||||||
!Contains(opt, "ro"))
|
|
||||||
{
|
|
||||||
opt = append(opt, "ro")
|
|
||||||
}
|
|
||||||
if (fsType == "xfs")
|
|
||||||
{
|
|
||||||
opt = append(opt, "nouuid")
|
|
||||||
}
|
|
||||||
readOnly := Contains(opt, "ro")
|
|
||||||
if (existingFormat == "" && !readOnly)
|
|
||||||
{
|
|
||||||
args := []string{}
|
|
||||||
switch fsType
|
|
||||||
{
|
|
||||||
case "ext4":
|
|
||||||
args = []string{"-m0", "-Enodiscard,lazy_itable_init=1,lazy_journal_init=1", devicePath}
|
|
||||||
case "xfs":
|
|
||||||
args = []string{"-K", devicePath}
|
|
||||||
}
|
|
||||||
if (len(args) > 0)
|
|
||||||
{
|
|
||||||
cmdOut, cmdErr := diskMounter.Exec.Command("mkfs."+fsType, args...).CombinedOutput()
|
|
||||||
if (cmdErr != nil)
|
|
||||||
{
|
|
||||||
klog.Errorf("failed to run mkfs error: %v, output: %v", cmdErr, string(cmdOut))
|
|
||||||
// unmap NBD device
|
|
||||||
unmapOut, unmapErr := exec.Command("/usr/bin/vitastor-nbd", "unmap", devicePath).CombinedOutput()
|
|
||||||
if (unmapErr != nil)
|
|
||||||
{
|
|
||||||
klog.Errorf("failed to unmap NBD device %s: %s, error: %v", devicePath, unmapOut, unmapErr)
|
|
||||||
}
|
|
||||||
return nil, status.Error(codes.Internal, cmdErr.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isBlock)
|
if (isBlock)
|
||||||
{
|
{
|
||||||
opt = append(opt, "bind")
|
err = diskMounter.Mount(devicePath, targetPath, "", []string{"bind"})
|
||||||
err = diskMounter.Mount(devicePath, targetPath, fsType, opt)
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Check existing format
|
||||||
|
existingFormat, err := diskMounter.GetDiskFormat(devicePath)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
klog.Errorf("failed to get disk format for path %s, error: %v", err)
|
||||||
|
goto unmap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the device (ext4 or xfs)
|
||||||
|
fsType := req.GetVolumeCapability().GetMount().GetFsType()
|
||||||
|
opt := req.GetVolumeCapability().GetMount().GetMountFlags()
|
||||||
|
opt = append(opt, "_netdev")
|
||||||
|
if ((req.VolumeCapability.AccessMode.Mode == csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY ||
|
||||||
|
req.VolumeCapability.AccessMode.Mode == csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY) &&
|
||||||
|
!Contains(opt, "ro"))
|
||||||
|
{
|
||||||
|
opt = append(opt, "ro")
|
||||||
|
}
|
||||||
|
if (fsType == "xfs")
|
||||||
|
{
|
||||||
|
opt = append(opt, "nouuid")
|
||||||
|
}
|
||||||
|
readOnly := Contains(opt, "ro")
|
||||||
|
if (existingFormat == "" && !readOnly)
|
||||||
|
{
|
||||||
|
var cmdOut []byte
|
||||||
|
switch fsType
|
||||||
|
{
|
||||||
|
case "ext4":
|
||||||
|
args := []string{"-m0", "-Enodiscard,lazy_itable_init=1,lazy_journal_init=1", devicePath}
|
||||||
|
cmdOut, err = diskMounter.Exec.Command("mkfs.ext4", args...).CombinedOutput()
|
||||||
|
case "xfs":
|
||||||
|
cmdOut, err = diskMounter.Exec.Command("mkfs.xfs", "-K", devicePath).CombinedOutput()
|
||||||
|
}
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
klog.Errorf("failed to run mkfs error: %v, output: %v", err, string(cmdOut))
|
||||||
|
goto unmap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = diskMounter.FormatAndMount(devicePath, targetPath, fsType, opt)
|
err = diskMounter.FormatAndMount(devicePath, targetPath, fsType, opt)
|
||||||
|
|
||||||
|
// Try to run online resize on mount.
|
||||||
|
// FIXME: Implement online resize. It requires online resize support in vitastor-nbd.
|
||||||
|
if (err == nil && existingFormat != "" && !readOnly)
|
||||||
|
{
|
||||||
|
var cmdOut []byte
|
||||||
|
switch (fsType)
|
||||||
|
{
|
||||||
|
case "ext4":
|
||||||
|
cmdOut, err = diskMounter.Exec.Command("resize2fs", devicePath).CombinedOutput()
|
||||||
|
case "xfs":
|
||||||
|
cmdOut, err = diskMounter.Exec.Command("xfs_growfs", devicePath).CombinedOutput()
|
||||||
|
}
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
klog.Errorf("failed to run resizefs error: %v, output: %v", err, string(cmdOut))
|
||||||
|
goto unmap
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (err != nil)
|
if (err != nil)
|
||||||
{
|
{
|
||||||
|
@ -218,15 +222,18 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
||||||
"failed to mount device path (%s) to path (%s) for volume (%s) error: %s",
|
"failed to mount device path (%s) to path (%s) for volume (%s) error: %s",
|
||||||
devicePath, targetPath, volName, err,
|
devicePath, targetPath, volName, err,
|
||||||
)
|
)
|
||||||
// unmap NBD device
|
goto unmap
|
||||||
unmapOut, unmapErr := exec.Command("/usr/bin/vitastor-nbd", "unmap", devicePath).CombinedOutput()
|
|
||||||
if (unmapErr != nil)
|
|
||||||
{
|
|
||||||
klog.Errorf("failed to unmap NBD device %s: %s, error: %v", devicePath, unmapOut, unmapErr)
|
|
||||||
}
|
|
||||||
return nil, status.Error(codes.Internal, err.Error())
|
|
||||||
}
|
}
|
||||||
return &csi.NodePublishVolumeResponse{}, nil
|
return &csi.NodePublishVolumeResponse{}, nil
|
||||||
|
|
||||||
|
unmap:
|
||||||
|
// unmap NBD device
|
||||||
|
unmapOut, unmapErr := exec.Command("/usr/bin/vitastor-nbd", "unmap", devicePath).CombinedOutput()
|
||||||
|
if (unmapErr != nil)
|
||||||
|
{
|
||||||
|
klog.Errorf("failed to unmap NBD device %s: %s, error: %v", devicePath, unmapOut, unmapErr)
|
||||||
|
}
|
||||||
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeUnpublishVolume unmounts the volume from the target path
|
// NodeUnpublishVolume unmounts the volume from the target path
|
||||||
|
|
Loading…
Reference in New Issue