diff --git a/.github/workflows/go-test-config/action.yaml b/.github/workflows/go-test-config/action.yaml index a3513de9..319602e8 100644 --- a/.github/workflows/go-test-config/action.yaml +++ b/.github/workflows/go-test-config/action.yaml @@ -116,6 +116,12 @@ runs: tests/github-action-helper.sh create_stale_subvolume subVol=$(kubectl rook-ceph ${NS_OPT} subvolume ls --stale | awk '{print $2}' | grep csi-vol) kubectl rook_ceph ${NS_OPT} subvolume delete myfs $subVol + + - name: Get rbd list + shell: bash --noprofile --norc -eo pipefail -x {0} + run: | + set -ex + kubectl rook-ceph ${NS_OPT} rbd ls - name: Get mon endpoints shell: bash --noprofile --norc -eo pipefail -x {0} diff --git a/cmd/commands/rbd.go b/cmd/commands/rbd.go index 32480e9a..a37e16a0 100644 --- a/cmd/commands/rbd.go +++ b/cmd/commands/rbd.go @@ -17,6 +17,8 @@ limitations under the License. package command import ( + rbd "github.com/rook/kubectl-rook-ceph/pkg/rbd" + "github.com/rook/kubectl-rook-ceph/pkg/exec" "github.com/rook/kubectl-rook-ceph/pkg/logging" "github.com/spf13/cobra" @@ -38,3 +40,16 @@ var RbdCmd = &cobra.Command{ } }, } + +var listCmdRbd = &cobra.Command{ + Use: "ls", + Short: "Print the list of rbd volumes.", + Run: func(cmd *cobra.Command, args []string) { + ctx := cmd.Context() + rbd.ListRbdVolumes(ctx, clientSets, operatorNamespace, cephClusterNamespace) + }, +} + +func init() { + RbdCmd.AddCommand(listCmdRbd) +} diff --git a/pkg/rbd/rbd.go b/pkg/rbd/rbd.go new file mode 100644 index 00000000..11093a88 --- /dev/null +++ b/pkg/rbd/rbd.go @@ -0,0 +1,81 @@ +/* +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 rbd + +import ( + "context" + "fmt" + "os" + "strings" + "text/tabwriter" + + "github.com/rook/kubectl-rook-ceph/pkg/exec" + "github.com/rook/kubectl-rook-ceph/pkg/k8sutil" + "github.com/rook/kubectl-rook-ceph/pkg/logging" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// List retrieves and displays the Ceph block pools and their associated images. +func ListRbdVolumes(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace string, clusterNamespace string) { + // List Ceph Block Pools + blockPoolList, err := clientsets.Rook.CephV1().CephBlockPools(clusterNamespace).List(ctx, v1.ListOptions{}) + if err != nil { + logging.Fatal(fmt.Errorf("failed to list CephBlockPools: %w", err)) + } + + // Initialize map to store block pool names and associated Rados namespaces + blockPoolNames := make(map[string][]string) + for _, blockPool := range blockPoolList.Items { + blockPoolNames[blockPool.Name] = []string{"--", "--"} + } + + // List Ceph Block Pool Rados Namespaces + blockPoolNamespaceList, err := clientsets.Rook.CephV1().CephBlockPoolRadosNamespaces(clusterNamespace).List(ctx, v1.ListOptions{}) + if err != nil { + logging.Fatal(fmt.Errorf("failed to list CephBlockPoolRadosNamespaces: %w", err)) + } + for _, blockPoolNameSpace := range blockPoolNamespaceList.Items { + if _, exists := blockPoolNames[blockPoolNameSpace.Spec.BlockPoolName]; exists { + blockPoolNames[blockPoolNameSpace.Spec.BlockPoolName][1] = blockPoolNameSpace.ObjectMeta.Name + } + } + + // Retrieve list of RBD images for each pool + cmd := "rbd" + for poolName := range blockPoolNames { + args := []string{"ls", "--pool=" + poolName} + list, err := exec.RunCommandInOperatorPod(ctx, clientsets, cmd, args, operatorNamespace, clusterNamespace, true) + if err == nil && len(list) > 0 { + blockPoolNames[poolName][0] = strings.ReplaceAll(list, "\n", "") + } + } + PrintBlockPoolNames(blockPoolNames) +} + +// PrintBlockPoolNames takes a map of block pool names to image names and prints them in a tabular format. +func PrintBlockPoolNames(blockPoolNames map[string][]string) { + writer := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) + defer writer.Flush() + // Print header with column names + fmt.Fprintln(writer, "poolName\timageName\tnameSpace\t") + fmt.Fprintln(writer, "--------\t---------\t---------\t") + + // Print each row from the map + for poolName, poolData := range blockPoolNames { + fmt.Fprintf(writer, "%s\t%s\t%s\t\n", poolName, poolData[0], poolData[1]) + } +}