diff --git a/pkg/daemon/ceph/osd/volume.go b/pkg/daemon/ceph/osd/volume.go index 52fff0868..4d7ebb3a4 100644 --- a/pkg/daemon/ceph/osd/volume.go +++ b/pkg/daemon/ceph/osd/volume.go @@ -870,7 +870,13 @@ func (a *OsdAgent) WipeDevicesFromOtherClusters(context *clusterd.Context) error } if len(existingOSDs) == 0 { - logger.Info("no existing OSDs were found. No disks to be wiped") + // ceph-volume raw list didn't return any existing OSDs. Its possible that /dev/mapper entry of the encrypted disks were removed. + // Check for cephFSID in the luks header of the disk and clean the disk if does not match the cephFSID of the current cluster. + logger.Infof("ceph-volume didn't return any existing OSDs. Checking for cephFSID of a different cluster in the luks header of the disk") + err := wipeEncryptedDevicesFromOtherClusters(context, a.clusterInfo.FSID) + if err != nil { + return errors.Wrapf(err, "failed to clean up encrypted disks from other clusters") + } return nil } @@ -912,6 +918,39 @@ func (a *OsdAgent) WipeDevicesFromOtherClusters(context *clusterd.Context) error return nil } +func wipeEncryptedDevicesFromOtherClusters(context *clusterd.Context, currentClusterFSID string) error { + for _, disk := range context.Devices { + if disk.Filesystem == "crypto_LUKS" { + metadata, err := dumpLUKS(context, disk.Name) + if err != nil { + logger.Debugf("failed to determine if the encrypted block %q is from our cluster. %v", disk.Name, err) + return nil + } + + ceph_fsid := luksLabelCephFSID.FindString(metadata) + if ceph_fsid == "" { + logger.Error("ceph_fsid not found in the LUKS header, the encrypted disk is not from a ceph cluster") + return nil + } + + // is it an OSD from our cluster? + currentDiskCephFSID := strings.SplitAfter(ceph_fsid, "=")[1] + if currentDiskCephFSID != currentClusterFSID { + logger.Infof("cleaning encrypted disk %q (%q) that is part of a different ceph cluster %q", disk.Name, disk.RealPath, currentDiskCephFSID) + output, err := context.Executor.ExecuteCommandWithCombinedOutput("stdbuf", "-oL", cephVolumeCmd, "lvm", "zap", disk.RealPath) + if err != nil { + return errors.Wrapf(err, "failed to zap encrypted disk with different ceph cluster %q. %s.", disk.RealPath, output) + } + logger.Infof("completed wiping device %q belonging to a different ceph cluster", disk.RealPath) + // Since the device is wiped clean, clear the stale filesystem reference on the disk so that the wiped disk is not filtered out for filesystem check. + disk.Filesystem = "" + } + } + } + + return nil +} + // getOSDDiskToBeWiped returns OSD disk path and the dmcrypt block in case of encrypted OSDs func getOSDDiskToBeWiped(context *clusterd.Context, existingOSDDevice string) (*sys.LocalDisk, string, error) { var err error diff --git a/pkg/daemon/ceph/osd/volume_test.go b/pkg/daemon/ceph/osd/volume_test.go index 5b29d0b6a..86e179e8d 100644 --- a/pkg/daemon/ceph/osd/volume_test.go +++ b/pkg/daemon/ceph/osd/volume_test.go @@ -2175,6 +2175,10 @@ func TestWipeDevicesFromOtherClusters(t *testing.T) { devicePath := "/dev/vdb" logger.Infof("%s %v", command, args) + if command == cryptsetupBinary && args[0] == "luksDump" { + return luksDump, nil + } + if contains(args, "zap") { if !contains(args, devicePath) { return "", errors.Errorf("device %s should not be zapped", devicePath) @@ -2215,4 +2219,19 @@ func TestWipeDevicesFromOtherClusters(t *testing.T) { context.Executor = executor err = agent.WipeDevicesFromOtherClusters(context) assert.NoError(t, err) + + // `ceph-volume raw list` returns empty but the expected device still has luks header with cephFSID from another cluster. + executor.MockExecuteCommandWithOutput = func(command string, args ...string) (string, error) { + logger.Infof("%s %v", command, args) + if contains(args, "raw") && contains(args, "list") { + return `{}`, nil // return empty + } + return "", errors.Errorf("unknown command %s %s", command, args) + } + context = &clusterd.Context{ + Devices: []*sys.LocalDisk{{RealPath: "/dev/vdb", Filesystem: "crypto_LUKS"}}, + } + context.Executor = executor + err = agent.WipeDevicesFromOtherClusters(context) + assert.NoError(t, err) }