From 877892fa10562535254dd09aac93e5517313f05d Mon Sep 17 00:00:00 2001 From: Oded Viner <oviner@redhat.com> Date: Sun, 27 Oct 2024 10:25:30 +0200 Subject: [PATCH] csi: add rbd ls option This commit adds the ability to list RBD images. Signed-off-by: Oded Viner <oviner@redhat.com> --- .github/workflows/go-test-config/action.yaml | 6 ++ cmd/commands/rbd.go | 15 ++++ go.mod | 10 +-- go.sum | 20 ++--- pkg/rbd/rbd.go | 93 ++++++++++++++++++++ 5 files changed, 129 insertions(+), 15 deletions(-) create mode 100644 pkg/rbd/rbd.go diff --git a/.github/workflows/go-test-config/action.yaml b/.github/workflows/go-test-config/action.yaml index 1f72dfcc..23bde1ba 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..b710e08c 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 images.", + Run: func(cmd *cobra.Command, args []string) { + ctx := cmd.Context() + rbd.ListImages(ctx, clientSets, operatorNamespace, cephClusterNamespace) + }, +} + +func init() { + RbdCmd.AddCommand(listCmdRbd) +} diff --git a/go.mod b/go.mod index 1f88e172..35005c0d 100644 --- a/go.mod +++ b/go.mod @@ -9,14 +9,14 @@ require ( github.com/golang/mock v1.6.0 github.com/kubernetes-csi/external-snapshotter/client/v8 v8.0.0 github.com/pkg/errors v0.9.1 - github.com/rook/rook v1.15.5 + github.com/rook/rook v1.15.6 github.com/rook/rook/pkg/apis v0.0.0-20231204200402-5287527732f7 github.com/spf13/cobra v1.8.1 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.31.2 - k8s.io/apimachinery v0.31.2 - k8s.io/client-go v0.31.2 + k8s.io/api v0.31.3 + k8s.io/apimachinery v0.31.3 + k8s.io/client-go v0.31.3 ) require ( diff --git a/go.sum b/go.sum index 5b3fa865..830ff767 100644 --- a/go.sum +++ b/go.sum @@ -688,8 +688,8 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rook/rook v1.15.5 h1:5CaeHUDnVYVC38en60XBCwSRh84jrgk8GrMyMO96lLg= -github.com/rook/rook v1.15.5/go.mod h1:/SklxXAcmvgkj5w+zZFXb5iImadQOTKduwtXVDhw/MY= +github.com/rook/rook v1.15.6 h1:LEBtNqEdpNcRFg3LX8oSGkYM/NdpbNbeHFtMONvU+tc= +github.com/rook/rook v1.15.6/go.mod h1:/SklxXAcmvgkj5w+zZFXb5iImadQOTKduwtXVDhw/MY= github.com/rook/rook/pkg/apis v0.0.0-20231204200402-5287527732f7 h1:jXRUM2OJDz6hwpO4fElAgUqdTKosO3LHV3fwEB6iYJM= github.com/rook/rook/pkg/apis v0.0.0-20231204200402-5287527732f7/go.mod h1:ZnB1JWtsxJLz2Q3ylHFS4lE/2A1lw2zIOKN0uAmhiZM= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -744,8 +744,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -1406,8 +1406,8 @@ k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= k8s.io/api v0.26.0/go.mod h1:k6HDTaIFC8yn1i6pSClSqIwLABIcLV9l5Q4EcngKnQg= -k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= -k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= +k8s.io/api v0.31.3 h1:umzm5o8lFbdN/hIXbrK9oRpOproJO62CV1zqxXrLgk8= +k8s.io/api v0.31.3/go.mod h1:UJrkIp9pnMOI9K2nlL6vwpxRzzEX5sWgn8kGQe92kCE= k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE= k8s.io/apiextensions-apiserver v0.18.3/go.mod h1:TMsNGs7DYpMXd+8MOCX8KzPOCx8fnZMoIGB24m03+JE= k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk= @@ -1420,8 +1420,8 @@ k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRp k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/apimachinery v0.26.0/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= -k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= -k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apimachinery v0.31.3 h1:6l0WhcYgasZ/wk9ktLq5vLaoXJJr5ts6lkaQzgeYPq4= +k8s.io/apimachinery v0.31.3/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/apiserver v0.18.3/go.mod h1:tHQRmthRPLUtwqsOnJJMoI8SW3lnoReZeE861lH8vUw= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= @@ -1430,8 +1430,8 @@ k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= k8s.io/client-go v0.20.0/go.mod h1:4KWh/g+Ocd8KkCwKF8vUNnmqgv+EVnQDK4MBF4oB5tY= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= -k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= -k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= +k8s.io/client-go v0.31.3 h1:CAlZuM+PH2cm+86LOBemaJI/lQ5linJ6UFxKX/SoG+4= +k8s.io/client-go v0.31.3/go.mod h1:2CgjPUTpv3fE5dNygAr2NcM8nhHzXvxB8KL5gYc3kJs= k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/code-generator v0.19.0/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= k8s.io/code-generator v0.20.0/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= diff --git a/pkg/rbd/rbd.go b/pkg/rbd/rbd.go new file mode 100644 index 00000000..2c322a05 --- /dev/null +++ b/pkg/rbd/rbd.go @@ -0,0 +1,93 @@ +/* +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 ListImages(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 { + var name string + // Check if Spec.BlockPoolName exists; otherwise, use ObjectMeta.Name + if blockPoolNameSpace.Spec.Name != "" { + name = blockPoolNameSpace.Spec.Name + } else { + name = blockPoolNameSpace.ObjectMeta.Name + } + if _, exists := blockPoolNames[blockPoolNameSpace.Spec.BlockPoolName]; exists { + blockPoolNames[blockPoolNameSpace.Spec.BlockPoolName][1] = name + } + } + + // Retrieve list of RBD images for each pool + cmd := "rbd" + var args []string + for poolName := range blockPoolNames { + if blockPoolNames[poolName][1] != "--" { + args = []string{"ls", "--pool=" + poolName, "--namespace=" + blockPoolNames[poolName][1]} + } else { + 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]) + } +}