diff --git a/manifests/crds/harvesterhci.io_blockdevices.yaml b/manifests/crds/harvesterhci.io_blockdevices.yaml index cc09566f..3458005d 100644 --- a/manifests/crds/harvesterhci.io_blockdevices.yaml +++ b/manifests/crds/harvesterhci.io_blockdevices.yaml @@ -84,6 +84,10 @@ spec: nodeName: description: name of the node to which the block device is attached type: string + provisioner: + description: a string with the provisioner name, e.g. "longhornv1", + longhornv2" + type: string tags: description: a string list with device tag for provisioner, e.g. ["default", "small", "ssd"] diff --git a/pkg/apis/harvesterhci.io/v1beta1/types.go b/pkg/apis/harvesterhci.io/v1beta1/types.go index 4b2a3c48..5893d2c2 100644 --- a/pkg/apis/harvesterhci.io/v1beta1/types.go +++ b/pkg/apis/harvesterhci.io/v1beta1/types.go @@ -42,6 +42,9 @@ type BlockDeviceSpec struct { // a string list with device tag for provisioner, e.g. ["default", "small", "ssd"] Tags []string `json:"tags,omitempty"` + + // a string with the provisioner name, e.g. "longhornv1", longhornv2" + Provisioner string `json:"provisioner,omitempty"` } type BlockDeviceStatus struct { diff --git a/pkg/controller/blockdevice/controller.go b/pkg/controller/blockdevice/controller.go index 51cc1d6a..1cde4c17 100644 --- a/pkg/controller/blockdevice/controller.go +++ b/pkg/controller/blockdevice/controller.go @@ -30,6 +30,7 @@ import ( const ( blockDeviceHandlerName = "harvester-block-device-handler" + defaultProvisioner = "longhornv1" ) // semaphore is a simple semaphore implementation in channel @@ -212,12 +213,16 @@ func (c *Controller) OnBlockDeviceChange(_ string, device *diskv1.BlockDevice) ( if devPath == "" { return nil, fmt.Errorf("failed to resolve persistent dev path for block device %s", device.Name) } + if device.Spec.Provisioner == "" { + deviceCpy.Spec.Provisioner = defaultProvisioner + } + filesystem := c.BlockInfo.GetFileSystemInfoByDevPath(devPath) devPathStatus := convertFSInfoToString(filesystem) logrus.Debugf("Get filesystem info from device %s, %s", devPath, devPathStatus) needFormat := deviceCpy.Spec.FileSystem.ForceFormatted && (deviceCpy.Status.DeviceStatus.FileSystem.Corrupted || deviceCpy.Status.DeviceStatus.FileSystem.LastFormattedAt == nil) - if needFormat { + if deviceCpy.Spec.Provisioner == defaultProvisioner && needFormat { logrus.Infof("Prepare to force format device %s", device.Name) err := c.forceFormat(deviceCpy, devPath, filesystem) if err != nil { @@ -233,7 +238,8 @@ func (c *Controller) OnBlockDeviceChange(_ string, device *diskv1.BlockDevice) ( return device, err } - if needMountUpdate := needUpdateMountPoint(deviceCpy, filesystem); needMountUpdate != NeedMountUpdateNoOp { + needMountUpdate := needUpdateMountPoint(deviceCpy, filesystem) + if deviceCpy.Spec.Provisioner == defaultProvisioner && needMountUpdate != NeedMountUpdateNoOp { err := c.updateDeviceMount(deviceCpy, devPath, filesystem, needMountUpdate) if err != nil { err := fmt.Errorf("failed to update device mount %s: %s", device.Name, err.Error()) @@ -461,13 +467,14 @@ func (c *Controller) provisionDeviceToNode(device *diskv1.BlockDevice) error { } nodeCpy := node.DeepCopy() - diskSpec := longhornv1.DiskSpec{ - Path: extraDiskMountPoint(device), - AllowScheduling: true, - EvictionRequested: false, - StorageReserved: 0, - Tags: device.Spec.Tags, + + diskSpec := generateDiskSpec(device.Spec.Provisioner) + if device.Spec.Provisioner == defaultProvisioner { + diskSpec.Path = extraDiskMountPoint(device) + } else { + diskSpec.Path = device.Status.DeviceStatus.DevPath } + diskSpec.Tags = device.Spec.Tags updated := false if disk, found := node.Spec.Disks[device.Name]; found { @@ -803,12 +810,16 @@ func convertFSInfoToString(fsInfo *block.FileSystemInfo) string { return fmt.Sprintf("mountpoint: %s, fsType: %s", fsInfo.MountPoint, fsInfo.Type) } -func removeUnNeeded[T string | int](x []T, y []T) []T { - result := make([]T, 0) - for _, item := range x { - if !slices.Contains(y, item) { - result = append(result, item) - } +func generateDiskSpec(provisioner string) longhornv1.DiskSpec { + diskType := longhornv1.DiskTypeFilesystem + if provisioner == "longhornv2" { + diskType = longhornv1.DiskTypeBlock + } + spec := longhornv1.DiskSpec{ + Type: diskType, + AllowScheduling: true, + EvictionRequested: false, + StorageReserved: 0, } - return result + return spec } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 64c8b7ad..46c4764d 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1,6 +1,7 @@ package utils import ( + "bytes" "fmt" "os" "os/exec" @@ -175,3 +176,14 @@ func CallerWithCondLock[T any](cond *sync.Cond, f func() T) T { defer cond.L.Unlock() return f() } + +// DoCommand executes a command and returns the stdout, stderr and error +func DoCommand(cmdString string) (string, string, error) { + var stdout bytes.Buffer + var stderr bytes.Buffer + cmd := exec.Command("bash", "-c", cmdString) + cmd.Stdout = &stdout + cmd.Stderr = &stderr + err := cmd.Run() + return stdout.String(), stderr.String(), err +} diff --git a/tests/integration/test_1_disk_hotplug_test.go b/tests/integration/test_1_disk_hotplug_test.go index 555a1099..e22a41e4 100644 --- a/tests/integration/test_1_disk_hotplug_test.go +++ b/tests/integration/test_1_disk_hotplug_test.go @@ -1,11 +1,9 @@ package integration import ( - "bytes" "context" "fmt" "os" - "os/exec" "path/filepath" "strings" "testing" @@ -118,7 +116,7 @@ func (s *HotPlugTestSuite) Test_0_PreCheckForDiskCount() { func (s *HotPlugTestSuite) Test_1_HotPlugRemoveDisk() { // remove disk dynamically cmd := fmt.Sprintf("virsh detach-disk %s %s --live", hotplugTargetNodeName, hotplugTargetDiskName) - _, _, err := doCommand(cmd) + _, _, err := utils.DoCommand(cmd) require.Equal(s.T(), err, nil, "Running command `virsh detach-disk` should not get error") // wait for controller handling @@ -137,7 +135,7 @@ func (s *HotPlugTestSuite) Test_1_HotPlugRemoveDisk() { func (s *HotPlugTestSuite) Test_2_HotPlugAddDisk() { // remove disk dynamically cmd := fmt.Sprintf("virsh attach-device --domain %s --file %s --live", hotplugTargetNodeName, hotplugDiskXMLFileName) - _, _, err := doCommand(cmd) + _, _, err := utils.DoCommand(cmd) require.Equal(s.T(), err, nil, "Running command `virsh attach-device` should not get error") // wait for controller handling @@ -161,7 +159,7 @@ func (s *HotPlugTestSuite) Test_3_AddDuplicatedWWNDsik() { duplicatedDeviceRaw = "/tmp/hotplug_disks/node1-sdb.qcow2" ) cmdCpyRawFile := fmt.Sprintf("cp %s %s", originalDeviceRaw, duplicatedDeviceRaw) - _, _, err := doCommand(cmdCpyRawFile) + _, _, err := utils.DoCommand(cmdCpyRawFile) require.Equal(s.T(), err, nil, "Running command `cp the raw device file` should not get error") disk, err := utils.DiskXMLReader(hotplugDiskXMLFileName) @@ -172,7 +170,7 @@ func (s *HotPlugTestSuite) Test_3_AddDuplicatedWWNDsik() { require.Equal(s.T(), err, nil, "Write xml file should not get error") cmd := fmt.Sprintf("virsh attach-device --domain %s --file %s --live", hotplugTargetNodeName, duplicatedDeviceXML) - _, _, err = doCommand(cmd) + _, _, err = utils.DoCommand(cmd) require.Equal(s.T(), err, nil, "Running command `virsh attach-device` should not get error") // wait for controller handling @@ -189,13 +187,3 @@ func (s *HotPlugTestSuite) Test_3_AddDuplicatedWWNDsik() { require.Equal(s.T(), s.curBusPath, curBlockdevice.Status.DeviceStatus.Details.BusPath, "Disk path should not replace by duplicated wwn disk") } - -func doCommand(cmdString string) (string, string, error) { - var stdout bytes.Buffer - var stderr bytes.Buffer - cmd := exec.Command("bash", "-c", cmdString) - cmd.Stdout = &stdout - cmd.Stderr = &stderr - err := cmd.Run() - return stdout.String(), stderr.String(), err -}