Skip to content

Commit

Permalink
controller: support lvm type dm-thin
Browse files Browse the repository at this point in the history
    - also drop linear/mirror

Signed-off-by: Vicente Cheng <[email protected]>
  • Loading branch information
Vicente-Cheng committed Jul 23, 2024
1 parent 9bbf1f7 commit 6b2de1d
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 21 deletions.
10 changes: 9 additions & 1 deletion cmd/provisioner/createsnap.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ func createSnapCmd() *cli.Command {
Name: flagLVName,
Usage: "Required. the name of the volumegroup",
},
&cli.StringFlag{
Name: flagLVMType,
Usage: "Required. the type of the source lvm",
},
},
Action: func(c *cli.Context) error {
if err := createSnap(c); err != nil {
Expand Down Expand Up @@ -58,6 +62,10 @@ func createSnap(c *cli.Context) error {
if snapName == "" {
return fmt.Errorf("invalid empty flag %v", flagLVMType)
}
lvType := c.String(flagLVMType)
if lvType == "" {
return fmt.Errorf("invalid empty flag %v", flagLVMType)
}

klog.Infof("create snapshot: %s source size: %d source lv: %s/%s", snapName, lvSize, vgName, lvName)

Expand All @@ -69,7 +77,7 @@ func createSnap(c *cli.Context) error {
}
}

output, err := lvm.CreateSnapshot(snapName, lvName, vgName, lvSize)
output, err := lvm.CreateSnapshot(snapName, lvName, vgName, lvSize, lvType)
if err != nil {
return fmt.Errorf("unable to create Snapshot: %w output:%s", err, output)
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/lvm/controllerserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
}

lvmType := req.GetParameters()["type"]
if !(lvmType == "linear" || lvmType == "mirror" || lvmType == "striped") {
if !(lvmType == "striped" || lvmType == "dm-thin") {
return nil, status.Errorf(codes.Internal, "lvmType is incorrect: %s", lvmType)
}

Expand Down Expand Up @@ -430,6 +430,7 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
ns := volume.Spec.NodeAffinity.Required.NodeSelectorTerms
node := ns[0].MatchExpressions[0].Values[0]
vgName := volume.Spec.CSI.VolumeAttributes["vgName"]
lvType := volume.Spec.CSI.VolumeAttributes["type"]
//snapSize := strconv.FormatUint(volume.Spec.CSI.VolumeAttributes["RequiredBytes"], 10)
snapSizeStr := volume.Spec.CSI.VolumeAttributes["RequiredBytes"]
snapSize, err := strconv.ParseInt(snapSizeStr, 10, 64)
Expand All @@ -449,6 +450,7 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
nodeName: node,
snapSize: snapSize,
vgName: vgName,
lvType: lvType,
hostWritePath: cs.hostWritePath,
kubeClient: cs.kubeClient,
namespace: cs.namespace,
Expand Down Expand Up @@ -503,6 +505,7 @@ func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteS
snapshotName: snapName,
nodeName: node,
vgName: vgName,
lvType: "", // not used
hostWritePath: cs.hostWritePath,
kubeClient: cs.kubeClient,
namespace: cs.namespace,
Expand Down
93 changes: 74 additions & 19 deletions pkg/lvm/lvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,13 @@ type snapshotAction struct {
kubeClient kubernetes.Clientset
namespace string
vgName string
lvType string
hostWritePath string
}

const (
linearType = "linear"
stripedType = "striped"
mirrorType = "mirror"
dmThinType = "dm-thin"
actionTypeCreate = "create"
actionTypeDelete = "delete"
actionTypeClone = "clone"
Expand Down Expand Up @@ -279,7 +279,7 @@ func createSnapshotterPod(ctx context.Context, sa snapshotAction) (err error) {
args := []string{}
switch sa.action {
case actionTypeCreate:
args = append(args, "createsnap", "--snapname", sa.snapshotName, "--lvname", sa.srcVolName, "--vgname", sa.vgName, "--lvsize", fmt.Sprintf("%d", sa.snapSize))
args = append(args, "createsnap", "--snapname", sa.snapshotName, "--lvname", sa.srcVolName, "--vgname", sa.vgName, "--lvsize", fmt.Sprintf("%d", sa.snapSize), "--lvmtype", sa.lvType)
case actionTypeDelete:
args = append(args, "deletesnap", "--snapname", sa.snapshotName, "--vgname", sa.vgName)
default:
Expand Down Expand Up @@ -436,40 +436,51 @@ func CreateLVS(vg string, name string, size uint64, lvmType string) (string, err
return "", fmt.Errorf("size must be greater than 0")
}

if !(lvmType == "linear" || lvmType == "mirror" || lvmType == "striped") {
return "", fmt.Errorf("lvmType is incorrect: %s", lvmType)
}

// TODO: check available capacity, fail if request doesn't fit

args := []string{"-v", "--yes", "-n", name, "-W", "y", "-L", fmt.Sprintf("%db", size)}
executor := cmd.NewExecutor()
thinPoolName := ""
// we need to create thin pool first if the lvmType is dm-thin
if lvmType == dmThinType {
thinPoolName = fmt.Sprintf("%s-thinpool", vg)
found, err := getThinPool(vg, thinPoolName)
if err != nil {
return "", fmt.Errorf("unable to determine if thinpool exists: %w", err)
}
if !found {
args := []string{"-l90%FREE", "--thinpool", thinPoolName, vg}
klog.Infof("lvcreate %s", args)
_, err := executor.Execute("lvcreate", args)
if err != nil {
return "", fmt.Errorf("unable to create thinpool: %w", err)
}
}
}

args := []string{"-v", "--yes", "-n", name, "-W", "y"}

pvs, err := pvCount(vg)
if err != nil {
return "", fmt.Errorf("unable to determine pv count of vg: %w", err)
}

if pvs < 2 {
klog.Warning("pvcount is <2 only linear is supported")
lvmType = linearType
if pvs < 2 && lvmType == stripedType {
klog.Warning("pvcount is <2, the striped does not meaningful.")
}

switch lvmType {
case stripedType:
args = append(args, "--type", "striped", "--stripes", fmt.Sprintf("%d", pvs))
case mirrorType:
args = append(args, "--type", "raid1", "--mirrors", "1", "--nosync")
case linearType:
args = append(args, "-L", fmt.Sprintf("%db", size), "--type", "striped", "--stripes", fmt.Sprintf("%d", pvs), vg)
case dmThinType:
args = append(args, "-V", fmt.Sprintf("%db", size), "--thin-pool", thinPoolName, vg)
default:
return "", fmt.Errorf("unsupported lvmtype: %s", lvmType)
}

executor := cmd.NewExecutor()
tags := []string{"harvester-csi-lvm"}
for _, tag := range tags {
args = append(args, "--addtag", tag)
}
args = append(args, vg)
klog.Infof("lvcreate %s", args)
out, err := executor.Execute("lvcreate", args)
return out, err
Expand Down Expand Up @@ -535,7 +546,7 @@ func RemoveLVS(name string) (string, error) {
return out, err
}

func CreateSnapshot(snapshotName, srcVolName, vgName string, volSize int64) (string, error) {
func CreateSnapshot(snapshotName, srcVolName, vgName string, volSize int64, lvType string) (string, error) {
if snapshotName == "" || srcVolName == "" {
return "", fmt.Errorf("invalid empty name or path")
}
Expand All @@ -552,7 +563,16 @@ func CreateSnapshot(snapshotName, srcVolName, vgName string, volSize int64) (str
// Names starting "snapshot" are reserved for internal use by LVM
// we patch new snapName as "lvm-<snapshotName>"
snapshotName = fmt.Sprintf("lvm-%s", snapshotName)
args := []string{"-s", "-y", "-n", snapshotName, "-L", fmt.Sprintf("%db", volSize)}
args := []string{"-s", "-y", "-n", snapshotName}
switch lvType {
case stripedType:
args = append(args, "-L", fmt.Sprintf("%db", volSize))
case dmThinType:
// no-size option for the dm-thin
break
default:
return "", fmt.Errorf("unsupported lvmtype: %s", lvType)
}
args = append(args, fmt.Sprintf("/dev/%s/%s", vgName, srcVolName))
klog.Infof("lvcreate %s", args)
out, err := executor.Execute("lvcreate", args)
Expand Down Expand Up @@ -593,6 +613,41 @@ func pvCount(vgname string) (int, error) {
return count, nil
}

func getThinPool(vgName, thinpoolName string) (bool, error) {
executor := cmd.NewExecutor()
// we would like to get the segtype, name as below:
// thin thinvol01 <-- this is volume
// thin-pool vg02-thinpool <-- this is thin-pool
args := []string{"--noheadings", "-o", "segtype,name", vgName}
out, err := executor.Execute("lvs", args)
if err != nil {
klog.Infof("execute lvs %s, err: %v", args, err)
return false, err
}
lines := strings.Split(out, "\n")
// type[Name]
// type: thin -> vol name
// thin-pool -> pool name
thinInfo := make(map[string]string)
for _, line := range lines {
if line == "" {
continue
}
parts := strings.Fields(line)
if len(parts) != 2 {
klog.Warningf("unexpected output from lvs: %s", line)
continue
}
thinInfo[parts[0]] = parts[1]
}
for typeName, val := range thinInfo {
if typeName == "thin-pool" && val == thinpoolName {
return true, nil
}
}
return false, nil
}

func getRelatedVG(lvname string) (string, error) {
executor := cmd.NewExecutor()
// we would like to get the lvname, vgname as below:
Expand Down

0 comments on commit 6b2de1d

Please sign in to comment.