2020-05-25 18:20:13 +02:00
|
|
|
|
/*
|
|
|
|
|
|
Copyright 2020 The Rook Authors. All rights reserved.
|
|
|
|
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
|
|
limitations under the License.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
package cleanup
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"strconv"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/coreos/pkg/capnslog"
|
2020-05-25 16:33:09 +02:00
|
|
|
|
cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
|
2020-05-25 18:20:13 +02:00
|
|
|
|
"github.com/rook/rook/pkg/clusterd"
|
2020-07-10 16:40:16 -06:00
|
|
|
|
"github.com/rook/rook/pkg/daemon/ceph/client"
|
2020-05-25 18:20:13 +02:00
|
|
|
|
"github.com/rook/rook/pkg/daemon/ceph/osd"
|
|
|
|
|
|
oposd "github.com/rook/rook/pkg/operator/ceph/cluster/osd"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
2025-04-07 18:20:27 +03:00
|
|
|
|
completeShredUtility = "shred"
|
2020-05-25 18:20:13 +02:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-03-13 15:24:58 -07:00
|
|
|
|
var logger = capnslog.NewPackageLogger("github.com/rook/rook", "cleanup")
|
2020-05-25 18:20:13 +02:00
|
|
|
|
|
|
|
|
|
|
// DiskSanitizer is simple struct to old the context to execute the commands
|
|
|
|
|
|
type DiskSanitizer struct {
|
2020-05-25 16:33:09 +02:00
|
|
|
|
context *clusterd.Context
|
|
|
|
|
|
clusterInfo *client.ClusterInfo
|
|
|
|
|
|
sanitizeDisksSpec *cephv1.SanitizeDisksSpec
|
2020-05-25 18:20:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-07 18:20:27 +03:00
|
|
|
|
// ShredCommand is a struct that defines a shred command with its arguments
|
|
|
|
|
|
type ShredCommand struct {
|
|
|
|
|
|
command string
|
|
|
|
|
|
args []string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-25 18:20:13 +02:00
|
|
|
|
// NewDiskSanitizer is function that returns a full filled DiskSanitizer object
|
2020-05-25 16:33:09 +02:00
|
|
|
|
func NewDiskSanitizer(context *clusterd.Context, clusterInfo *client.ClusterInfo, sanitizeDisksSpec *cephv1.SanitizeDisksSpec) *DiskSanitizer {
|
2020-05-25 18:20:13 +02:00
|
|
|
|
return &DiskSanitizer{
|
2020-05-25 16:33:09 +02:00
|
|
|
|
context: context,
|
|
|
|
|
|
clusterInfo: clusterInfo,
|
|
|
|
|
|
sanitizeDisksSpec: sanitizeDisksSpec,
|
2020-05-25 18:20:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// StartSanitizeDisks main entrypoint of the cleanup package
|
2020-07-10 16:40:16 -06:00
|
|
|
|
func (s *DiskSanitizer) StartSanitizeDisks() {
|
2020-05-25 18:20:13 +02:00
|
|
|
|
// LVM based OSDs
|
2020-07-10 16:40:16 -06:00
|
|
|
|
osdLVMList, err := osd.GetCephVolumeLVMOSDs(s.context, s.clusterInfo, s.clusterInfo.FSID, "", false, false)
|
2020-05-25 18:20:13 +02:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
logger.Errorf("failed to list lvm osd(s). %v", err)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Start the sanitizing sequence
|
2023-06-22 09:59:34 +05:30
|
|
|
|
s.SanitizeLVMDisk(osdLVMList)
|
2020-05-25 18:20:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Raw based OSDs
|
2021-06-02 15:03:50 +04:00
|
|
|
|
osdRawList, err := osd.GetCephVolumeRawOSDs(s.context, s.clusterInfo, s.clusterInfo.FSID, "", "", "", false, true)
|
2020-05-25 18:20:13 +02:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
logger.Errorf("failed to list raw osd(s). %v", err)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Start the sanitizing sequence
|
2023-06-22 09:59:34 +05:30
|
|
|
|
s.SanitizeRawDisk(osdRawList)
|
2020-05-25 18:20:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-06-22 09:59:34 +05:30
|
|
|
|
func (s *DiskSanitizer) SanitizeRawDisk(osdRawList []oposd.OSDInfo) {
|
2020-05-25 18:20:13 +02:00
|
|
|
|
// Initialize work group to wait for completion of all the go routine
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
|
|
|
|
|
|
for _, osd := range osdRawList {
|
|
|
|
|
|
logger.Infof("sanitizing osd %d disk %q", osd.ID, osd.BlockPath)
|
|
|
|
|
|
|
|
|
|
|
|
// Increment the wait group counter
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
|
|
|
|
// Put each sanitize in a go routine to speed things up
|
2022-04-29 10:29:14 +02:00
|
|
|
|
go s.executeSanitizeCommand(osd, &wg)
|
2020-05-25 18:20:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-06-22 09:59:34 +05:30
|
|
|
|
func (s *DiskSanitizer) SanitizeLVMDisk(osdLVMList []oposd.OSDInfo) {
|
2020-05-25 18:20:13 +02:00
|
|
|
|
// Initialize work group to wait for completion of all the go routine
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
pvs := []string{}
|
|
|
|
|
|
|
|
|
|
|
|
for _, osd := range osdLVMList {
|
|
|
|
|
|
// Increment the wait group counter
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
|
|
|
|
// Lookup the PV associated to the LV
|
|
|
|
|
|
pvs = append(pvs, s.returnPVDevice(osd.BlockPath)[0])
|
|
|
|
|
|
|
|
|
|
|
|
// run c-v
|
|
|
|
|
|
go s.wipeLVM(osd.ID, &wg)
|
|
|
|
|
|
}
|
|
|
|
|
|
// Wait for ceph-volume to finish before wiping the remaining Physical Volume data
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
|
|
|
|
var wg2 sync.WaitGroup
|
2023-06-22 09:59:34 +05:30
|
|
|
|
// purge remaining LVM2 metadata from PV
|
2020-05-25 18:20:13 +02:00
|
|
|
|
for _, pv := range pvs {
|
|
|
|
|
|
wg2.Add(1)
|
2022-04-29 10:29:14 +02:00
|
|
|
|
go s.executeSanitizeCommand(oposd.OSDInfo{BlockPath: pv}, &wg2)
|
2020-05-25 18:20:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
wg2.Wait()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *DiskSanitizer) wipeLVM(osdID int, wg *sync.WaitGroup) {
|
|
|
|
|
|
// On return, notify the WaitGroup that we’re done
|
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
|
|
|
|
|
|
output, err := s.context.Executor.ExecuteCommandWithCombinedOutput("stdbuf", "-oL", "ceph-volume", "lvm", "zap", "--osd-id", strconv.Itoa(osdID), "--destroy")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
logger.Errorf("failed to sanitize osd %d. %s. %v", osdID, output, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
logger.Infof("%s\n", output)
|
|
|
|
|
|
logger.Infof("successfully sanitized lvm osd %d", osdID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *DiskSanitizer) returnPVDevice(disk string) []string {
|
|
|
|
|
|
output, err := s.context.Executor.ExecuteCommandWithOutput("lvs", disk, "-o", "seg_pe_ranges", "--noheadings")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
logger.Errorf("failed to execute lvs command. %v", err)
|
|
|
|
|
|
return []string{}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
logger.Infof("output: %s", output)
|
|
|
|
|
|
return strings.Split(output, ":")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-25 16:33:09 +02:00
|
|
|
|
func (s *DiskSanitizer) buildDataSource() string {
|
|
|
|
|
|
return fmt.Sprintf("/dev/%s", s.sanitizeDisksSpec.DataSource.String())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *DiskSanitizer) buildShredArgs(disk string) []string {
|
|
|
|
|
|
var shredArgs []string
|
|
|
|
|
|
|
|
|
|
|
|
// If data source is not zero, then let's add zeros at the end of the pass
|
|
|
|
|
|
if s.sanitizeDisksSpec.DataSource != cephv1.SanitizeDataSourceZero {
|
|
|
|
|
|
shredArgs = append(shredArgs, "--zero")
|
2020-05-25 18:20:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-25 16:33:09 +02:00
|
|
|
|
// If the data source for randomness is zero
|
|
|
|
|
|
if s.sanitizeDisksSpec.DataSource == cephv1.SanitizeDataSourceZero {
|
|
|
|
|
|
shredArgs = append(shredArgs, fmt.Sprintf("--random-source=%s", s.buildDataSource()))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
shredArgs = append(shredArgs, []string{
|
|
|
|
|
|
"--force",
|
|
|
|
|
|
"--verbose",
|
|
|
|
|
|
fmt.Sprintf("--iterations=%s", strconv.Itoa(int(s.sanitizeDisksSpec.Iteration))),
|
2025-03-13 15:24:58 -07:00
|
|
|
|
disk,
|
|
|
|
|
|
}...)
|
2020-05-25 16:33:09 +02:00
|
|
|
|
|
|
|
|
|
|
return shredArgs
|
2020-05-25 18:20:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-07 18:20:27 +03:00
|
|
|
|
func (s *DiskSanitizer) buildQuickShredCommands(disk string) []ShredCommand {
|
|
|
|
|
|
return []ShredCommand{
|
|
|
|
|
|
{command: "ceph-volume", args: []string{"lvm", "zap", disk}},
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *DiskSanitizer) buildShredCommands(disk string) []ShredCommand {
|
|
|
|
|
|
var shredCommands []ShredCommand
|
|
|
|
|
|
|
|
|
|
|
|
if s.sanitizeDisksSpec.Method == cephv1.SanitizeMethodQuick {
|
|
|
|
|
|
return s.buildQuickShredCommands(disk)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if s.sanitizeDisksSpec.DataSource == cephv1.SanitizeDataSourceZero {
|
|
|
|
|
|
shredCommands = append(shredCommands, ShredCommand{command: completeShredUtility, args: s.buildShredArgs(disk)})
|
|
|
|
|
|
return shredCommands
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
shredCommands = append(shredCommands, ShredCommand{command: completeShredUtility, args: s.buildShredArgs(disk)})
|
|
|
|
|
|
|
|
|
|
|
|
return shredCommands
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-04-29 10:29:14 +02:00
|
|
|
|
func (s *DiskSanitizer) executeSanitizeCommand(osdInfo oposd.OSDInfo, wg *sync.WaitGroup) {
|
2020-05-25 18:20:13 +02:00
|
|
|
|
// On return, notify the WaitGroup that we’re done
|
|
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
|
2025-04-07 18:20:27 +03:00
|
|
|
|
// If the device is encrypted, get the real path and remove the dm device
|
|
|
|
|
|
if osdInfo.Encrypted {
|
|
|
|
|
|
realPath, err := osd.GetBackingDeviceForEncryptedBlock(s.context, osdInfo.BlockPath)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
logger.Errorf("failed to get backing device for encrypted block %q. %v", osdInfo.BlockPath, err)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
err := osd.RemoveEncryptedDevice(s.context, osdInfo.BlockPath)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
logger.Errorf("failed to remove dm device %q. %v", osdInfo.BlockPath, err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
osdInfo.BlockPath = realPath
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-23 15:32:56 +02:00
|
|
|
|
for _, device := range []string{osdInfo.BlockPath, osdInfo.MetadataPath, osdInfo.WalPath} {
|
|
|
|
|
|
if device == "" {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
2020-05-25 18:20:13 +02:00
|
|
|
|
|
2025-04-07 18:20:27 +03:00
|
|
|
|
for _, shredCmd := range s.buildShredCommands(device) {
|
|
|
|
|
|
output, err := s.context.Executor.ExecuteCommandWithCombinedOutput(shredCmd.command, shredCmd.args...)
|
2024-08-23 15:32:56 +02:00
|
|
|
|
|
2025-04-07 18:20:27 +03:00
|
|
|
|
logger.Infof("%s\n", output)
|
2022-04-29 10:29:14 +02:00
|
|
|
|
|
2024-08-23 15:32:56 +02:00
|
|
|
|
if err != nil {
|
2025-04-07 18:20:27 +03:00
|
|
|
|
logger.Errorf("failed to execute sanitization command for osd disk %q. output: %s, error: %v", device, output, err)
|
2024-08-23 15:32:56 +02:00
|
|
|
|
} else {
|
2025-04-07 18:20:27 +03:00
|
|
|
|
logger.Infof("successfully executed sanitization command for osd disk %q", device)
|
2024-08-23 15:32:56 +02:00
|
|
|
|
}
|
2022-04-29 10:29:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-05-25 18:20:13 +02:00
|
|
|
|
}
|