From 50fa7c61697c1e2b2970d3ee8c83aa1f7d61c638 Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Fri, 26 Jan 2024 03:16:16 +0000 Subject: [PATCH] core: add flatten-rbd-pvc command - Flatten an RBD image corrensponding to the target PVC - Remove the corresponding temporary RBD image Closes: https://github.com/rook/kubectl-rook-ceph/issues/222 Signed-off-by: Satoru Takeuchi --- cmd/commands/flatten_rbd_pvc.go | 95 +++++++++++++++++++++++++++++++++ cmd/main.go | 1 + 2 files changed, 96 insertions(+) create mode 100644 cmd/commands/flatten_rbd_pvc.go diff --git a/cmd/commands/flatten_rbd_pvc.go b/cmd/commands/flatten_rbd_pvc.go new file mode 100644 index 00000000..cd7c980a --- /dev/null +++ b/cmd/commands/flatten_rbd_pvc.go @@ -0,0 +1,95 @@ +/* +Copyright 2024 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 command + +import ( + "encoding/json" + "fmt" + + "github.com/rook/kubectl-rook-ceph/pkg/exec" + "github.com/rook/kubectl-rook-ceph/pkg/logging" + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type TrashLsOutput struct { + ID string `json:"id"` + Name string `json:"name"` +} + +var namespace string +var allowInUse bool + +// FlattenRBDPVCCmd represents the rook commands +var FlattenRBDPVCCmd = &cobra.Command{ + Use: "flatten-rbd-pvc", + Short: "Flatten the RBD image corresponding to the target RBD PVC", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + pvcName := args[0] + pvc, err := clientSets.Kube.CoreV1().PersistentVolumeClaims(namespace).Get(cmd.Context(), pvcName, metav1.GetOptions{}) + if err != nil { + logging.Fatal(err, "failed to get pvc %s/%s", namespace, pvcName) + } + if pvc.DeletionTimestamp != nil { + logging.Fatal(fmt.Errorf("pvc %s is deleting", pvcName)) + } + if pvc.Status.Phase != corev1.ClaimBound { + logging.Fatal(fmt.Errorf("pvc %s is not bound", pvcName)) + } + pvName := pvc.Spec.VolumeName + pv, err := clientSets.Kube.CoreV1().PersistentVolumes().Get(cmd.Context(), pvName, metav1.GetOptions{}) + if err != nil { + logging.Fatal(fmt.Errorf("failed to get pv %s", pvName)) + } + imageName, ok := pv.Spec.CSI.VolumeAttributes["imageName"] + if !ok { + logging.Fatal(fmt.Errorf("pv %s would not be a CSI PVC", pvName)) + } + poolName, ok := pv.Spec.CSI.VolumeAttributes["pool"] + logging.Fatal(fmt.Errorf("pv %s would not be a CSI PVC", pvName)) + + tempImageName := imageName + "-temp" + if !allowInUse { + // TODO: check whether the target PVC is mounted + logging.Fatal(fmt.Errorf("can't flatten in-use pvc %s", pvcName)) + } + logging.Info("removing the temporary RBD image %s/%s if exist", poolName, tempImageName) + exec.RunCommandInOperatorPod(cmd.Context(), clientSets, "rbd", []string{"-p", poolName, "trash", "mv", tempImageName}, cephClusterNamespace, operatorNamespace, false, false) + out := exec.RunCommandInOperatorPod(cmd.Context(), clientSets, "rbd", []string{"-p", poolName, "trash", "ls", "--format=json"}, cephClusterNamespace, operatorNamespace, true, false) + var data []TrashLsOutput + json.Unmarshal([]byte(out), &data) + var id string + for _, d := range data { + if d.Name == tempImageName { + id = d.ID + break + } + } + if id != "" { + exec.RunCommandInOperatorPod(cmd.Context(), clientSets, "ceph", []string{"rbd", "task", "add", "trash", "remove", fmt.Sprintf("%s/%s", poolName, id)}, cephClusterNamespace, operatorNamespace, false, false) + } + logging.Info("flattening the target RBD image %s/%s", poolName, imageName) + exec.RunCommandInOperatorPod(cmd.Context(), clientSets, "rbd", []string{"-p", poolName, "flatten", imageName}, cephClusterNamespace, operatorNamespace, false, false) + }, +} + +func init() { + FlattenRBDPVCCmd.Flags().StringVarP(&namespace, "namespace", "n", "default", "pvc's namespace") + FlattenRBDPVCCmd.Flags().BoolVarP(&allowInUse, "allow-in-use", "a", false, "allow to flatten in-use image") +} diff --git a/cmd/main.go b/cmd/main.go index a6a24906..3a21b9f1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -41,5 +41,6 @@ func addcommands() { command.RestoreCmd, command.DestroyClusterCmd, command.SubvolumeCmd, + command.FlattenRBDPVCCmd, ) }