forked from canonical/microceph
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Don't list WAL/DB devices as available
Signed-off-by: Peter Sabaini <[email protected]>
- Loading branch information
Showing
5 changed files
with
243 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package common | ||
|
||
import ( | ||
"bufio" | ||
"github.com/canonical/lxd/shared/logger" | ||
"github.com/canonical/microceph/microceph/constants" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
) | ||
|
||
// IsMounted checks if a device is mounted. | ||
func IsMounted(device string) (bool, error) { | ||
// Resolve any symlink and get the absolute path of the device. | ||
// Note /proc/mounts contains the absolute path of the device as well. | ||
resolvedPath, err := filepath.EvalSymlinks(device) | ||
if err != nil { | ||
// Handle errors other than not existing differently as EvalSymlinks takes care of symlink resolution | ||
return false, err | ||
} | ||
file, err := os.Open(filepath.Join(constants.GetPathConst().ProcPath, "mounts")) | ||
if err != nil { | ||
return false, err | ||
} | ||
defer file.Close() | ||
|
||
scanner := bufio.NewScanner(file) | ||
for scanner.Scan() { | ||
// Each line in /proc/mounts is of the format: | ||
// device mountpoint fstype options dump pass | ||
// --> split the line into parts and check if the first part matches | ||
parts := strings.Fields(scanner.Text()) | ||
if len(parts) > 0 && parts[0] == resolvedPath { | ||
return true, nil | ||
} | ||
} | ||
if err := scanner.Err(); err != nil { | ||
return false, err | ||
} | ||
return false, nil | ||
} | ||
|
||
// IsCephDevice checks if a given device is used as either a WAL or DB block device in any Ceph OSD. | ||
func IsCephDevice(device string) (bool, error) { | ||
// Resolve the given device path first to handle any symlinks | ||
resolved, err := filepath.EvalSymlinks(device) | ||
if err != nil { | ||
logger.Errorf("failed to resolve device path: %v", err) | ||
return false, err | ||
} | ||
// Check all ceph data dirs | ||
baseDir := filepath.Join(constants.GetPathConst().DataPath, "osd") | ||
osdDirs, err := os.ReadDir(baseDir) | ||
if err != nil { | ||
// Likely no OSDs exist yet | ||
logger.Debugf("couldn't read osd data dir %s: %v", baseDir, err) | ||
return false, nil | ||
} | ||
// Do we have a block{,.wal,.db} symlink pointing to the given device? if yes | ||
// it's already being used as a ceph device | ||
for _, osdDir := range osdDirs { | ||
if osdDir.IsDir() { | ||
if !strings.HasPrefix(osdDir.Name(), "ceph-") { | ||
continue | ||
} | ||
for _, symlinkName := range []string{"block", "block.wal", "block.db"} { | ||
symlinkPath := filepath.Join(baseDir, osdDir.Name(), symlinkName) | ||
resolvedPath, err := filepath.EvalSymlinks(symlinkPath) | ||
if err == nil { | ||
if resolvedPath == resolved { | ||
logger.Debugf("device %s is used as %s for OSD %s", device, symlinkName, osdDir.Name()) | ||
return true, nil | ||
} | ||
} else if !os.IsNotExist(err) { | ||
logger.Errorf("failed to resolve symlink %s: %v", symlinkPath, err) | ||
return false, err | ||
} | ||
} | ||
} | ||
} | ||
// Fall-through: no symlink found | ||
logger.Debugf("device %s is not used as WAL or DB device for any OSD", device) | ||
return false, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package common | ||
|
||
import ( | ||
"github.com/canonical/microceph/microceph/tests" | ||
"github.com/stretchr/testify/suite" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
) | ||
|
||
type StorageDeviceTestSuite struct { | ||
tests.BaseSuite | ||
devicePath string | ||
} | ||
|
||
func (s *StorageDeviceTestSuite) SetupTest() { | ||
s.BaseSuite.SetupTest() | ||
s.CopyCephConfigs() | ||
|
||
osdDir := filepath.Join(s.Tmp, "SNAP_COMMON", "data", "osd", "ceph-0") | ||
os.MkdirAll(osdDir, 0775) | ||
// create a temp file to use as a device | ||
s.devicePath = filepath.Join(s.Tmp, "device") | ||
os.Create(s.devicePath) | ||
|
||
// create a /proc/mounts like file | ||
mountsFile := filepath.Join(s.Tmp, "proc", "mounts") | ||
mountsContent := "/dev/root / ext4 rw,relatime,discard,errors=remount-ro 0 0\n" | ||
mountsContent += "/dev/sdb /mnt ext2 rw,relatime 0 0\n" | ||
_ = os.WriteFile(mountsFile, []byte(mountsContent), 0644) | ||
|
||
} | ||
|
||
func (s *StorageDeviceTestSuite) TestIsCephDeviceNotADevice() { | ||
isCeph, err := IsCephDevice(s.devicePath) | ||
s.NoError(err, "There should not be an error when checking a device that is not used by Ceph") | ||
s.False(isCeph, "The device should not be identified as a Ceph device") | ||
} | ||
|
||
func (s *StorageDeviceTestSuite) TestIsCephDeviceHaveDevice() { | ||
// create a symlink to the device file | ||
os.Symlink(s.devicePath, filepath.Join(s.Tmp, "SNAP_COMMON", "data", "osd", "ceph-0", "block")) | ||
isCeph, err := IsCephDevice(s.devicePath) | ||
s.NoError(err, "There should not be an error when checking a device that is used by Ceph") | ||
s.True(isCeph, "The device should be identified as a Ceph device") | ||
} | ||
|
||
func (s *StorageDeviceTestSuite) TestIsMounted() { | ||
// we added a /proc/mounts like file containing an entry for /dev/sdb | ||
mounted, err := IsMounted("/dev/sdb") | ||
s.NoError(err, "There should not be an error when checking if a device is mounted") | ||
s.True(mounted, "The device should be mounted") | ||
|
||
mounted, err = IsMounted("/dev/sdc") | ||
s.NoError(err, "There should not be an error when checking if a device is not mounted") | ||
s.False(mounted, "The device should not be mounted") | ||
|
||
} | ||
|
||
func TestStorageDeviceSuite(t *testing.T) { | ||
suite.Run(t, new(StorageDeviceTestSuite)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters