File kubectl-rook-ceph-0.9.4.obscpio of Package kubectl-rook-ceph

07070100000000000081A4000000000000000000000001680F0E8800000333000000000000000000000000000000000000002B00000000kubectl-rook-ceph-0.9.4/.commitlintrc.json{
    "extends": [
        "@commitlint/config-conventional"
    ],
    "rules": {
        "type-enum": [
            2,
            "always",
            [
                "build",
                "ci",
                "core",
                "csi",
                "doc",
                "docs",
                "mds",
                "mgr",
                "mon",
                "mons",
                "operator",
                "osd",
                "test",
                "tests",
                "clean",
                "maintenance"
            ]
        ],
        "body-leading-blank": [
            2,
            "always"
        ],
        "footer-leading-blank": [
            2,
            "always"
        ],
        "body-max-line-length": [
            0,
            "always"
        ]
    }
}
07070100000001000081A4000000000000000000000001680F0E880000020F000000000000000000000000000000000000002900000000kubectl-rook-ceph-0.9.4/.goreleaser.yamlbefore:
  hooks:
    - go mod tidy
builds:
  - id: kubectl-rook-ceph
    main: ./cmd
    binary: kubectl-rook-ceph
    env:
      - CGO_ENABLED=0
    goos:
      - linux
      - darwin
      - windows
    goarch:
      - amd64
      - arm64
    ignore:
      - goos: windows
        goarch: arm64

archives:
  - builds:
      - kubectl-rook-ceph
    name_template: "{{ .ProjectName }}_{{ .Tag }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
    wrap_in_directory: false
    format: tar.gz
    files:
      - LICENSE
07070100000002000081A4000000000000000000000001680F0E8800000708000000000000000000000000000000000000002300000000kubectl-rook-ceph-0.9.4/.krew.yamlapiVersion: krew.googlecontainertools.github.com/v1alpha2
kind: Plugin
metadata:
  name: rook-ceph
spec:
  version: {{ .TagName }}
  homepage: https://github.com/rook/kubectl-rook-ceph
  shortDescription: Rook plugin for Ceph management
  description: |
    The kubectl-rook-ceph is a Krew plugin designed for Rook-Ceph. It simplifies the management, debugging, and
    troubleshooting processes, while also offering valuable insights into the configuration of the Rook-Ceph clusters.
  platforms:
  - selector:
      matchLabels:
        os: darwin
        arch: amd64
    {{addURIAndSha "https://github.com/rook/kubectl-rook-ceph/releases/download/{{ .TagName }}/kubectl-rook-ceph_{{ .TagName }}_darwin_amd64.tar.gz" .TagName }}
    bin: kubectl-rook-ceph
  - selector:
      matchLabels:
        os: darwin
        arch: arm64
    {{addURIAndSha "https://github.com/rook/kubectl-rook-ceph/releases/download/{{ .TagName }}/kubectl-rook-ceph_{{ .TagName }}_darwin_arm64.tar.gz" .TagName }}
    bin: kubectl-rook-ceph
  - selector:
      matchLabels:
        os: linux
        arch: amd64
    {{addURIAndSha "https://github.com/rook/kubectl-rook-ceph/releases/download/{{ .TagName }}/kubectl-rook-ceph_{{ .TagName }}_linux_amd64.tar.gz" .TagName }}
    bin: kubectl-rook-ceph
  - selector:
      matchLabels:
        os: linux
        arch: arm64
    {{addURIAndSha "https://github.com/rook/kubectl-rook-ceph/releases/download/{{ .TagName }}/kubectl-rook-ceph_{{ .TagName }}_linux_arm64.tar.gz" .TagName }}
    bin: kubectl-rook-ceph
  - selector:
      matchLabels:
        os: windows
        arch: amd64
    {{addURIAndSha "https://github.com/rook/kubectl-rook-ceph/releases/download/{{ .TagName }}/kubectl-rook-ceph_{{ .TagName }}_windows_amd64.tar.gz" .TagName }}
    bin: kubectl-rook-ceph.exe
07070100000003000081A4000000000000000000000001680F0E8800002C68000000000000000000000000000000000000002000000000kubectl-rook-ceph-0.9.4/LICENSE                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2016 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.
07070100000004000081A4000000000000000000000001680F0E880000041C000000000000000000000000000000000000002100000000kubectl-rook-ceph-0.9.4/Makefile# Copyright 2023 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.


build:
	gofmt -w $(shell find . -type f -name '*.go')
	@echo
	env GOOS=$(shell go env GOOS) GOARCH=$(shell go env GOARCH) go build -o bin/kubectl-rook-ceph  cmd/main.go

clean:
	@rm -f bin/kubectl-rook-ceph

test:
	@echo "running unit tests"
	go test ./...

help :
	@echo "build : Create go binary."
	@echo "test  : Runs unit tests"
	@echo "clean : Remove go binary file."

codegen:
	@echo "generating mocks..."
	@go generate ./...
	@echo completed07070100000005000081A4000000000000000000000001680F0E8800001D39000000000000000000000000000000000000002200000000kubectl-rook-ceph-0.9.4/README.md<img alt="Rook" src="media/logo.svg" width="50%" height="50%">

# kubectl-rook-ceph

Provide common management and troubleshooting tools for the [Rook Ceph](https://github.com/rook/rook) storage provider as a [Krew](https://github.com/kubernetes-sigs/krew) plugin.

## Install

> Note: This requires kubectl [krew](https://krew.sigs.k8s.io/docs/user-guide/setup/install/) to be installed.

To install the plugin, run:

  ```kubectl krew install rook-ceph```

To check plugin version `kubectl krew list` this will list all krew plugin with their current version.

## Update

  ```kubectl krew upgrade rook-ceph```

## Usage

`kubectl rook-ceph <root-args> <command> <command-args>`

### Root args

These are args currently supported:

1. `-h|--help`: this will print brief command help text.

    ```bash
    kubectl rook-ceph --help
    ```

2. `-n|--namespace='rook-ceph'`: the Kubernetes namespace in which the CephCluster resides. (optional,  default: rook-ceph)

    ```bash
    kubectl rook-ceph -o test-operator -n test-cluster rook version
    ```

3. `-o|--operator-namespace` : the Kubernetes namespace in which the rook operator resides, when the arg `-n` is passed but `-o` is not then `-o` will equal to the `-n`. (default: rook-ceph)

    ```bash
    kubectl rook-ceph -o test-operator -n test-cluster rook version
    ```

4. `--context`: the name of the Kubernetes context to be used (optional).

    ```bash
    kubectl rook-ceph --context=$(kubectl config current-context) mons
    ```

### Commands

- `ceph <args>` : Run a Ceph CLI command. Supports any arguments the `ceph` command supports. See [Ceph docs](https://docs.ceph.com/en/pacific/start/intro/) for more.

- `ceph daemon <daemon.id> <args>`: Run a Ceph daemon command by connecting to its admin socket.

- `rados <args>` : Run a Rados CLI command. Supports any arguments the `rados` command supports. See [Rados docs](https://docs.ceph.com/en/latest/man/8/rados/) for more.

- `radosgw-admin <args>` : Run an RGW CLI command. Supports any arguments the `radosgw-admin` command supports. See the [radosgw-admin docs](https://docs.ceph.com/en/latest/man/8/radosgw-admin/) for more.

- `rbd <args>` : Call a 'rbd' CLI command with arbitrary args

- `mons` : Print mon endpoints
  - `restore-quorum <mon-name>` : Restore the mon quorum based on a single healthy mon since quorum was lost with the other mons

- `health` : check health of the cluster and common configuration issues

- `operator`
  - `restart` : Restart the Rook-Ceph operator
  - `set <property> <value>` : Set the property in the rook-ceph-operator-config configmap.

- `rook`
  - `version`     : Print the version of Rook
  - `status`      : Print the phase and/or conditions of every CR in the namespace
  - `status all`  : Print the phase and conditions of all CRs
  - `status <CR>` : Print the phase and conditions of CRs of a specific type, such as `cephobjectstore`, `cephfilesystem`, etc
  - `purge-osd <osd-id> [--force]` : Permanently remove an OSD from the cluster. Multiple OSDs can be removed with a comma-separated list of IDs.

- `maintenance` : [Perform maintenance operations](docs/maintenance.md) on mons or OSDs. The mon or OSD deployment will be scaled down and replaced temporarily by a maintenance deployment.
  - `start  <deployment-name>`
    `[--alternate-image <alternate-image>]` : Start a maintenance deployment with an optional alternative ceph container image
  - `stop  <deployment-name>` : Stop the maintenance deployment and restore the mon or OSD deployment

- `dr` :
  - `health [ceph status args]`: Print the `ceph status` of a peer cluster in a mirroring-enabled environment thereby validating connectivity between ceph clusters. Ceph status args can be optionally passed, such as to change the log level: `--debug-ms 1`.

- `restore-deleted <CRD> [CRName]`: Restore the ceph resources which are stuck in deleting state due to underlying resources being present in the cluster

- `help` : Output help text

## Documentation

Visit docs below for complete details about each command and their flags uses.

1. [Running ceph commands](docs/ceph.md)
1. [Running ceph daemon commands](docs/ceph.md#Daemon)
1. [Running rbd commands](docs/rbd.md)
1. [Get mon endpoints](docs/mons.md#print-mon-endpoints)
1. [Get cluster health status](docs/health.md)
1. [Update configmap rook-ceph-operator-config](docs/operator.md#set)
1. [Restart operator pod](docs/operator.md#restart)
1. [Get rook version](docs/rook.md#version)
1. [Get all CR status](docs/rook.md#status-all)
1. [Get cephCluster CR status](docs/rook.md#status)
1. [Get specific CR status](docs/rook.md#status-cr-name)
1. [To purge OSD](docs/rook.md#operator.md)
1. [Perform maintenance for OSDs and Mons](docs/maintenance.md)
1. [Restore mon quorum](docs/mons.md#restore-quorum)
1. [Disaster Recovery](docs/dr-health.md)
1. [Restore deleted CRs](docs/crd.md)
1. [Destroy cluster](docs/destroy-cluster.md)
1. [Running rados commands](docs/rados.md)

## Examples

### Run a Ceph Command

Any `ceph` command can be run with the plugin. This example gets the ceph status:

```console
kubectl rook-ceph ceph status
```

>```text
>  cluster:
>    id:     a1ac6554-4cc8-4c3b-a8a3-f17f5ec6f529
>    health: HEALTH_OK
>
>  services:
>    mon: 3 daemons, quorum a,b,c (age 11m)
>    mgr: a(active, since 10m)
>    mds: 1/1 daemons up, 1 hot standby
>    osd: 3 osds: 3 up (since 10m), 3 in (since 8d)
>
>  data:
>    volumes: 1/1 healthy
>    pools:   6 pools, 137 pgs
>    objects: 34 objects, 4.1 KiB
>    usage:   58 MiB used, 59 GiB / 59 GiB avail
>    pgs:     137 active+clean
>
>  io:
>    client:   1.2 KiB/s rd, 2 op/s rd, 0 op/s wr
>```

### Restart the Operator

```console
kubectl rook-ceph operator restart
```

>```text
>deployment.apps/rook-ceph-operator restarted
>```

### Rook Version

```console
kubectl rook-ceph rook version
```

```text
rook: v1.8.0-alpha.0.267.g096dabfa6
go: go1.16.13
```

### Ceph Versions

```console
kubectl rook-ceph ceph versions
```

```text
{
    "mon": {
        "ceph version 16.2.7 (dd0603118f56ab514f133c8d2e3adfc983942503) pacific (stable)": 1
    },
    "mgr": {
        "ceph version 16.2.7 (dd0603118f56ab514f133c8d2e3adfc983942503) pacific (stable)": 1
    },
    "osd": {
        "ceph version 16.2.7 (dd0603118f56ab514f133c8d2e3adfc983942503) pacific (stable)": 1
    },
    "mds": {},
    "overall": {
        "ceph version 16.2.7 (dd0603118f56ab514f133c8d2e3adfc983942503) pacific (stable)": 3
    }
}
```

## Contributing

We welcome contributions. See the [Rook Contributing Guide](https://github.com/rook/rook/blob/master/CONTRIBUTING.md) to get started.

## Report a Bug

For filing bugs, suggesting improvements, or requesting new features, please open an [issue](https://github.com/rook/kubectl-rook-ceph/issues).

## Contact

Please use the following to reach members of the community:

- Slack: Join our [slack channel](https://slack.rook.io)
- Forums: [rook-dev](https://groups.google.com/forum/#!forum/rook-dev)
- Twitter: [@rook_io](https://twitter.com/rook_io)
- Email (general topics): [cncf-rook-info@lists.cncf.io](mailto:cncf-rook-info@lists.cncf.io)
- Email (security topics): [cncf-rook-security@lists.cncf.io](mailto:cncf-rook-security@lists.cncf.io)

## Licensing

Rook is under the Apache 2.0 license.

[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Frook%2Frook.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Frook%2Frook?ref=badge_large)
07070100000006000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000001C00000000kubectl-rook-ceph-0.9.4/cmd07070100000007000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002500000000kubectl-rook-ceph-0.9.4/cmd/commands07070100000008000081A4000000000000000000000001680F0E88000008BD000000000000000000000000000000000000002D00000000kubectl-rook-ceph-0.9.4/cmd/commands/ceph.go/*
Copyright 2023 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 (
	"fmt"
	"strings"

	"github.com/rook/kubectl-rook-ceph/pkg/exec"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	"github.com/spf13/cobra"
)

// CephCmd represents the ceph command
var CephCmd = &cobra.Command{
	Use:                "ceph",
	Short:              "call a 'ceph' CLI command with arbitrary args",
	DisableFlagParsing: true,
	Args:               cobra.MinimumNArgs(1),
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
	Run: func(cmd *cobra.Command, args []string) {
		logging.Info("running 'ceph' command with args: %v", args)
		if args[0] == "daemon" {
			if len(args) < 2 {
				logging.Fatal(fmt.Errorf("too few arguments to run the 'ceph daemon' command"))
			}
			cephDaemonNameAndID := splitCephDaemonNameAndID(args[1])
			_, err := exec.RunCommandInLabeledPod(cmd.Context(), clientSets, fmt.Sprintf("%s=%s", cephDaemonNameAndID[0], cephDaemonNameAndID[1]), cephDaemonNameAndID[0], cmd.Use, args, cephClusterNamespace, false)
			if err != nil {
				logging.Fatal(err)
			}

		} else {
			_, err := exec.RunCommandInOperatorPod(cmd.Context(), clientSets, cmd.Use, args, operatorNamespace, cephClusterNamespace, false)
			if err != nil {
				logging.Fatal(err)
			}
		}
	},
}

// splitCephDaemonNameAndID splits the arg based on '.' so that we use it with label, example osd.0 to osd and 0
func splitCephDaemonNameAndID(args string) []string {
	if !strings.Contains(args, ".") {
		logging.Fatal(fmt.Errorf("Invalid argument to 'ceph daemon' command: %v. The arg should be in the format of '<daemon.id>'", args))
	}
	return strings.Split(args, ".")
}
07070100000009000081A4000000000000000000000001680F0E8800000374000000000000000000000000000000000000003200000000kubectl-rook-ceph-0.9.4/cmd/commands/ceph_test.go/*
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 (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestSplitCephDaemonNameAndID(t *testing.T) {
	daemon := "osd.0"
	cephDaemonNameAndID := splitCephDaemonNameAndID(daemon)
	assert.Equal(t, cephDaemonNameAndID[0], "osd")
	assert.Equal(t, cephDaemonNameAndID[1], "0")
}
0707010000000A000081A4000000000000000000000001680F0E88000006BC000000000000000000000000000000000000003800000000kubectl-rook-ceph-0.9.4/cmd/commands/destroy_cluster.go/*
Copyright 2023 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 (
	"fmt"

	"github.com/rook/kubectl-rook-ceph/pkg/crds"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	"github.com/rook/kubectl-rook-ceph/pkg/mons"
	"github.com/spf13/cobra"
)

const (
	destroyClusterQuestion = "Are you sure you want to destroy the cluster in namespace %q? If absolutely certain, enter: " + destroyClusterAnswer
	destroyClusterAnswer   = "yes-really-destroy-cluster"
)

// DestroyClusterCmd represents the command for destroy cluster
var DestroyClusterCmd = &cobra.Command{
	Use:   "destroy-cluster",
	Short: "delete ALL data in the Rook cluster and all Rook CRs",

	Run: func(cmd *cobra.Command, args []string) {
		ctx := cmd.Context()
		var answer string
		logging.Warning(destroyClusterQuestion, cephClusterNamespace)
		fmt.Scanf("%s", &answer)
		err := mons.PromptToContinueOrCancel(destroyClusterAnswer, answer)
		if err != nil {
			logging.Fatal(fmt.Errorf("the response %q to confirm the cluster deletion", destroyClusterAnswer))
		}

		logging.Info("proceeding")
		clientsets := getClientsets(ctx)
		crds.DeleteCustomResources(ctx, clientsets, clientsets.Kube, cephClusterNamespace)
	},
}
0707010000000B000081A4000000000000000000000001680F0E8800000352000000000000000000000000000000000000003200000000kubectl-rook-ceph-0.9.4/cmd/commands/dr_health.gopackage command

import (
	"github.com/rook/kubectl-rook-ceph/pkg/dr"
	"github.com/spf13/cobra"
)

var DrCmd = &cobra.Command{
	Use:                "dr",
	Short:              "Calls subcommand health",
	DisableFlagParsing: true,
	Args:               cobra.ExactArgs(1),
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
}

var healthCmd = &cobra.Command{
	Use:                "health",
	Short:              "Print the ceph status of a peer cluster in a mirroring-enabled cluster.",
	DisableFlagParsing: true,
	Args:               cobra.MaximumNArgs(2),
	Example:            "rook-ceph dr health [Arg]",
	Run: func(cmd *cobra.Command, args []string) {
		dr.Health(cmd.Context(), clientSets, operatorNamespace, cephClusterNamespace, args)
	},
}

func init() {
	DrCmd.AddCommand(healthCmd)
}
0707010000000C000081A4000000000000000000000001680F0E88000006B8000000000000000000000000000000000000003800000000kubectl-rook-ceph-0.9.4/cmd/commands/flatten_rbd_pvc.go/*
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 (
	flatten_rbd_pvc "github.com/rook/kubectl-rook-ceph/pkg/flatten-rbd-pvc"

	"github.com/spf13/cobra"
)

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",
	Long: `Flatten the RBD image corresponding to the target RBD PVC.
The target RBD PVC must be a cloned image and must be created by ceph-csi.
This command removes the corresponding temporary cloned image[1]
if the target PVC was cloned from another PVC.

[1]: https://github.com/ceph/ceph-csi/blob/devel/docs/design/proposals/rbd-snap-clone.md`,
	Args: cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		flatten_rbd_pvc.FlattenRBDPVC(cmd.Context(), clientSets, operatorNamespace, cephClusterNamespace, namespace, args[0], allowInUse)
	},
}

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")
}
0707010000000D000081A4000000000000000000000001680F0E8800000472000000000000000000000000000000000000002F00000000kubectl-rook-ceph-0.9.4/cmd/commands/health.go/*
Copyright 2023 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 (
	"github.com/rook/kubectl-rook-ceph/pkg/health"
	"github.com/spf13/cobra"
)

var Health = &cobra.Command{
	Use:                "health",
	Short:              "check health of the cluster and common configuration issues",
	DisableFlagParsing: true,
	Args:               cobra.NoArgs,
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
	Run: func(cmd *cobra.Command, _ []string) {
		health.Health(cmd.Context(), clientSets, operatorNamespace, cephClusterNamespace)
	},
}
0707010000000E000081A4000000000000000000000001680F0E8800000885000000000000000000000000000000000000003400000000kubectl-rook-ceph-0.9.4/cmd/commands/maintenance.go/*
Copyright 2023 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 (
	"github.com/rook/kubectl-rook-ceph/pkg/maintenance"
	"github.com/spf13/cobra"
)

// MaintenanceCmd represents the operator commands
var MaintenanceCmd = &cobra.Command{
	Use:                "maintenance",
	Short:              "Perform maintenance operation on mons and OSDs deployment by scaling it down and creating a maintenance deployment.",
	DisableFlagParsing: true,
	Args:               cobra.ExactArgs(1),
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
}

var startMaintenanceCmd = &cobra.Command{
	Use:     "start",
	Short:   "Start a maintenance deployment with an optional alternative ceph container image",
	Args:    cobra.ExactArgs(1),
	Example: "kubectl rook-ceph maintenance start <deployment_name>",
	Run: func(cmd *cobra.Command, args []string) {
		alternateImage := cmd.Flag("alternate-image").Value.String()
		maintenance.StartMaintenance(cmd.Context(), clientSets.Kube, cephClusterNamespace, args[0], alternateImage)
	},
}

var stopMaintenanceCmd = &cobra.Command{
	Use:     "stop",
	Short:   "Stops the maintenance deployment",
	Args:    cobra.ExactArgs(1),
	Example: "kubectl rook-ceph maintenance stop <deployment_name>",
	Run: func(cmd *cobra.Command, args []string) {
		maintenance.StopMaintenance(cmd.Context(), clientSets.Kube, cephClusterNamespace, args[0])
	},
}

func init() {
	MaintenanceCmd.AddCommand(startMaintenanceCmd)
	startMaintenanceCmd.Flags().String("alternate-image", "", "To create deployment with alternate image")
	MaintenanceCmd.AddCommand(stopMaintenanceCmd)
}
0707010000000F000081A4000000000000000000000001680F0E880000065A000000000000000000000000000000000000002D00000000kubectl-rook-ceph-0.9.4/cmd/commands/mons.go/*
Copyright 2023 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 (
	"fmt"

	"github.com/rook/kubectl-rook-ceph/pkg/mons"
	"github.com/spf13/cobra"
)

// MonCmd represents the mons command
var MonCmd = &cobra.Command{
	Use:                "mons",
	Short:              "Output mon endpoints",
	DisableFlagParsing: true,
	Args:               cobra.MaximumNArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			fmt.Println(mons.GetMonEndpoint(cmd.Context(), clientSets.Kube, cephClusterNamespace))
		}
	},
}

// RestoreQuorum represents the mons command
var RestoreQuorum = &cobra.Command{
	Use:                "restore-quorum",
	Short:              "When quorum is lost, restore quorum to the remaining healthy mon",
	DisableFlagParsing: true,
	Args:               cobra.ExactArgs(1),
	Example:            "kubectl rook-ceph mons restore-quorum <Mon_ID>",
	Run: func(cmd *cobra.Command, args []string) {
		mons.RestoreQuorum(cmd.Context(), clientSets, operatorNamespace, cephClusterNamespace, args[0])
	},
}

func init() {
	MonCmd.AddCommand(RestoreQuorum)
}
07070100000010000081A4000000000000000000000001680F0E8800000745000000000000000000000000000000000000003100000000kubectl-rook-ceph-0.9.4/cmd/commands/operator.go/*
Copyright 2023 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 (
	k8sutil "github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/spf13/cobra"
)

// OperatorCmd represents the operator commands
var OperatorCmd = &cobra.Command{
	Use:                "operator",
	Short:              "Calls subcommands like `restart`  and `set <key> <value>` to update  rook-ceph-operator-config configmap",
	DisableFlagParsing: true,
	Args:               cobra.ExactArgs(1),
}

var restartCmd = &cobra.Command{
	Use:   "restart",
	Short: "Restart rook-ceph-operator pod",
	Args:  cobra.NoArgs,
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
	Run: func(cmd *cobra.Command, _ []string) {
		k8sutil.RestartDeployment(cmd.Context(), clientSets.Kube, operatorNamespace, "rook-ceph-operator")
	},
}

var setCmd = &cobra.Command{
	Use:     "set",
	Short:   "Set the property in the rook-ceph-operator-config configmap.",
	Example: "kubectl rook-ceph operator set <KEY> <VALUE>",
	Args:    cobra.ExactArgs(2),
	Run: func(cmd *cobra.Command, args []string) {
		k8sutil.UpdateConfigMap(cmd.Context(), clientSets.Kube, operatorNamespace, "rook-ceph-operator-config", args[0], args[1])
	},
}

func init() {
	OperatorCmd.AddCommand(restartCmd)
	OperatorCmd.AddCommand(setCmd)
}
07070100000011000081A4000000000000000000000001680F0E8800000564000000000000000000000000000000000000002E00000000kubectl-rook-ceph-0.9.4/cmd/commands/rados.go/*
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 (
	"github.com/rook/kubectl-rook-ceph/pkg/exec"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	"github.com/spf13/cobra"
)

// RadosCmd represents the rados command
var RadosCmd = &cobra.Command{
	Use:                "rados",
	Short:              "call a 'rados' CLI command with arbitrary args",
	DisableFlagParsing: true,
	Args:               cobra.MinimumNArgs(1),
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
	Run: func(cmd *cobra.Command, args []string) {
		logging.Info("running 'rados' command with args: %v", args)
		_, err := exec.RunCommandInOperatorPod(cmd.Context(), clientSets, cmd.Use, args, operatorNamespace, cephClusterNamespace, false)
		if err != nil {
			logging.Fatal(err)
		}
	},
}
07070100000012000081A4000000000000000000000001680F0E880000056E000000000000000000000000000000000000003000000000kubectl-rook-ceph-0.9.4/cmd/commands/radosgw.go/*
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 (
	"github.com/rook/kubectl-rook-ceph/pkg/exec"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	"github.com/spf13/cobra"
)

// RadosgwCmd represents the radosgw command
var RadosgwCmd = &cobra.Command{
	Use:                "radosgw-admin",
	Short:              "call a 'radosgw-admin' CLI command",
	DisableFlagParsing: true,
	Args:               cobra.MinimumNArgs(1),
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
	Run: func(cmd *cobra.Command, args []string) {
		logging.Info("running 'radosgw-admin' command with args: %v", args)
		_, err := exec.RunCommandInOperatorPod(cmd.Context(), clientSets, cmd.Use, args, operatorNamespace, cephClusterNamespace, false)
		if err != nil {
			logging.Fatal(err)
		}
	},
}
07070100000013000081A4000000000000000000000001680F0E880000066E000000000000000000000000000000000000002C00000000kubectl-rook-ceph-0.9.4/cmd/commands/rbd.go/*
Copyright 2023 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 (
	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"
)

// RbdCmd represents the rbd command
var RbdCmd = &cobra.Command{
	Use:                "rbd",
	Short:              "call a 'rbd' CLI command with arbitrary args",
	DisableFlagParsing: true,
	Args:               cobra.MinimumNArgs(1),
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
	Run: func(cmd *cobra.Command, args []string) {
		_, err := exec.RunCommandInOperatorPod(cmd.Context(), clientSets, cmd.Use, args, operatorNamespace, cephClusterNamespace, false)
		if err != nil {
			logging.Fatal(err)
		}
	},
}

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)
}
07070100000014000081A4000000000000000000000001680F0E8800000595000000000000000000000000000000000000003000000000kubectl-rook-ceph-0.9.4/cmd/commands/restore.go/*
Copyright 2023 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 (
	"github.com/rook/kubectl-rook-ceph/pkg/crds"
	"github.com/rook/kubectl-rook-ceph/pkg/restore"
	"github.com/spf13/cobra"
)

// RestoreCmd represents the restore commands
var RestoreCmd = &cobra.Command{
	Use:     "restore-deleted",
	Short:   "Restores a CR that was accidentally deleted and is still in terminating state.",
	Args:    cobra.RangeArgs(1, 2),
	Example: "kubectl rook-ceph restore-deleted <CRD> [CR_Name]",
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
	Run: func(cmd *cobra.Command, args []string) {
		customResources := []restore.CustomResource{}
		restore.RestoreCrd(cmd.Context(), clientSets, operatorNamespace, cephClusterNamespace, crds.CephRookIoGroup, crds.CephRookResourcesVersion, "rook-ceph-operator", customResources, args)
	},
}
07070100000015000081A4000000000000000000000001680F0E8800000B9E000000000000000000000000000000000000002D00000000kubectl-rook-ceph-0.9.4/cmd/commands/rook.go/*
Copyright 2023 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 (
	"fmt"
	"strconv"
	"strings"

	"github.com/rook/kubectl-rook-ceph/pkg/exec"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	"github.com/rook/kubectl-rook-ceph/pkg/rook"
	"github.com/spf13/cobra"
)

// RookCmd represents the rook commands
var RookCmd = &cobra.Command{
	Use:   "rook",
	Short: "Calls subcommands like `version`, `purge-osd, status` and etc.",
	Args:  cobra.ExactArgs(1),
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Prints rook version",
	Args:  cobra.NoArgs,
	Run: func(cmd *cobra.Command, _ []string) {
		_, err := exec.RunCommandInOperatorPod(cmd.Context(), clientSets, "rook", []string{cmd.Use}, operatorNamespace, cephClusterNamespace, false)
		if err != nil {
			logging.Fatal(err)
		}
	},
}

var purgeCmd = &cobra.Command{
	Use:     "purge-osd",
	Short:   "Permanently remove an OSD from the cluster. Multiple OSDs can be removed in a single command with a comma-separated list of IDs, for example, purge-osd 0,1",
	PreRunE: validateOsdIDs,
	Args:    cobra.ExactArgs(1),
	Example: "kubectl rook-ceph rook purge-osd <OSD_ID>",
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
	Run: func(cmd *cobra.Command, args []string) {
		forceflagValue := cmd.Flag("force").Value.String()
		osdIDs := args[0]
		rook.PurgeOsds(cmd.Context(), clientSets, operatorNamespace, cephClusterNamespace, osdIDs, forceflagValue)
	},
}

var statusCmd = &cobra.Command{
	Use:     "status",
	Short:   "Print the phase and conditions of the CephCluster CR",
	Args:    cobra.MaximumNArgs(1),
	Example: "kubectl rook-ceph rook status [CR_Name]",
	Run: func(cmd *cobra.Command, args []string) {
		rook.PrintCustomResourceStatus(cmd.Context(), clientSets, cephClusterNamespace, args)
	},
}

func init() {
	RookCmd.AddCommand(versionCmd)
	RookCmd.AddCommand(statusCmd)
	RookCmd.AddCommand(purgeCmd)
	statusCmd.PersistentFlags().Bool("json", false, "print status in json format")
	purgeCmd.PersistentFlags().Bool("force", false, "force deletion of OSD(s) even with the risk they still contain data")
}

func validateOsdIDs(cmd *cobra.Command, args []string) error {
	osdIDs := strings.Split(args[0], ",")
	for _, osdID := range osdIDs {
		_, err := strconv.Atoi(osdID)
		if err != nil {
			return fmt.Errorf("invalid ID %s, the OSD ID must be an integer. %v", osdID, err)
		}
	}

	return nil
}
07070100000016000081A4000000000000000000000001680F0E8800001211000000000000000000000000000000000000002D00000000kubectl-rook-ceph-0.9.4/cmd/commands/root.go/*
Copyright 2023 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 (
	"context"
	"fmt"
	"regexp"
	"strings"

	"github.com/rook/kubectl-rook-ceph/pkg/exec"
	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	rookclient "github.com/rook/rook/pkg/client/clientset/versioned"
	"github.com/spf13/cobra"

	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/dynamic"
	k8s "k8s.io/client-go/kubernetes"
	_ "k8s.io/client-go/plugin/pkg/client/auth"
	"k8s.io/client-go/tools/clientcmd"
)

var (
	kubeConfig           string
	operatorNamespace    string
	cephClusterNamespace string
	kubeContext          string
	clientSets           *k8sutil.Clientsets
)

// rookCmd represents the rook command
var RootCmd = &cobra.Command{
	Use:              "rook-ceph",
	Short:            "kubectl rook-ceph provides common management and troubleshooting tools for Ceph.",
	Args:             cobra.MinimumNArgs(1),
	TraverseChildren: true,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		if cephClusterNamespace != "" && operatorNamespace == "" {
			operatorNamespace = cephClusterNamespace
		}
		clientSets = getClientsets(cmd.Context())
		preValidationCheck(cmd.Context(), clientSets)
	},
}

func init() {
	// Define your flags and configuration settings.
	RootCmd.PersistentFlags().StringVar(&kubeConfig, "kubeconfig", "", "kubernetes config path")
	RootCmd.PersistentFlags().StringVar(&operatorNamespace, "operator-namespace", "", "Kubernetes namespace where rook operator is running")
	RootCmd.PersistentFlags().StringVarP(&cephClusterNamespace, "namespace", "n", "rook-ceph", "Kubernetes namespace where CephCluster is created")
	RootCmd.PersistentFlags().StringVar(&kubeContext, "context", "", "Kubernetes context to use")
}

func getClientsets(ctx context.Context) *k8sutil.Clientsets {
	var err error

	clientsets := &k8sutil.Clientsets{}

	congfigOverride := &clientcmd.ConfigOverrides{}
	if kubeContext != "" {
		congfigOverride = &clientcmd.ConfigOverrides{CurrentContext: kubeContext}
	}

	// 1. Create Kubernetes Client
	kubeconfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
		clientcmd.NewDefaultClientConfigLoadingRules(),
		congfigOverride,
	)

	clientsets.KubeConfig, err = kubeconfig.ClientConfig()
	if err != nil {
		logging.Fatal(err)
	}

	clientsets.Rook, err = rookclient.NewForConfig(clientsets.KubeConfig)
	if err != nil {
		logging.Fatal(err)
	}

	clientsets.Kube, err = k8s.NewForConfig(clientsets.KubeConfig)
	if err != nil {
		logging.Fatal(err)
	}

	clientsets.Dynamic, err = dynamic.NewForConfig(clientsets.KubeConfig)
	if err != nil {
		logging.Fatal(err)
	}

	return clientsets
}

func preValidationCheck(ctx context.Context, k8sclientset *k8sutil.Clientsets) {
	_, err := k8sclientset.Kube.CoreV1().Namespaces().Get(ctx, operatorNamespace, v1.GetOptions{})
	if err != nil {
		logging.Fatal(fmt.Errorf("operator namespace '%s' does not exist. %v", operatorNamespace, err))
	}
	_, err = k8sclientset.Kube.CoreV1().Namespaces().Get(ctx, cephClusterNamespace, v1.GetOptions{})
	if err != nil {
		logging.Fatal(fmt.Errorf("cephCluster namespace '%s' does not exist. %v", cephClusterNamespace, err))
	}
}

func verifyOperatorPodIsRunning(ctx context.Context, k8sclientset *k8sutil.Clientsets) {
	rookVersionOutput, err := exec.RunCommandInOperatorPod(ctx, k8sclientset, "rook", []string{"version"}, operatorNamespace, cephClusterNamespace, true)
	if err != nil {
		logging.Fatal(err, "failed to get rook version")
	}
	rookVersion := trimGoVersionFromRookVersion(rookVersionOutput)
	if strings.Contains(rookVersion, "alpha") || strings.Contains(rookVersion, "beta") {
		logging.Warning("rook version '%s' is running a pre-release version of Rook.", rookVersion)
		fmt.Println()
	}
}

func trimGoVersionFromRookVersion(rookVersion string) string {
	re := regexp.MustCompile("(?m)[\r\n]+^.*go: go.*$") // remove the go version from the output
	rookVersion = re.ReplaceAllString(rookVersion, "")
	rookVersion = strings.TrimSpace(rookVersion) // remove any trailing newlines

	return rookVersion
}
07070100000017000081A4000000000000000000000001680F0E88000004E1000000000000000000000000000000000000003200000000kubectl-rook-ceph-0.9.4/cmd/commands/root_test.go/*
Copyright 2023 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 "testing"

func Test_trimGoVersionFromRookVersion(t *testing.T) {
	type args struct {
		rookVersion string
	}

	sampleRookVersion := `rook: v1.11.0-alpha.0.420.gd9a17691c
go: go1.19.10s`
	tests := []struct {
		name string
		args args
		want string
	}{
		{
			name: "trim go version from rook version",
			args: args{rookVersion: sampleRookVersion},
			want: "rook: v1.11.0-alpha.0.420.gd9a17691c",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := trimGoVersionFromRookVersion(tt.args.rookVersion); got != tt.want {
				t.Errorf("trimGoVersionFromRookVersion() = %v, want %v", got, tt.want)
			}
		})
	}
}
07070100000018000081A4000000000000000000000001680F0E880000074F000000000000000000000000000000000000003200000000kubectl-rook-ceph-0.9.4/cmd/commands/subvolume.go/*
Copyright 2023 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 (
	subvolume "github.com/rook/kubectl-rook-ceph/pkg/filesystem"
	"github.com/spf13/cobra"
)

var SubvolumeCmd = &cobra.Command{
	Use:   "subvolume",
	Short: "manages stale subvolumes",
	PreRun: func(cmd *cobra.Command, args []string) {
		verifyOperatorPodIsRunning(cmd.Context(), clientSets)
	},
	Args: cobra.ExactArgs(1),
}

var listCmd = &cobra.Command{
	Use:   "ls",
	Short: "Print the list of subvolumes.",
	Run: func(cmd *cobra.Command, args []string) {
		ctx := cmd.Context()
		staleSubvol, _ := cmd.Flags().GetBool("stale")
		subvolume.List(ctx, clientSets, operatorNamespace, cephClusterNamespace, staleSubvol)
	},
}

var deleteCmd = &cobra.Command{
	Use:     "delete",
	Short:   "Deletes a stale subvolume.",
	Args:    cobra.RangeArgs(2, 3),
	Example: "kubectl rook-ceph delete <filesystem> <subvolume> [subvolumegroup]",
	Run: func(cmd *cobra.Command, args []string) {
		ctx := cmd.Context()
		fs := args[0]
		subvol := args[1]
		svg := "csi"
		if len(args) > 2 {
			svg = args[2]
		}
		subvolume.Delete(ctx, clientSets, operatorNamespace, cephClusterNamespace, fs, subvol, svg)
	},
}

func init() {
	SubvolumeCmd.AddCommand(listCmd)
	SubvolumeCmd.PersistentFlags().Bool("stale", false, "List only stale subvolumes")
	SubvolumeCmd.AddCommand(deleteCmd)
}
07070100000019000081A4000000000000000000000001680F0E880000049C000000000000000000000000000000000000002400000000kubectl-rook-ceph-0.9.4/cmd/main.go/*
Copyright 2023 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 main

import (
	command "github.com/rook/kubectl-rook-ceph/cmd/commands"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
)

func main() {
	addcommands()
	err := command.RootCmd.Execute()
	if err != nil {
		logging.Fatal(err)
	}
}

func addcommands() {
	command.RootCmd.AddCommand(
		command.CephCmd,
		command.MonCmd,
		command.RbdCmd,
		command.OperatorCmd,
		command.RookCmd,
		command.MaintenanceCmd,
		command.Health,
		command.DrCmd,
		command.RestoreCmd,
		command.DestroyClusterCmd,
		command.SubvolumeCmd,
		command.RadosCmd,
		command.FlattenRBDPVCCmd,
		command.RadosgwCmd,
	)
}
0707010000001A000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000001D00000000kubectl-rook-ceph-0.9.4/docs0707010000001B000081A4000000000000000000000001680F0E880000095A000000000000000000000000000000000000002500000000kubectl-rook-ceph-0.9.4/docs/ceph.md# Ceph

This used to run any ceph cli command with with arbitrary args.

## Examples

```bash
kubectl rook-ceph ceph status

#   cluster:
#     id:     b74c18dd-6ee3-44fe-90b5-ed12feac46a4
#     health: HEALTH_OK
#
#   services:
#     mon: 3 daemons, quorum a,b,c (age 62s)
#     mgr: a(active, since 23s)
#     osd: 1 osds: 1 up (since 12s), 1 in (since 30s)
#
#   data:
#     pools:   0 pools, 0 pg
#     objects: 0 objects, 0 B
#     usage:   0 B used, 0 B / 0 B avail
#     pgs:
```

This also supports all the ceph supported flags like `--format json-pretty`

```bash
kubectl rook-ceph ceph status --format json-pretty

# {
#     "fsid": "b74c18dd-6ee3-44fe-90b5-ed12feac46a4",
#     "health": {
#         "status": "HEALTH_OK",
#         "checks": {},
#         "mutes": []
#     },
#     "election_epoch": 12,
#     "quorum": [
#         0,
#         1,
#         2
#     ],
#     "quorum_names": [
#         "a",
#         "b",
#         "c"
#     ],
#     "quorum_age": 67,
#     "monmap": {
#         "epoch": 3,
#         "min_mon_release_name": "quincy",
#         "num_mons": 3
#     },
#     "osdmap": {
#         "epoch": 13,
#         "num_osds": 1,
#         "num_up_osds": 1,
#         "osd_up_since": 1663145830,
#         "num_in_osds": 1,
#         "osd_in_since": 1663145812,
#         "num_remapped_pgs": 0
#     },
#     "pgmap": {
#         "pgs_by_state": [],
#         "num_pgs": 0,
#         "num_pools": 0,
#         "num_objects": 0,
#         "data_bytes": 0,
#         "bytes_used": 0,
#         "bytes_avail": 0,
#         "bytes_total": 0
#     },
#     "fsmap": {
#         "epoch": 1,
#         "by_rank": [],
#         "up:standby": 0
#     },
#     "mgrmap": {
#         "available": false,
#         "num_standbys": 0,
#         "modules": [
#             "dashboard",
#             "iostat",
#             "nfs",
#             "prometheus",
#             "restful"
#         ],
#         "services": {}
#     },
#     "servicemap": {
#         "epoch": 1,
#         "modified": "2022-09-14T08:55:39.603658+0000",
#         "services": {}
#     },
#     "progress_events": {}
# }
```

## Daemon

Run the Ceph daemon command by connecting to its admin socket.

```bash
kubectl rook-ceph ceph daemon osd.0 dump_historic_ops

Info: running 'ceph' command with args: [daemon osd.0 dump_historic_ops]
{
    "size": 20,
    "duration": 600,
    "ops": []
}
```
0707010000001C000081A4000000000000000000000001680F0E8800000ADF000000000000000000000000000000000000002400000000kubectl-rook-ceph-0.9.4/docs/crd.md# Restoring Deleted CRs

When a Rook CR is deleted, the Rook operator will respond to the deletion event to attempt to clean up the cluster resources. If any data is still present in the cluster, Rook will refuse to delete the CR to ensure data is not lost. The operator will refuse to remove the finalizer on the CR until the underlying data is deleted.

While the underlying Ceph data and daemons continue to be available, the CRs will be stuck indefinitely in a Deleting state in which the operator will not continue to ensure cluster health. Upgrades will be blocked, further updates to the CRs are prevented, and so on. Since Kubernetes does not allow undeleting resources, the command below will allow repairing the CRs without even necessarily suffering cluster downtime.

> [!NOTE]
> If there are multiple deleted resources in the cluster and no specific resource is mentioned, the first resource will be restored. To restore all deleted resources, re-run the command multiple times.

## restore-deleted Command

The `restore-deleted` command has one required and one optional parameter:

- `<CRD>`: The CRD type that is to be restored, such as CephClusters, CephFilesystems, CephBlockPools and so on.
- `[CRName]`: The name of the specific CR which you want to restore since there can be multiple instances under the same CRD. For example, if there are multiple CephFilesystems stuck in deleting state, a specific filesystem can be restored: `restore-deleted cephfilesystems filesystem-2`.

```bash
kubectl rook-ceph restore-deleted <CRD> [CRName]
```

## CephClusters Restore Example

```bash
kubectl rook-ceph restore-deleted cephclusters

Info: Detecting which resources to restore for crd "cephclusters"

Info: Restoring CR my-cluster
Warning: The resource my-cluster was found deleted. Do you want to restore it? yes | no

Info: skipped prompt since ROOK_PLUGIN_SKIP_PROMPTS=true
Info: Proceeding with restoring deleting CR
Info: Scaling down the operator
Info: Deleting validating webhook rook-ceph-webhook if present
Info: Removing ownerreferences from resources with matching uid 92c0e549-44fd-43db-80ba-5473db996208
Info: Removing owner references for secret cluster-peer-token-my-cluster
Info: Removed ownerReference for Secret: cluster-peer-token-my-cluster

Info: Removing owner references for secret rook-ceph-admin-keyring
Info: Removed ownerReference for Secret: rook-ceph-admin-keyring

---
---
---

Info: Removing owner references for deployment rook-ceph-osd-0
Info: Removed ownerReference for deployment: rook-ceph-osd-0

Info: Removing finalizers from cephclusters/my-cluster
Info: Re-creating the CR cephclusters from dynamic resource
Info: Scaling up the operator
Info: CR is successfully restored. Please watch the operator logs and check the crd
```
0707010000001D000081A4000000000000000000000001680F0E8800000E00000000000000000000000000000000000000003000000000kubectl-rook-ceph-0.9.4/docs/destroy-cluster.md# Destroying a Cluster

When a cluster is no longer needed and needs to be torn down, Rook has a [Cleanup guide](https://rook.io/docs/rook/latest/Getting-Started/ceph-teardown/) with instructions to tear it down cleanly. While following that document is highly preferred, there is a command that will automate the cleanup of Rook after applications are removed.
The `destroy-cluster` command destroys a Rook cluster and deletes CRs (custom resources) by force removing any finalizers that may be preventing the cleanup.

## !!! Warning !!!
**This command is not reversible**, and it will destroy your Rook cluster completely with guaranteed data loss.
Only use this command if you are 100% sure that the cluster and its data should be destroyed.

## `destroy-cluster` command

To destroy a cluster, run the command:
```bash
$ kubectl rook-ceph destroy-cluster
Warning: Are you sure you want to destroy the cluster in namespace "rook-ceph"? If absolutely certain, enter: yes-really-destroy-cluster
```

Any other response will cause the command to abort.

## Example of destroying a cluster
```bash
$ kubectl rook-ceph -n rook-ceph destroy-cluster
Warning: Are you sure you want to destroy the cluster in namespace "rook-ceph"? If absolutely certain, enter: yes-really-destroy-cluster
yes-really-destroy-cluster
Info: proceeding
Info: getting resource kind cephclusters
Info: removing resource cephclusters: my-cluster
Info: resource "my-cluster" is not yet deleted, applying patch to remove finalizer...
Info: resource my-cluster was deleted
Info: getting resource kind cephblockpoolradosnamespaces
Info: resource cephblockpoolradosnamespaces was not found on the cluster
Info: getting resource kind cephblockpools
Info: removing resource cephblockpools: builtin-mgr
Info: resource builtin-mgr was deleted
Info: getting resource kind cephbucketnotifications
Info: resource cephbucketnotifications was not found on the cluster
Info: getting resource kind cephbuckettopics
Info: resource cephbuckettopics was not found on the cluster
Info: getting resource kind cephclients
Info: resource cephclients was not found on the cluster
Info: getting resource kind cephcosidrivers
Info: resource cephcosidrivers was not found on the cluster
Info: getting resource kind cephfilesystemmirrors
Info: resource cephfilesystemmirrors was not found on the cluster
Info: getting resource kind cephfilesystems
Info: removing resource cephfilesystems: myfs
Info: resource myfs was deleted
Info: getting resource kind cephfilesystemsubvolumegroups
Info: removing resource cephfilesystemsubvolumegroups: myfs-csi
Info: resource myfs-csi was deleted
Info: getting resource kind cephnfses
Info: resource cephnfses was not found on the cluster
Info: getting resource kind cephobjectrealms
Info: resource cephobjectrealms was not found on the cluster
Info: getting resource kind cephobjectstores
Info: removing resource cephobjectstores: my-store
Info: resource my-store was deleted
Info: getting resource kind cephobjectstoreusers
Info: resource cephobjectstoreusers was not found on the cluster
Info: getting resource kind cephobjectzonegroups
Info: resource cephobjectzonegroups was not found on the cluster
Info: getting resource kind cephobjectzones
Info: resource cephobjectzones was not found on the cluster
Info: getting resource kind cephrbdmirrors
Info: resource cephrbdmirrors was not found on the cluster
Info: removing deployment rook-ceph-tools
Info: waiting to clean up resources
Info: 1 pods still alive, removing....
Info: pod rook-ceph-mds-myfs-b-58cf7bcbb7-d6rc4 still a live
Info: done
```0707010000001E000081A4000000000000000000000001680F0E8800000547000000000000000000000000000000000000002A00000000kubectl-rook-ceph-0.9.4/docs/dr-health.md# Disaster Recovery

## Health

The DR health command is used to get the connection status of one cluster from another cluster in mirroring-enabled clusters. The cephblockpool is queried with mirroring-enabled and If not found will exit with relevant logs. Optionally, args can be passed to be appended to `ceph status`, for example: `--debug-ms 1`.

Example: `kubectl rook-ceph dr health [ceph status args]`

```bash
kubectl rook-ceph dr health

# Info: running ceph status from other cluster details
#   cluster:
#     id:     32261f66-1qw2e-48bb-ae4e-d8de080714ca
#     health: HEALTH_WARN
#             clock skew detected on mon.b, mon.c

#   services:
#     mon:        3 daemons, quorum a,b,c (age 2h)
#     mgr:        a(active, since 2h)
#     mds:        1/1 daemons up, 1 hot standby
#     osd:        3 osds: 3 up (since 2h), 3 in (since 8d)
#     rbd-mirror: 1 daemon active (1 hosts)
#     rgw:        1 daemon active (1 hosts, 1 zones)

#   data:
#     volumes: 1/1 healthy
#     pools:   11 pools, 321 pgs
#     objects: 931 objects, 1.4 GiB
#     usage:   4.3 GiB used, 1.5 TiB / 1.5 TiB avail
#     pgs:     321 active+clean

#   io:
#     client:   45 KiB/s rd, 156 KiB/s wr, 55 op/s rd, 21 op/s wr

# Info: running mirroring daemon health
# health: OK
# daemon health: OK
# image health: OK
# images: 4 total
#     4 replaying
```
0707010000001F000081A4000000000000000000000001680F0E88000001DE000000000000000000000000000000000000003000000000kubectl-rook-ceph-0.9.4/docs/flatten-rbd-pvc.md# Flatten RBD PVC

`flatten-rbd-pvc` command is to flatten the RBD image corresponding to the target RBD PVC.
Fore more details about flatten, see [the Ceph official document](https://docs.ceph.com/en/latest/rbd/rbd-snapshot/#flattening-a-cloned-image).

By flattening RBD images, we can bypass the problems specific to non-flattened cloned image like https://github.com/ceph/ceph-csi/discussions/4360.

## Examples.

```bash
kubectl rook-ceph flatten-rbd-pvc rbd-pvc-clone
```
07070100000020000081A4000000000000000000000001680F0E8800000CBE000000000000000000000000000000000000002700000000kubectl-rook-ceph-0.9.4/docs/health.md# Health

Health command check health of the cluster and common configuration issues. Health command currently validates these things configurations (let us know if you would like to add other validation in health command):

1. at least three mon pods should running on different nodes
2. mon quorum and ceph health details
3. at least three osd pods should running on different nodes
4. all pods 'Running' status
5. placement group status
6. at least one mgr pod is running

Health commands logs have three ways of logging:

1. `Info`: This is just a logging information for the users.
2. `Warning`: which mean there is some improvement required in the cluster.
3. `Error`: This requires immediate user attention to get the cluster in healthy state.

## Output

```bash
kubectl rook-ceph health

# Info:  Checking if at least three mon pods are running on different nodes
# Warning:  At least three mon pods should running on different nodes
# rook-ceph-mon-a-5988949b9f-kfshx                1/1     Running       0          26s
# rook-ceph-mon-a-debug-6bc9d99979-4q2hd          1/1     Terminating   0          32s
# rook-ceph-mon-b-69c8cb6d85-vg6js                1/1     Running       0          2m29s
# rook-ceph-mon-c-6f6754bff5-746rp                1/1     Running       0          2m18s
#
# Info:  Checking mon quorum and ceph health details
# Warning:  HEALTH_WARN 1/3 mons down, quorum b,c
# [WRN] MON_DOWN: 1/3 mons down, quorum b,c
#     mon.a (rank 0) addr [v2:10.98.95.196:3300/0,v1:10.98.95.196:6789/0] is down (out of quorum)
#
# Info:  Checking if at least three osd pods are running on different nodes
# Warning:  At least three osd pods should running on different nodes
# rook-ceph-osd-0-debug-6f6f5496d8-m2nbp          1/1     Terminating   0          19s
#
# Info:  Pods that are in 'Running' status
# NAME                                            READY   STATUS        RESTARTS   AGE
# csi-cephfsplugin-provisioner-5f978bdb5b-7hbtr   5/5     Running       0          3m
# csi-cephfsplugin-vjl4c                          2/2     Running       0          3m
# csi-rbdplugin-cwkc2                             2/2     Running       0          3m
# csi-rbdplugin-provisioner-578f847bc-2j9ct       5/5     Running       0          3m
# rook-ceph-mgr-a-7b78b4b4b8-ndpmt                1/1     Running       0          2m7s
# rook-ceph-mon-a-5988949b9f-kfshx                1/1     Running       0          28s
# rook-ceph-mon-a-debug-6bc9d99979-4q2hd          1/1     Terminating   0          34s
# rook-ceph-mon-b-69c8cb6d85-vg6js                1/1     Running       0          2m31s
# rook-ceph-mon-c-6f6754bff5-746rp                1/1     Running       0          2m20s
# rook-ceph-operator-78cbdb59bd-4zcsh             1/1     Running       0          62s
# rook-ceph-osd-0-debug-6f6f5496d8-m2nbp          1/1     Terminating   0          19s
#
# Warning:  Pods that are 'Not' in 'Running' status
# NAME                                          READY   STATUS      RESTARTS   AGE
#
# Info:  checking placement group status
# Info:  2 pgs: 2 active+clean; 449 KiB data, 21 MiB used, 14 GiB / 14 GiB avail
#
# Info:  checking if at least one mgr pod is running
# rook-ceph-mgr-a-7b78b4b4b8-ndpmt                Running     fv-az290-487
```
07070100000021000081A4000000000000000000000001680F0E8800000AF7000000000000000000000000000000000000002C00000000kubectl-rook-ceph-0.9.4/docs/maintenance.md# Maintenance Mode

Maintenance mode can be useful when a mon or OSD needs advanced maintenance operations that require the daemon to be stopped. Ceph tools such as `ceph-objectstore-tool`,`ceph-bluestore-tool`, or `ceph-monstore-tool` are commonly used in these scenarios. Maintenance mode will set up the mon or OSD so that these commands can be run.

Maintenance mode will automate the following:

1. Scale down the existing mon or OSD deployment
2. Start a new maintenance deployment where operations can be performed directly against the mon or OSD without that daemon running
   a. The main container sleeps so you can connect and run the ceph commands
   b. Liveness and startup probes are removed
   c. If alternate Image is passed by --alternate-image flag then the new maintenance deployment container will be using alternate Image.

Maintenance mode provides these options:

1. [Start](#start-maintenance-mode) the maintenance deployment for troubleshooting.
2. [Stop](#stop-maintenance-mode) the temporary maintenance deployment
3. Update the resource limits for the deployment pod [advanced option](#advanced-options).

## Start maintenance mode

In this example we are using `mon-a` deployment

```bash
kubectl rook-ceph maintenance start rook-ceph-mon-a

Info: fetching the deployment rook-ceph-mon-a to be running

Info: deployment rook-ceph-mon-a exists

Info: setting maintenance command to main container
Info: deployment rook-ceph-mon-a scaled down

Info: waiting for the deployment pod rook-ceph-mon-a-df79bc6dc-2k8fc to be deleted

Info: ensure the maintenance deployment rook-ceph-mon-a is scaled up

Info: waiting for pod with label "ceph_daemon_type=mon,ceph_daemon_id=a" in namespace "rook-ceph" to be running
Info: pod rook-ceph-mon-a-maintenance-67b9f54944-jmcjj is ready for maintenance operations
```

Now connect to the daemon pod and perform operations:

```console
kubectl exec <maintenance-pod> -- <ceph command>
```

When finished, stop maintenance mode and restore the original daemon by running the command in the next section.

## Stop maintenance mode

Stop the deployment `mon-b` that is started above example.

```bash
kubectl rook-ceph maintenance stop rook-ceph-mon-b

Info: fetching the deployment rook-ceph-mon-a-maintenance to be running

Info: deployment rook-ceph-mon-a-maintenance exists

Info: removing maintenance mode from deployment rook-ceph-mon-a-maintenance

Info: Successfully deleted maintenance deployment and restored deployment "rook-ceph-mon-a"
```

## Advanced Options

If you need to update the limits and requests of the maintenance deployment that is created using maintenance command you can run:

>```console
>kubectl set resources deployment rook-ceph-osd-${osdid}-maintenance --limits=cpu=8,memory=64Gi --requests=cpu=8,memory=64Gi
>```
07070100000022000081A4000000000000000000000001680F0E880000175C000000000000000000000000000000000000002500000000kubectl-rook-ceph-0.9.4/docs/mons.md# Mon Commands

## Print Mon Endpoints

This is used to print mon endpoints.

```bash
kubectl rook-ceph mons

# 10.98.95.196:6789,10.106.118.240:6789,10.111.18.121:6789
```

## Restore Quorum

Mon quorum is critical to the Ceph cluster. If majority of mons are not in quorum,
the cluster will be down. If the majority of mons are also lost permanently,
the quorum will need to be restore to a remaining good mon in order to bring
the Ceph cluster up again.

To restore the quorum in this disaster scenario:

1. Identify that mon quorum is lost. Some indications include:
   - The Rook operator log shows timeout errors and continuously fails to reconcile
   - All commands in the toolbox are unresponsive
   - Multiple mon pods are likely down
2. Identify which mon has good state.
   - Exec to a mon pod and run the following command
     - `ceph daemon mon.<name> mon_status`
     - For example, if connecting to mon.a, run: `ceph daemon mon.a mon_status`
   - If multiple mons respond, find the mon with the highest `election_epoch`
3. Start the toolbox pod if not already running
4. Run the command below to restore quorum to that good mon
5. Follow the prompts to confirm that you want to continue with each critical step of the restore
6. The final prompt will be to restart the operator, which will add new mons to restore the full quorum size

In this example, quorum is restored to mon **c**.

```bash
kubectl rook-ceph mons restore-quorum c
```

Before the restore proceeds, you will be prompted if you want to continue.
For example, here is the output in a test cluster up to the point of starting the restore.

```bash
$ kubectl rook-ceph mons restore-quorum c

Info: mon c state is leader
mon=b, endpoint=192.168.64.168:6789
mon=c, endpoint=192.168.64.167:6789
mon=a, endpoint=192.168.64.169:6789
Info: Check for the running toolbox
Info: Waiting for the pod from deployment "rook-ceph-tools" to be running
deployment.apps/rook-ceph-tools condition met

Warning: Restoring mon quorum to mon c (192.168.64.167)
Info: The mons to discard are: b a
Info: Are you sure you want to restore the quorum to mon "c"? If so, enter: yes-really-restore
```

After entering `yes-really-restore`, the restore continues with output as such:

```bash
Info: proceeding with resorting quorum
Info: Waiting for operator pod to stop
Info: rook-ceph-operator deployment scaled down
Info: Waiting for bad mon pod to stop
Info: deployment.apps/rook-ceph-mon-c scaled

Info: deployment.apps/rook-ceph-mon-a scaled

Info: fetching the deployment rook-ceph-mon-b to be running

Info: deployment rook-ceph-mon-b exists

Info: setting maintenance command to main container
Info: deployment rook-ceph-mon-b scaled down

Info: waiting for the deployment pod rook-ceph-mon-b-6cf85df489-l2lf4 to be deleted

Info: ensure the maintenance deployment rook-ceph-mon-b is scaled up

Info: waiting for pod with label "ceph_daemon_type=mon,ceph_daemon_id=b" in namespace "openshift-storage" to be running
Info: pod rook-ceph-mon-b-maintenance-5844bddbd7-k4cdk is ready for maintenance operations
Info: fetching the deployment rook-ceph-mon-b-maintenance to be running

Info: deployment rook-ceph-mon-b-maintenance exists

Info: Started maintenance pod, restoring the mon quorum in the maintenance pod
Info: Extracting the monmap


# Lengthy rocksdb output removed

Info: Finished updating the monmap!
Info: Printing final monmap
monmaptool: monmap file /tmp/monmap
epoch 3
fsid 4d32410e-fee1-4b0a-bc80-7f395fc43136
last_changed 2024-02-27T15:42:56.748095+0000
created 2024-02-27T15:42:03.020653+0000
min_mon_release 17 (quincy)
election_strategy: 1
0: v2:172.30.14.162:3300/0 mon.b
Info: Restoring the mons in the rook-ceph-mon-endpoints configmap to the good mon
Info: Stopping the maintenance pod for mon b.

Info: fetching the deployment rook-ceph-mon-b-maintenance to be running

Info: deployment rook-ceph-mon-b-maintenance exists

Info: removing maintenance mode from deployment rook-ceph-mon-b-maintenance

Info: Successfully deleted maintenance deployment and restored deployment "rook-ceph-mon-b"
Info: Check that the restored mon is responding
Error: failed to get the status of ceph cluster. failed to run command. failed to run command. command terminated with exit code 1
Info: 1: waiting for ceph status to confirm single mon quorum.

Info: current ceph status output

Info: sleeping for 5 seconds

Info: 10: waiting for ceph status to confirm single mon quorum.

Info: current ceph status output   cluster:
   id:     4d32410e-fee1-4b0a-bc80-7f395fc43136
   health: HEALTH_ERR
            1 filesystem is offline
            1 filesystem is online with fewer MDS than max_mds

   services:
     mon: 1 daemons, quorum b (age 93s)
     mgr: a(active, since 7m)
     mds: 0/0 daemons up
     osd: 3 osds: 3 up (since 6m), 3 in (since 7m)

   data:
     volumes: 1/1 healthy
     pools:   4 pools, 113 pgs
     objects: 9 objects, 580 KiB
     usage:   32 MiB used, 1.5 TiB / 1.5 TiB avail
     pgs:     113 active+clean



Info: sleeping for 5 seconds

Info: finished waiting for ceph status   cluster:
   id:     4d32410e-fee1-4b0a-bc80-7f395fc43136
   health: HEALTH_OK

   services:
     mon: 1 daemons, quorum b (age 101s)
     mgr: a(active, since 7m)
     mds: 1/1 daemons up
     osd: 3 osds: 3 up (since 6m), 3 in (since 7m)

   data:
     volumes: 1/1 healthy
     pools:   4 pools, 113 pgs
     objects: 31 objects, 582 KiB
     usage:   32 MiB used, 1.5 TiB / 1.5 TiB avail
     pgs:     113 active+clean

   io:
     client:   1.1 KiB/s wr, 0 op/s rd, 3 op/s wr

Info: Purging the bad mons [c a]

Info: purging bad mon: c

Info: purging bad mon: a

Info: Mon quorum was successfully restored to mon b

Info: Only a single mon is currently running
Info: Enter 'continue' to start the operator and expand to full mon quorum again
```

After reviewing that the cluster is healthy with a single mon, press Enter to continue:

```bash
continue
Info: proceeding with resorting quorum
```
07070100000023000081A4000000000000000000000001680F0E8800000253000000000000000000000000000000000000002900000000kubectl-rook-ceph-0.9.4/docs/operator.md# Operator

Operator is parent command which requires sub-command. Currently, operator supports these sub-commands:

1. `restart`: [restart](#restart) the Rook-Ceph operator
2. `set <property> <value>` : [set](#set) the property in the rook-ceph-operator-config configmap.

## Restart

Restart the Rook-Ceph operator.

```bash
kubectl rook-ceph operator restart

# deployment.apps/rook-ceph-operator restarted
```

## Set

Set the property in the rook-ceph-operator-config configmap

```bash
kubectl rook-ceph operator set ROOK_LOG_LEVEL DEBUG

# configmap/rook-ceph-operator-config patched
```
07070100000024000081A4000000000000000000000001680F0E8800000576000000000000000000000000000000000000002600000000kubectl-rook-ceph-0.9.4/docs/rados.md# Rados

This used to run any rados cli command with with arbitrary args.

## Examples

```bash
kubectl rook-ceph rados df

# POOL_NAME     USED  OBJECTS  CLONES  COPIES  MISSING_ON_PRIMARY  UNFOUND  DEGRADED  RD_OPS      RD  WR_OPS       WR  USED COMPR  UNDER COMPR
# .mgr       452 KiB        2       0       2                   0        0         0      22  18 KiB      14  262 KiB         0 B          0 B

# total_objects    2
# total_used       27 MiB
# total_avail      10 GiB
# total_space      10 GiB
```

This also supports all the rados supported flags like `--format json-pretty`

```bash
kubectl rook-ceph rados df --format json-pretty

# {
#     "pools": [
#         {
#             "name": ".mgr",
#             "id": 1,
#             "size_bytes": 462848,
#             "size_kb": 452,
#             "num_objects": 2,
#             "num_object_clones": 0,
#             "num_object_copies": 2,
#             "num_objects_missing_on_primary": 0,
#             "num_objects_unfound": 0,
#             "num_objects_degraded": 0,
#             "read_ops": 22,
#             "read_bytes": 18432,
#             "write_ops": 14,
#             "write_bytes": 268288,
#             "compress_bytes_used": 0,
#             "compress_under_bytes": 0
#         }
#     ],
#     "total_objects": 2,
#     "total_used": 27404,
#     "total_avail": 10458356,
#     "total_space": 10485760
# }
```
07070100000025000081A4000000000000000000000001680F0E880000017F000000000000000000000000000000000000002E00000000kubectl-rook-ceph-0.9.4/docs/radosgw-admin.md# radosgw-admin

This runs any radosgw-admin CLI command with arbitrary args.

## Examples

```bash
kubectl rook-ceph radosgw-admin user create --display-name="my user" --uid=myuser

# Info: running 'radosgw-admin' command with args: [user create --display-name=my-user --uid=myuser]
# {
#     "user_id": "myuser",
#     "display_name": "my user",
#    ...
#    ...
#    ...
# }
```
07070100000026000081A4000000000000000000000001680F0E88000000B4000000000000000000000000000000000000002400000000kubectl-rook-ceph-0.9.4/docs/rbd.md# RBD

This used to run any rbd cli command with with arbitrary args.

## Example

```bash
kubectl rook-ceph rbd ls replicapool

# csi-vol-427774b4-340b-11ed-8d66-0242ac110004
```
07070100000027000081A4000000000000000000000001680F0E8800001E94000000000000000000000000000000000000002500000000kubectl-rook-ceph-0.9.4/docs/rook.md# Rook

The `rook` command supports the following sub-commands:

1. `purge-osd <osd-id> [--force]` : [purge osd](#purge-an-osd) permanently remove an OSD from the cluster. Multiple OSDs can be removed in a single command with a comma-separated list of IDs.
2. `version`: [version](#version) prints the rook version.
3. `status`: [status](#status) print the phase and conditions of the CephCluster CR
4. `status all`: [status all](#status-all) print the phase and conditions of all CRs
5. `status <CR>`: [status  cr](#status-cr-name) print the phase and conditions of CRs of a specific type, such as 'cephobjectstore', 'cephfilesystem', etc

## Purge OSDs

Permanently remove OSD(s) from the cluster.

!!! warning
    Data loss is possible when passing the --force flag if the PGs are not healthy on other OSDs.

```bash
kubectl rook-ceph rook purge-osd 0 --force

# 2022-09-14 08:58:28.888431 I | rookcmd: starting Rook v1.10.0-alpha.0.164.gcb73f728c with arguments 'rook ceph osd remove --osd-ids=0 --force-osd-removal=true'
# 2022-09-14 08:58:28.889217 I | rookcmd: flag values: --force-osd-removal=true, --help=false, --log-level=INFO, --operator-image=, --osd-ids=0, --preserve-pvc=false, --service-account=
# 2022-09-14 08:58:28.889582 I | op-mon: parsing mon endpoints: b=10.106.118.240:6789
# 2022-09-14 08:58:28.898898 I | cephclient: writing config file /var/lib/rook/rook-ceph/rook-ceph.config
# 2022-09-14 08:58:28.899567 I | cephclient: generated admin config in /var/lib/rook/rook-ceph
# 2022-09-14 08:58:29.421345 I | cephosd: validating status of osd.0
# 2022-09-14 08:58:29.421371 I | cephosd: osd.0 is healthy. It cannot be removed unless it is 'down'
```

Multiple OSDs can be removed in one invocation with a comma-separated list of IDs.

## Version

Print the version of Rook.

```bash
kubectl rook-ceph rook version

#rook: v1.10.0-alpha.0.164.gcb73f728c
#go: go1.18.5
```

## Status

```bash
kubectl rook-ceph rook status

# Info: cephclusters my-cluster
# ceph:
#   capacity:
#     bytesAvailable: 20942778368
#     bytesTotal: 20971520000
#     bytesUsed: 28741632
#     lastUpdated: "2024-01-11T06:43:27Z"
#   fsid: 5a8dc97a-1d21-4c0e-aac2-fdc924e18374
#   health: HEALTH_OK
#   lastChanged: "2024-01-11T05:38:27Z"
#   lastChecked: "2024-01-11T06:43:27Z"
#   previousHealth: HEALTH_ERR
#   versions:
#     mgr:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 1
#     mon:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 1
#     osd:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 1
#     overall:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 3
# conditions:
# - lastHeartbeatTime: "2024-01-11T05:37:46Z"
#   lastTransitionTime: "2024-01-11T05:37:46Z"
#   message: Processing OSD 0 on node "minikube"
#   reason: ClusterProgressing
#   status: "True"
#   type: Progressing
# - lastHeartbeatTime: "2024-01-11T06:43:27Z"
#   lastTransitionTime: "2024-01-11T05:38:27Z"
#   message: Cluster created successfully
#   reason: ClusterCreated
#   status: "True"
#   type: Ready
# message: Cluster created successfully
# observedGeneration: 2
# phase: Ready
# state: Created
# storage:
#   deviceClasses:
#   - name: hdd
#   osd:
#     storeType:
#       bluestore: 1
# version:
#   image: quay.io/ceph/ceph:v18
#   version: 18.2.1-0
```

## Status All

```bash
kubectl rook-ceph rook status all

# Info: cephclusters my-cluster
# ceph:
#   capacity:
#     bytesAvailable: 20942770176
#     bytesTotal: 20971520000
#     bytesUsed: 28749824
#     lastUpdated: "2024-01-11T06:44:28Z"
#   details:
#     POOL_APP_NOT_ENABLED:
#       message: 1 pool(s) do not have an application enabled
#       severity: HEALTH_WARN
#   fsid: 5a8dc97a-1d21-4c0e-aac2-fdc924e18374
#   health: HEALTH_WARN
#   lastChanged: "2024-01-11T06:44:28Z"
#   lastChecked: "2024-01-11T06:44:28Z"
#   previousHealth: HEALTH_OK
#   versions:
#     mds:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 2
#     mgr:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 1
#     mon:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 1
#     osd:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 1
#     overall:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 5
# conditions:
# - lastHeartbeatTime: "2024-01-11T05:37:46Z"
#   lastTransitionTime: "2024-01-11T05:37:46Z"
#   message: Processing OSD 0 on node "minikube"
#   reason: ClusterProgressing
#   status: "True"
#   type: Progressing
# - lastHeartbeatTime: "2024-01-11T06:44:28Z"
#   lastTransitionTime: "2024-01-11T05:38:27Z"
#   message: Cluster created successfully
#   reason: ClusterCreated
#   status: "True"
#   type: Ready
# message: Cluster created successfully
# observedGeneration: 2
# phase: Ready
# state: Created
# storage:
#   deviceClasses:
#   - name: hdd
#   osd:
#     storeType:
#       bluestore: 1
# version:
#   image: quay.io/ceph/ceph:v18
#   version: 18.2.1-0

# Info: resource cephblockpoolradosnamespaces was not found on the cluster
# Info: cephblockpools builtin-mgr
# observedGeneration: 2
# phase: Ready

# Info: resource cephbucketnotifications was not found on the cluster
# Info: resource cephbuckettopics was not found on the cluster
# Info: resource cephclients was not found on the cluster
# Info: resource cephcosidrivers was not found on the cluster
# Info: resource cephfilesystemmirrors was not found on the cluster
# Info: cephfilesystems myfs
# observedGeneration: 2
# phase: Ready

# Info: cephfilesystemsubvolumegroups myfs-csi
# info:
#   clusterID: e1026845ad66577abae1d16671b464c8
# observedGeneration: 1
# phase: Ready

# Info: resource cephnfses was not found on the cluster
# Info: resource cephobjectrealms was not found on the cluster
# Info: resource cephobjectstores was not found on the cluster
# Info: resource cephobjectstoreusers was not found on the cluster
# Info: resource cephobjectzonegroups was not found on the cluster
# Info: resource cephobjectzones was not found on the cluster
# Info: resource cephrbdmirrors was not found on the cluster
```

## Status `<cr-name>`

```bash
kubectl rook-ceph rook status cephclusters

# Info: cephclusters my-cluster
# ceph:
#   capacity:
#     bytesAvailable: 20942778368
#     bytesTotal: 20971520000
#     bytesUsed: 28741632
#     lastUpdated: "2024-01-11T06:43:27Z"
#   fsid: 5a8dc97a-1d21-4c0e-aac2-fdc924e18374
#   health: HEALTH_OK
#   lastChanged: "2024-01-11T05:38:27Z"
#   lastChecked: "2024-01-11T06:43:27Z"
#   previousHealth: HEALTH_ERR
#   versions:
#     mgr:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 1
#     mon:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 1
#     osd:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 1
#     overall:
#       ceph version 18.2.1 (7fe91d5d5842e04be3b4f514d6dd990c54b29c76) reef (stable): 3
# conditions:
# - lastHeartbeatTime: "2024-01-11T05:37:46Z"
#   lastTransitionTime: "2024-01-11T05:37:46Z"
#   message: Processing OSD 0 on node "minikube"
#   reason: ClusterProgressing
#   status: "True"
#   type: Progressing
# - lastHeartbeatTime: "2024-01-11T06:43:27Z"
#   lastTransitionTime: "2024-01-11T05:38:27Z"
#   message: Cluster created successfully
#   reason: ClusterCreated
#   status: "True"
#   type: Ready
# message: Cluster created successfully
# observedGeneration: 2
# phase: Ready
# state: Created
# storage:
#   deviceClasses:
#   - name: hdd
#   osd:
#     storeType:
#       bluestore: 1
# version:
#   image: quay.io/ceph/ceph:v18
#   version: 18.2.1-0
```
07070100000028000081A4000000000000000000000001680F0E8800000804000000000000000000000000000000000000002A00000000kubectl-rook-ceph-0.9.4/docs/subvolume.md# Subvolume cleanup

The subvolume command is used to clean the stale subvolumes
which have no parent-pvc attached to them.
The command would list out all such subvolumes which needs to be removed.
This would consider all the cases where we can have stale subvolume
and delete them without impacting other resources and attached volumes.

The subvolume command will require the following sub commands:
* `ls` : [ls](#ls) lists all the subvolumes
    * `--stale`: lists only stale subvolumes
* `delete <filesystem> <subvolume> [subvolumegroup]`:
    [delete](#delete) a stale subvolume.
    * subvolume: subvolume name.
    * filesystem: filesystem name to which the subvolume belongs.
    * subvolumegroup: subvolumegroup name to which the subvolume belong(default is "csi")
## ls

```bash
$ kubectl rook-ceph subvolume ls

Filesystem  Subvolume  SubvolumeGroup  State
myfs csi-vol-427774b4-340b-11ed-8d66-0242ac110004 csi in-use
myfs csi-vol-427774b4-340b-11ed-8d66-0242ac110005 csi in-use
myfs csi-vol-427774b4-340b-11ed-8d66-0242ac110007 csi stale
myfs csi-vol-427774b4-340b-11ed-8d66-0242ac110007 csi stale-with-snapshot
```

```bash
$ kubectl rook-ceph subvolume ls --stale

Filesystem  Subvolume  SubvolumeGroup state
myfs csi-vol-427774b4-340b-11ed-8d66-0242ac110004 csi stale
myfs csi-vol-427774b4-340b-11ed-8d66-0242ac110005 csi stale-with-snapshot
```

## delete

```bash
$ kubectl rook-ceph subvolume delete myfs csi-vol-427774b4-340b-11ed-8d66-0242ac110005

Info: Deleting the omap object and key for subvolume "csi-vol-0c91ba82-5a63-4117-88a4-690acd86cbbd"
Info: omap object:"csi.volume.0c91ba82-5a63-4117-88a4-690acd86cbbd" deleted
Info: omap key:"csi.volume.pvc-78abf81c-5381-42ee-8d75-dc17cd0cf5de" deleted
Info: subvolume "csi-vol-0c91ba82-5a63-4117-88a4-690acd86cbbd" deleted
```

```bash
$ kubectl rook-ceph subvolume delete myfs csi-vol-427774b4-340b-11ed-8d66-0242ac110005

Info: No omapvals found for subvolume csi-vol-427774b4-340b-11ed-8d66-0242ac110005
Info: subvolume "csi-vol-427774b4-340b-11ed-8d66-0242ac110005" deleted
```07070100000029000081A4000000000000000000000001680F0E88000015B3000000000000000000000000000000000000001F00000000kubectl-rook-ceph-0.9.4/go.modmodule github.com/rook/kubectl-rook-ceph

go 1.23.0

toolchain go1.23.4

require (
	github.com/fatih/color v1.18.0
	github.com/golang/mock v1.6.0
	github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0
	github.com/pkg/errors v0.9.1
	github.com/rook/rook v1.17.1
	github.com/rook/rook/pkg/apis v0.0.0-20241216163035-3170ac6a0c58
	github.com/spf13/cobra v1.9.1
	github.com/stretchr/testify v1.10.0
	gopkg.in/yaml.v3 v3.0.1
	k8s.io/api v0.32.3
	k8s.io/apimachinery v0.32.3
	k8s.io/client-go v0.32.3
)

require (
	github.com/cenkalti/backoff/v4 v4.3.0 // indirect
	github.com/containernetworking/cni v1.2.3 // indirect
	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
	github.com/emicklei/go-restful/v3 v3.12.1 // indirect
	github.com/fxamacker/cbor/v2 v2.7.0 // indirect
	github.com/go-jose/go-jose/v4 v4.0.5 // indirect
	github.com/go-logr/logr v1.4.2 // indirect
	github.com/go-openapi/jsonpointer v0.21.0 // indirect
	github.com/go-openapi/jsonreference v0.21.0 // indirect
	github.com/go-openapi/swag v0.23.0 // indirect
	github.com/gogo/protobuf v1.3.2 // indirect
	github.com/golang/protobuf v1.5.4 // indirect
	github.com/google/gnostic-models v0.6.9 // indirect
	github.com/google/go-cmp v0.7.0 // indirect
	github.com/google/gofuzz v1.2.0 // indirect
	github.com/google/uuid v1.6.0 // indirect
	github.com/gorilla/websocket v1.5.3 // indirect
	github.com/hashicorp/errwrap v1.1.0 // indirect
	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
	github.com/hashicorp/go-multierror v1.1.1 // indirect
	github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
	github.com/hashicorp/go-rootcerts v1.0.2 // indirect
	github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 // indirect
	github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
	github.com/hashicorp/go-sockaddr v1.0.7 // indirect
	github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
	github.com/hashicorp/vault/api v1.16.0 // indirect
	github.com/hashicorp/vault/api/auth/approle v0.8.0 // indirect
	github.com/hashicorp/vault/api/auth/kubernetes v0.8.0 // indirect
	github.com/inconshreveable/mousetrap v1.1.0 // indirect
	github.com/josharian/intern v1.0.0 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.7.6 // indirect
	github.com/kube-object-storage/lib-bucket-provisioner v0.0.0-20221122204822-d1a8c34382f1 // indirect
	github.com/libopenstorage/secrets v0.0.0-20240416031220-a17cf7f72c6c // indirect
	github.com/mailru/easyjson v0.9.0 // indirect
	github.com/mattn/go-colorable v0.1.13 // indirect
	github.com/mattn/go-isatty v0.0.20 // indirect
	github.com/mitchellh/go-homedir v1.1.0 // indirect
	github.com/mitchellh/mapstructure v1.5.0 // indirect
	github.com/moby/spdystream v0.5.0 // indirect
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
	github.com/modern-go/reflect2 v1.0.2 // indirect
	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
	github.com/openshift/api v0.0.0-20241216151652-de9de05a8e43 // indirect
	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
	github.com/ryanuber/go-glob v1.0.0 // indirect
	github.com/sirupsen/logrus v1.9.3 // indirect
	github.com/spf13/pflag v1.0.6 // indirect
	github.com/x448/float16 v0.8.4 // indirect
	golang.org/x/crypto v0.36.0 // indirect
	golang.org/x/net v0.38.0 // indirect
	golang.org/x/oauth2 v0.27.0 // indirect
	golang.org/x/sys v0.31.0 // indirect
	golang.org/x/term v0.30.0 // indirect
	golang.org/x/text v0.23.0 // indirect
	golang.org/x/time v0.9.0 // indirect
	google.golang.org/protobuf v1.36.5 // indirect
	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
	gopkg.in/inf.v0 v0.9.1 // indirect
	k8s.io/klog/v2 v2.130.1 // indirect
	k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
	k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect
	sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
	sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
	sigs.k8s.io/yaml v1.4.0 // indirect
)

replace (
	github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.4.1
	github.com/kubernetes-incubator/external-storage => github.com/libopenstorage/external-storage v0.20.4-openstorage-rc3
	github.com/portworx/sched-ops => github.com/portworx/sched-ops v0.20.4-openstorage-rc3
)

exclude (
	// This tag doesn't exist, but is imported by github.com/portworx/sched-ops.
	github.com/kubernetes-incubator/external-storage v0.20.4-openstorage-rc2
	// Exclude pre-go-mod kubernetes tags, because they are older
	// than v0.x releases but are picked when updating dependencies.
	k8s.io/client-go v1.4.0
	k8s.io/client-go v1.5.0
	k8s.io/client-go v1.5.1
	k8s.io/client-go v1.5.2
	k8s.io/client-go v2.0.0-alpha.1+incompatible
	k8s.io/client-go v2.0.0+incompatible
	k8s.io/client-go v3.0.0-beta.0+incompatible
	k8s.io/client-go v3.0.0+incompatible
	k8s.io/client-go v4.0.0-beta.0+incompatible
	k8s.io/client-go v4.0.0+incompatible
	k8s.io/client-go v5.0.0+incompatible
	k8s.io/client-go v5.0.1+incompatible
	k8s.io/client-go v6.0.0+incompatible
	k8s.io/client-go v7.0.0+incompatible
	k8s.io/client-go v8.0.0+incompatible
	k8s.io/client-go v9.0.0-invalid+incompatible
	k8s.io/client-go v9.0.0+incompatible
	k8s.io/client-go v10.0.0+incompatible
	k8s.io/client-go v11.0.0+incompatible
	k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible
	k8s.io/client-go v12.0.0+incompatible
)
0707010000002A000081A4000000000000000000000001680F0E8800023ADA000000000000000000000000000000000000001F00000000kubectl-rook-ceph-0.9.4/go.sumcloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go v62.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
github.com/Azure/go-autorest/autorest/adal v0.9.20/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/IBM/keyprotect-go-client v0.5.1/go.mod h1:5TwDM/4FRJq1ZOlwQL1xFahLWQ3TveR88VmL1u3njyI=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.44.164/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/containernetworking/cni v1.2.3 h1:hhOcjNVUQTnzdRJ6alC5XF+wd9mfGIUaj8FuJbEslXM=
github.com/containernetworking/cni v1.2.3/go.mod h1:DuLgF+aPd3DzcTQTtp/Nvl1Kim23oFKdm2okJzBQA5M=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU=
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8 h1:iBt4Ew4XEGLfh6/bPk4rSYmuZJGizr6/x/AEizP0CQc=
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.8/go.mod h1:aiJI+PIApBRQG7FZTEBx5GiiX+HbOHilUdNxUZi4eV0=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw=
github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I=
github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8=
github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4=
github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA=
github.com/hashicorp/vault/api/auth/approle v0.5.0/go.mod h1:CHOQIA1AZACfjTzHggmyfiOZ+xCSKNRFqe48FTCzH0k=
github.com/hashicorp/vault/api/auth/approle v0.8.0 h1:FuVtWZ0xD6+wz1x0l5s0b4852RmVXQNEiKhVXt6lfQY=
github.com/hashicorp/vault/api/auth/approle v0.8.0/go.mod h1:NV7O9r5JUtNdVnqVZeMHva81AIdpG0WoIQohNt1VCPM=
github.com/hashicorp/vault/api/auth/kubernetes v0.5.0/go.mod h1:afrElBIO9Q4sHFVuVWgNevG4uAs1bT2AZFA9aEiI608=
github.com/hashicorp/vault/api/auth/kubernetes v0.8.0 h1:6jPcORq7OHwf+MCbaaUmiBvMhETAaZ7+i97WfZtF5kc=
github.com/hashicorp/vault/api/auth/kubernetes v0.8.0/go.mod h1:nfl5sRUUork0ZSfV3xf+pgAFQSD5kSkL0k9axg523DM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.7.6 h1:lhSaboKtal0XF2yqSw2BqNB1vUL4+a4BFe39I9G/yiM=
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.7.6/go.mod h1:CM7HAH5PNuIsqjMN0fGc1ydM74Uj+0VZFhob620nklw=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kube-object-storage/lib-bucket-provisioner v0.0.0-20221122204822-d1a8c34382f1 h1:dQEHhTfi+bSIOSViQrKY9PqJvZenD6tFz+3lPzux58o=
github.com/kube-object-storage/lib-bucket-provisioner v0.0.0-20221122204822-d1a8c34382f1/go.mod h1:my+EVjOJLeQ9lUR9uVkxRvNNkhO2saSGIgzV8GZT9HY=
github.com/kubernetes-csi/external-snapshotter/client/v4 v4.0.0/go.mod h1:YBCo4DoEeDndqvAn6eeu0vWM7QdXmHEeI9cFWplmBys=
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0 h1:Q3jQ1NkFqv5o+F8dMmHd8SfEmlcwNeo1immFApntEwE=
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0/go.mod h1:E3vdYxHj2C2q6qo8/Da4g7P+IcwqRZyy3gJBzYybV9Y=
github.com/libopenstorage/autopilot-api v0.6.1-0.20210128210103-5fbb67948648/go.mod h1:6JLrPbR3ZJQFbUY/+QJMl/aF00YdIrLf8/GWAplgvJs=
github.com/libopenstorage/openstorage v8.0.0+incompatible/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc=
github.com/libopenstorage/operator v0.0.0-20200725001727-48d03e197117/go.mod h1:Qh+VXOB6hj60VmlgsmY+R1w+dFuHK246UueM4SAqZG0=
github.com/libopenstorage/secrets v0.0.0-20240416031220-a17cf7f72c6c h1:sCgvz+9ukGwz0k9kHNzGm1zJLTOo5HT1F//9mtXZ08g=
github.com/libopenstorage/secrets v0.0.0-20240416031220-a17cf7f72c6c/go.mod h1:TB8PxROcwcNeaawFm45+XAj0lnZL2wRI3wTr/tZ3/bM=
github.com/libopenstorage/stork v1.3.0-beta1.0.20200630005842-9255e7a98775/go.mod h1:qBSzYTJVHlOMg5RINNiHD1kBzlasnrc2uKLPZLgu1Qs=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
github.com/onsi/ginkgo/v2 v2.6.0/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc=
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/openshift/api v0.0.0-20210105115604-44119421ec6b/go.mod h1:aqU5Cq+kqKKPbDMqxo9FojgDeSpNJI7iuskjXjtojDg=
github.com/openshift/api v0.0.0-20241216151652-de9de05a8e43 h1:3lcB5nqOOfsJzY4JD12AMKyg3+yQhAdJzNDenbmbMQg=
github.com/openshift/api v0.0.0-20241216151652-de9de05a8e43/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
github.com/openshift/build-machinery-go v0.0.0-20200917070002-f171684f77ab/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE=
github.com/openshift/client-go v0.0.0-20210112165513-ebc401615f47/go.mod h1:u7NRAjtYVAKokiI9LouzTv4mhds8P4S1TwdVAfbjKSk=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v0.0.0-20170612153648-e790cca94e6c/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/portworx/dcos-secrets v0.0.0-20180616013705-8e8ec3f66611/go.mod h1:4hklRW/4DQpLqkcXcjtNprbH2tz/sJaNtqinfPWl/LA=
github.com/portworx/kvdb v0.0.0-20200929023115-b312c7519467/go.mod h1:Q8YyrNDvPp3DVF96BDcQuaC7fAYUCuUX+l58S7OnD2M=
github.com/portworx/sched-ops v0.20.4-openstorage-rc3/go.mod h1:DpRDDqXWQrReFJ5SHWWrURuZdzVKjrh2OxbAfwnrAyk=
github.com/portworx/talisman v0.0.0-20191007232806-837747f38224/go.mod h1:OjpMH9Uh5o9ntVGktm4FbjLNwubJ3ITih2OfYrAeWtA=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.44.1/go.mod h1:3WYi4xqXxGGXWDdQIITnLNmuDzO5n6wYva9spVhR4fg=
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.46.0/go.mod h1:3WYi4xqXxGGXWDdQIITnLNmuDzO5n6wYva9spVhR4fg=
github.com/prometheus-operator/prometheus-operator/pkg/client v0.46.0/go.mod h1:k4BrWlVQQsvBiTcDnKEMgyh/euRxyxgrHdur/ZX/sdA=
github.com/prometheus/client_golang v0.9.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
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.17.1 h1:nNUGesl5UtCVGi8Ta/Gl2m5z9rNmqnEzqSjY6vRFzKA=
github.com/rook/rook v1.17.1/go.mod h1:Z5nuT7cGJLek9nRDH92J3XTcdqGMIyGDsFYo/O3NuT0=
github.com/rook/rook/pkg/apis v0.0.0-20241216163035-3170ac6a0c58 h1:z7TkRb4D+XvXIGg4ClSjZw8gAPQcZg9zUSFfZ0pUcTY=
github.com/rook/rook/pkg/apis v0.0.0-20241216163035-3170ac6a0c58/go.mod h1:ybPZNHfwtlMsl7Xbgm0Ka8rpg0s3qsWaXgOffubA+0U=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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.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=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
google.golang.org/api v0.83.0/go.mod h1:CNywQoj/AfhTw26ZWAa6LwOv+6WFxHmeLPZq2uncLZk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA=
k8s.io/api v0.19.0/go.mod h1:I1K45XlvTrDjmj5LoM5LuP/KYrhWbjUKT/SoPG0qTjw=
k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI=
k8s.io/api v0.20.0/go.mod h1:HyLC5l5eoS/ygQYl1BXBgFzWNlkHiAuyNAbevIn+FKg=
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.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls=
k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k=
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=
k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko=
k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
k8s.io/apimachinery v0.20.0/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
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.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U=
k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
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=
k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU=
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.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU=
k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY=
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=
k8s.io/code-generator v0.20.1/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg=
k8s.io/component-base v0.18.3/go.mod h1:bp5GzGR0aGkYEfTj+eTY0AN/vXTgkJdQXjNTTVUaa3k=
k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E=
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM=
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4=
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg=
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas=
k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
sigs.k8s.io/controller-runtime v0.2.2/go.mod h1:9dyohw3ZtoXQuV1e766PHUn+cmrRCIcBh6XIMFNMZ+I=
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016 h1:kXv6kKdoEtedwuqMmkqhbkgvYKeycVbC8+iPCP9j5kQ=
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw=
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
0707010000002B000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000001E00000000kubectl-rook-ceph-0.9.4/media0707010000002C000081A4000000000000000000000001680F0E8800000E1B000000000000000000000000000000000000002700000000kubectl-rook-ceph-0.9.4/media/logo.svg<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
	 viewBox="0 0 1091.9 228.8" style="enable-background:new 0 0 1091.9 228.8;" xml:space="preserve">
<style type="text/css">
	.st0{fill:#2B2B2B;}
</style>
<g>
	<g>
		<g>
			<path class="st0" d="M178.8,222.8H76.7c-26.6,0-48.3-21.7-48.3-48.3V94.7c0-3.8,3.1-6.9,6.9-6.9h184.8c3.8,0,6.9,3.1,6.9,6.9
				v79.9C227.1,201.1,205.4,222.8,178.8,222.8z M42.3,101.6v73c0,19,15.5,34.5,34.5,34.5h102.1c19,0,34.5-15.5,34.5-34.5v-73H42.3z"
				/>
		</g>
		<g>
			<path class="st0" d="M151.9,186.3h-48.3c-3.8,0-6.9-3.1-6.9-6.9v-24.1c0-17.1,13.9-31,31-31s31,13.9,31,31v24.1
				C158.8,183.2,155.7,186.3,151.9,186.3z M110.5,172.5H145v-17.2c0-9.5-7.7-17.2-17.2-17.2s-17.2,7.7-17.2,17.2V172.5z"/>
		</g>
		<g>
			<path class="st0" d="M220.2,74.7C220.2,74.7,220.2,74.7,220.2,74.7L183,74.7c-3.8,0-6.9-3.1-6.9-6.9c0-3.8,3.1-6.9,6.9-6.9
				c0,0,0,0,0,0l30.2,0.1V19.8h-23.2v11.6c0,1.8-0.7,3.6-2,4.9c-1.3,1.3-3,2-4.9,2l0,0l-37,0c-3.8,0-6.9-3.1-6.9-6.9V19.8h-23.2
				v11.6c0,3.8-3.1,6.9-6.9,6.9l-37,0c-1.8,0-3.6-0.7-4.9-2s-2-3-2-4.9V19.8H42.3v41.2h29.9c3.8,0,6.9,3.1,6.9,6.9
				c0,3.8-3.1,6.9-6.9,6.9H35.4c-3.8,0-6.9-3.1-6.9-6.9v-55c0-3.8,3.1-6.9,6.9-6.9h37c3.8,0,6.9,3.1,6.9,6.9v11.6l23.2,0V12.9
				c0-3.8,3.1-6.9,6.9-6.9h37c3.8,0,6.9,3.1,6.9,6.9v11.6l23.2,0V12.9c0-3.8,3.1-6.9,6.9-6.9h37c3.8,0,6.9,3.1,6.9,6.9v55
				c0,1.8-0.7,3.6-2,4.9C223.8,74,222,74.7,220.2,74.7z"/>
		</g>
	</g>
	<g>
		<path class="st0" d="M432.4,202.2l-40.2-56.5c-4.5,0.5-9.2,0.8-14.1,0.8h-47.2v55.7h-18.6V26.5h65.8c22.4,0,40,5.4,52.7,16.1
			c12.7,10.7,19.1,25.4,19.1,44.2c0,13.7-3.5,25.3-10.4,34.8c-6.9,9.5-16.9,16.3-29.7,20.5l42.9,60.3H432.4z M417.5,119.2
			c9.2-7.7,13.8-18.5,13.8-32.4c0-14.2-4.6-25.1-13.8-32.8c-9.2-7.6-22.5-11.4-39.9-11.4h-46.7v88.1h46.7
			C395,130.7,408.3,126.9,417.5,119.2z"/>
		<path class="st0" d="M523.4,192.1c-14.1-7.8-25.2-18.5-33.1-32c-8-13.6-11.9-28.8-11.9-45.7c0-16.9,4-32.1,11.9-45.7
			c7.9-13.6,19-24.2,33.1-32c14.1-7.8,29.9-11.7,47.3-11.7c17.4,0,33.1,3.9,47.1,11.5c14,7.7,25,18.4,33,32
			c8,13.6,12.1,28.9,12.1,45.8c0,16.9-4,32.2-12.1,45.8c-8,13.6-19,24.3-33,32c-14,7.7-29.7,11.5-47.1,11.5
			C553.3,203.8,537.5,199.9,523.4,192.1z M608.3,177.8c11.2-6.3,20-15,26.4-26.1c6.4-11.1,9.5-23.6,9.5-37.3
			c0-13.7-3.2-26.1-9.5-37.3C628.3,66,619.5,57.3,608.3,51c-11.2-6.3-23.8-9.4-37.7-9.4c-13.9,0-26.5,3.1-37.8,9.4
			c-11.3,6.3-20.2,15-26.6,26.1c-6.4,11.1-9.7,23.6-9.7,37.3c0,13.7,3.2,26.2,9.7,37.3c6.4,11.1,15.3,19.8,26.6,26.1
			c11.3,6.3,23.9,9.4,37.8,9.4C584.6,187.2,597.1,184,608.3,177.8z"/>
		<path class="st0" d="M734,192.1c-14.1-7.8-25.2-18.5-33.1-32c-8-13.6-11.9-28.8-11.9-45.7c0-16.9,4-32.1,11.9-45.7
			c7.9-13.6,19-24.2,33.1-32c14.1-7.8,29.9-11.7,47.3-11.7c17.4,0,33.1,3.9,47.1,11.5c14,7.7,25,18.4,33,32
			c8,13.6,12.1,28.9,12.1,45.8c0,16.9-4,32.2-12.1,45.8c-8,13.6-19,24.3-33,32c-14,7.7-29.7,11.5-47.1,11.5
			C763.9,203.8,748.1,199.9,734,192.1z M819,177.8c11.2-6.3,20-15,26.4-26.1c6.4-11.1,9.5-23.6,9.5-37.3c0-13.7-3.2-26.1-9.5-37.3
			C839,66,830.2,57.3,819,51c-11.2-6.3-23.8-9.4-37.7-9.4c-13.9,0-26.5,3.1-37.8,9.4c-11.3,6.3-20.2,15-26.6,26.1
			c-6.4,11.1-9.7,23.6-9.7,37.3c0,13.7,3.2,26.2,9.7,37.3c6.4,11.1,15.3,19.8,26.6,26.1c11.3,6.3,23.9,9.4,37.8,9.4
			C795.2,187.2,807.7,184,819,177.8z"/>
		<path class="st0" d="M969.6,119.7l-35.9,36.4v46.2h-18.6V26.5h18.6v106.2l103.2-106.2h21.3l-76.1,79.6l81.3,96.1h-22.1
			L969.6,119.7z"/>
	</g>
</g>
</svg>
0707010000002D000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000001C00000000kubectl-rook-ceph-0.9.4/pkg0707010000002E000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002100000000kubectl-rook-ceph-0.9.4/pkg/crds0707010000002F000081A4000000000000000000000001680F0E8800002110000000000000000000000000000000000000002900000000kubectl-rook-ceph-0.9.4/pkg/crds/crds.go/*
Copyright 2023 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 crds

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/pkg/errors"
	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	corev1 "k8s.io/api/core/v1"
	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/kubernetes"
)

var CephResources = []string{
	"cephclusters",
	"cephblockpoolradosnamespaces",
	"cephblockpools",
	"cephbucketnotifications",
	"cephbuckettopics",
	"cephclients",
	"cephcosidrivers",
	"cephfilesystemmirrors",
	"cephfilesystems",
	"cephfilesystemsubvolumegroups",
	"cephnfses",
	"cephobjectrealms",
	"cephobjectstores",
	"cephobjectstoreusers",
	"cephobjectzonegroups",
	"cephobjectzones",
	"cephrbdmirrors",
}

const (
	CephRookIoGroup          = "ceph.rook.io"
	CephRookResourcesVersion = "v1"
)

const (
	CephResourceCephClusters = "cephclusters"
	toolBoxDeployment        = "rook-ceph-tools"
	timeOutCheckResources    = 5 * time.Second
	maxExecutionTime         = 15 * time.Minute
	maxDisplayedPods         = 10
)

var (
	clusterResourcePatchFinalizer = map[string]interface{}{
		"spec": map[string]interface{}{
			"cleanupPolicy": map[string]string{
				"confirmation": "yes-really-destroy-data",
			},
		},
	}

	DefaultResourceRemoveFinalizers = map[string]interface{}{
		"metadata": map[string]interface{}{
			"finalizers": nil,
		},
	}
)

func DeleteCustomResources(ctx context.Context, clientsets k8sutil.ClientsetsInterface, k8sClientSet kubernetes.Interface, clusterNamespace string) {
	err := deleteCustomResources(ctx, clientsets, clusterNamespace)
	if err != nil {
		logging.Fatal(err)
	}
	k8sutil.DeleteDeployment(ctx, k8sClientSet, clusterNamespace, toolBoxDeployment)
	ensureClusterIsEmpty(ctx, k8sClientSet, clusterNamespace)
	logging.Info("done")
}

func deleteCustomResources(ctx context.Context, clientsets k8sutil.ClientsetsInterface, clusterNamespace string) error {
	for _, resource := range CephResources {
		logging.Info("getting resource kind %s", resource)
		items, err := clientsets.ListResourcesDynamically(ctx, CephRookIoGroup, CephRookResourcesVersion, resource, clusterNamespace)
		if err != nil {
			if k8sErrors.IsNotFound(err) {
				logging.Info("the server could not find the requested resource: %s", resource)
				continue
			}
			return err
		}

		if len(items) == 0 {
			logging.Info("resource %s was not found on the cluster", resource)
			continue
		}

		for _, item := range items {
			logging.Info(fmt.Sprintf("removing resource %s: %s", resource, item.GetName()))
			err = clientsets.DeleteResourcesDynamically(ctx, CephRookIoGroup, CephRookResourcesVersion, resource, clusterNamespace, item.GetName())
			if err != nil {
				if k8sErrors.IsNotFound(err) {
					logging.Info(err.Error())
					continue
				}
				return err
			}

			itemResource, err := clientsets.GetResourcesDynamically(ctx, CephRookIoGroup, CephRookResourcesVersion, resource, item.GetName(), clusterNamespace)
			if err != nil {
				if !k8sErrors.IsNotFound(err) {
					return err
				}
			}

			if itemResource != nil {
				logging.Info(fmt.Sprintf("resource %q is not yet deleted, applying patch to remove finalizer...", itemResource.GetName()))
				err = updatingFinalizers(ctx, clientsets, itemResource, resource, clusterNamespace)
				if err != nil {
					if k8sErrors.IsNotFound(err) {
						logging.Info(err.Error())
						continue
					}
					return err
				}

				err = clientsets.DeleteResourcesDynamically(ctx, CephRookIoGroup, CephRookResourcesVersion, resource, clusterNamespace, item.GetName())
				if err != nil {
					if !k8sErrors.IsNotFound(err) {
						return err
					}
				}
			}

			itemResource, err = clientsets.GetResourcesDynamically(ctx, CephRookIoGroup, CephRookResourcesVersion, resource, item.GetName(), clusterNamespace)
			if err != nil {
				if !k8sErrors.IsNotFound(err) {
					return err
				}
			}

			logging.Info("resource %s was deleted", item.GetName())
		}
	}
	return nil
}

func updatingFinalizers(ctx context.Context, clientsets k8sutil.ClientsetsInterface, itemResource *unstructured.Unstructured, resource, clusterNamespace string) error {
	if resource == CephResourceCephClusters {
		jsonPatchData, _ := json.Marshal(clusterResourcePatchFinalizer)
		err := clientsets.PatchResourcesDynamically(ctx, CephRookIoGroup, CephRookResourcesVersion, resource, clusterNamespace, itemResource.GetName(), types.MergePatchType, jsonPatchData)
		if err != nil {
			return err
		}
		logging.Info("Added cleanup policy to the cephcluster CR %q", resource)
		return nil
	}

	jsonPatchData, _ := json.Marshal(DefaultResourceRemoveFinalizers)
	err := clientsets.PatchResourcesDynamically(ctx, CephRookIoGroup, CephRookResourcesVersion, resource, clusterNamespace, itemResource.GetName(), types.MergePatchType, jsonPatchData)
	if err != nil {
		return err
	}

	return nil
}

func ensureClusterIsEmpty(ctx context.Context, k8sClientSet kubernetes.Interface, clusterNamespace string) {
	logging.Info("waiting to clean up resources")
	ctx, cancel := context.WithTimeout(context.Background(), maxExecutionTime)
	defer cancel()

	for {
		select {
		case <-time.After(timeOutCheckResources):
			pods, err := k8sClientSet.CoreV1().Pods(clusterNamespace).List(ctx, v1.ListOptions{LabelSelector: "rook_cluster=" + clusterNamespace})
			if err != nil {
				logging.Fatal(err)
			}

			if len(pods.Items) == 0 {
				return
			}

			logging.Info("%d pods still alive, removing....", len(pods.Items))
			for i, pod := range pods.Items {
				if i < maxDisplayedPods {
					logging.Info("pod %s still alive", pod.Name)
				}
				appLabel := getPodLabel(ctx, pod, "app")
				err := pruneDeployments(ctx, k8sClientSet, clusterNamespace, appLabel)
				if err != nil {
					logging.Warning("failed to prune deployments. %v", err)
				}
				err = pruneJobs(ctx, k8sClientSet, clusterNamespace, appLabel)
				if err != nil {
					logging.Warning("failed to prune jobs. %v", err)
				}
			}

		case <-ctx.Done():
			logging.Info("Timeout reached, exiting cleanup loop")
			return
		}
	}
}

func getPodLabel(_ context.Context, pod corev1.Pod, label string) string {
	for podLabelName, podLabelValue := range pod.Labels {
		if podLabelName == label {
			return podLabelValue
		}
	}
	return ""
}

func pruneDeployments(ctx context.Context, k8sClientSet kubernetes.Interface, clusterNamespace, labelApp string) error {
	deployments, err := k8sClientSet.
		AppsV1().
		Deployments(clusterNamespace).List(ctx, v1.ListOptions{
		LabelSelector: "rook_cluster=" + clusterNamespace + ",app=" + labelApp,
	})
	if err != nil {
		if !k8sErrors.IsNotFound(err) {
			return err
		}
		return nil
	}

	for _, deployment := range deployments.Items {
		logging.Info("deployment %s exists removing....", deployment.Name)
		k8sutil.DeleteDeployment(ctx, k8sClientSet, clusterNamespace, deployment.Name)
	}
	return nil
}

func pruneJobs(ctx context.Context, k8sClientSet kubernetes.Interface, clusterNamespace, labelApp string) error {
	selector := "rook_cluster=" + clusterNamespace + ",app=" + labelApp
	jobs, err := k8sClientSet.BatchV1().Jobs(clusterNamespace).List(ctx, v1.ListOptions{
		LabelSelector: selector,
	})
	if err != nil {
		if !k8sErrors.IsNotFound(err) {
			return err
		}
		return nil
	}

	for _, job := range jobs.Items {
		logging.Info("job %s exists removing....", job.Name)
		var gracePeriod int64
		propagation := metav1.DeletePropagationForeground
		options := &metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod, PropagationPolicy: &propagation}
		if err := k8sClientSet.BatchV1().Jobs(clusterNamespace).Delete(ctx, job.Name, *options); err != nil {
			if !k8sErrors.IsNotFound(err) {
				return errors.Wrapf(err, "failed to delete job %q", job.Name)
			}
		}
	}
	return nil
}
07070100000030000081A4000000000000000000000001680F0E8800001EE9000000000000000000000000000000000000002E00000000kubectl-rook-ceph-0.9.4/pkg/crds/crds_test.go/*
Copyright 2023 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 crds

import (
	"context"
	"fmt"
	"github.com/golang/mock/gomock"
	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/stretchr/testify/assert"
	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"testing"
)

func NewUnstructuredData(version, kind, name string) *unstructured.Unstructured {
	obj := unstructured.Unstructured{}
	obj.SetAPIVersion(version)
	obj.SetKind(kind)
	obj.SetName(name)
	return &obj
}

func TestDeleteCustomResources(t *testing.T) {

	type MockListResourcesDynamically struct {
		items []unstructured.Unstructured
		err   error
	}

	type MockGetResourceDynamically struct {
		itemResource *unstructured.Unstructured
		err          error
	}

	type given struct {
		MockListResourcesDynamically  MockListResourcesDynamically
		MockGetResourceDynamically    MockGetResourceDynamically
		DeleteResourcesDynamicallyErr error
		PatchResourcesDynamicallyErr  error
	}

	type expected struct {
		err error
	}

	var cases = []struct {
		name     string
		given    given
		expected expected
	}{
		{
			name: "Should return error if was not able to run ListResourcesDynamically successfully",
			given: given{
				MockListResourcesDynamically: MockListResourcesDynamically{
					err: fmt.Errorf("error from ListResourcesDynamically"),
				},
			},
			expected: expected{
				err: fmt.Errorf("error from ListResourcesDynamically"),
			},
		},
		{
			name: "Should return no error if the error from ListResourcesDynamically was resource not found",
			given: given{
				MockListResourcesDynamically: MockListResourcesDynamically{
					err: errors.NewNotFound(schema.GroupResource{}, "cephrbdmirrors"),
				},
			},
		},
		{
			name: "Should return no error if no any error was thrown and the items from the list of resource is empty",
			given: given{
				MockListResourcesDynamically: MockListResourcesDynamically{},
			},
		},
		{
			name: "Should return error if an error was throw by DeleteResourcesDynamically",
			given: given{
				MockListResourcesDynamically: MockListResourcesDynamically{
					items: []unstructured.Unstructured{
						*NewUnstructuredData("v1", "cephblockpools", "cephblockpools"),
					},
				},
				DeleteResourcesDynamicallyErr: errors.NewNotFound(schema.GroupResource{}, "cephblockpools"),
			},
		},
		{
			name: "Should return no error if the error from GetResourcesDynamically was the server could not find the requested resource",
			given: given{
				MockListResourcesDynamically: MockListResourcesDynamically{
					items: []unstructured.Unstructured{
						*NewUnstructuredData("v1", "cephblockpools", "cephblockpools"),
					},
				},
				MockGetResourceDynamically: MockGetResourceDynamically{
					err: errors.NewNotFound(schema.GroupResource{}, "cephblockpools"),
				},
			},
		},
		{
			name: "Should return error if was unable to patch the resource kind cephblockpools",
			given: given{
				MockListResourcesDynamically: MockListResourcesDynamically{
					items: []unstructured.Unstructured{
						*NewUnstructuredData("v1", "cephblockpools", "cephblockpools"),
					},
				},
				MockGetResourceDynamically: MockGetResourceDynamically{
					itemResource: NewUnstructuredData("v1", "cephblockpools", "cephblockpools"),
				},
				PatchResourcesDynamicallyErr: fmt.Errorf("unable to patch the resource"),
			},
			expected: expected{
				err: fmt.Errorf("unable to patch the resource"),
			},
		},
		{
			name: "Should return error if was unable to patch the resource kind cephclusters with cleanupPolicy patch",
			given: given{
				MockListResourcesDynamically: MockListResourcesDynamically{
					items: []unstructured.Unstructured{
						*NewUnstructuredData("v1", "CephCluster", "cephclusters"),
					},
				},
				MockGetResourceDynamically: MockGetResourceDynamically{
					itemResource: NewUnstructuredData("v1", "CephCluster", "cephclusters"),
				},
				PatchResourcesDynamicallyErr: fmt.Errorf("unable to patch the resource"),
			},
			expected: expected{
				err: fmt.Errorf("unable to patch the resource"),
			},
		},
		{
			name: "Should return no error if was unable to patch the resource due the server could not find the requested resource",
			given: given{
				MockListResourcesDynamically: MockListResourcesDynamically{
					items: []unstructured.Unstructured{
						*NewUnstructuredData("v1", "CephCluster", "cephclusters"),
					},
				},
				MockGetResourceDynamically: MockGetResourceDynamically{
					itemResource: NewUnstructuredData("v1", "CephCluster", "cephclusters"),
				},
				PatchResourcesDynamicallyErr: errors.NewNotFound(schema.GroupResource{}, "cephclusters"),
			},
		},
		{
			name: "Should return no error if DeleteResourcesDynamically returns the server could not find the requested resource ",
			given: given{
				MockListResourcesDynamically: MockListResourcesDynamically{
					items: []unstructured.Unstructured{
						*NewUnstructuredData("v1", "CephCluster", "cephclusters"),
					},
				},
				MockGetResourceDynamically: MockGetResourceDynamically{
					itemResource: NewUnstructuredData("v1", "CephCluster", "cephclusters"),
				},
				DeleteResourcesDynamicallyErr: errors.NewNotFound(schema.GroupResource{}, "cephclusters"),
			},
		},
		{
			name: "Should return no error if the resource was deleted successfully",
			given: given{
				MockListResourcesDynamically: MockListResourcesDynamically{
					items: []unstructured.Unstructured{
						*NewUnstructuredData("v1", "CephCluster", "cephclusters"),
					},
				},
				MockGetResourceDynamically: MockGetResourceDynamically{
					itemResource: NewUnstructuredData("v1", "CephCluster", "cephclusters"),
				},
			},
		},
	}

	for _, tc := range cases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			ctrl := gomock.NewController(t)
			defer ctrl.Finish()

			clientSets := k8sutil.NewMockClientsetsInterface(ctrl)
			clientSets.
				EXPECT().
				ListResourcesDynamically(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
				Return(tc.given.MockListResourcesDynamically.items, tc.given.MockListResourcesDynamically.err).
				AnyTimes()

			clientSets.
				EXPECT().
				GetResourcesDynamically(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
				Return(tc.given.MockGetResourceDynamically.itemResource, tc.given.MockGetResourceDynamically.err).
				AnyTimes()

			counter := 0

			clientSets.
				EXPECT().
				DeleteResourcesDynamically(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
				Do(func(arg1, arg2, arg3, arg4, arg5, arg6 interface{}) error {
					if counter%2 == 1 {
						return nil
					}
					return tc.given.DeleteResourcesDynamicallyErr
				}).
				Return(tc.given.DeleteResourcesDynamicallyErr).
				AnyTimes()

			clientSets.
				EXPECT().
				PatchResourcesDynamically(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
				Return(tc.given.PatchResourcesDynamicallyErr).
				AnyTimes()

			clusterNamespace := "rook-ceph"
			err := deleteCustomResources(context.Background(), clientSets, clusterNamespace)
			if tc.expected.err != nil {
				assert.Error(t, err)
				assert.Equal(t, tc.expected.err.Error(), err.Error())
				return
			}

			assert.NoError(t, err)
		})
	}
}
07070100000031000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000001F00000000kubectl-rook-ceph-0.9.4/pkg/dr07070100000032000081A4000000000000000000000001680F0E8800000BFD000000000000000000000000000000000000002900000000kubectl-rook-ceph-0.9.4/pkg/dr/health.gopackage dr

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"

	"github.com/rook/kubectl-rook-ceph/pkg/exec"
	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	rookv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"

	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

type secretData struct {
	Key      string `json:"key"`
	MonHost  string `json:"mon_host"`
	ClientId string `json:"client_id"`
}

func Health(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, cephClusterNamespace string, args []string) {
	logging.Info("fetching the cephblockpools with mirroring enabled")
	blockPoolList, err := clientsets.Rook.CephV1().CephBlockPools(cephClusterNamespace).List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(err)
	}

	var mirrorBlockPool rookv1.CephBlockPool
	for _, blockPool := range blockPoolList.Items {
		if blockPool.Spec.Mirroring.Enabled && blockPool.Spec.Mirroring.Peers != nil {
			mirrorBlockPool = blockPool
			logging.Info("found %q cephblockpool with mirroring enabled", mirrorBlockPool.Name)
		}
	}

	if mirrorBlockPool.Name == "" {
		logging.Warning("DR is not confiqured, cephblockpool with mirroring enabled not found.")
		return
	}

	var secretDetail string
	for _, data := range mirrorBlockPool.Spec.Mirroring.Peers.SecretNames {
		if data != "" {
			secretDetail = data
			break
		}
	}

	secretData, err := extractSecretData(ctx, clientsets.Kube, operatorNamespace, cephClusterNamespace, secretDetail)
	if err != nil {
		logging.Fatal(fmt.Errorf("failed to extract secret %s", secretDetail))
	}

	logging.Info("running ceph status from peer cluster")

	cephArgs := []string{"-s", "--mon-host", secretData.MonHost, "--id", secretData.ClientId, "--key", secretData.Key}

	if len(args) == 0 {
		cephArgs = append(cephArgs, "--debug-ms", "0")
	} else {
		cephArgs = append(cephArgs, args...)
	}

	cephStatus, err := exec.RunCommandInOperatorPod(ctx, clientsets, "ceph", cephArgs, operatorNamespace, cephClusterNamespace, true)
	if err != nil {
		logging.Warning("failed to get ceph status from peer cluster, please check for network issues between the clusters")
		return
	}
	logging.Info(cephStatus)

	logging.Info("running mirroring daemon health")

	_, err = exec.RunCommandInOperatorPod(ctx, clientsets, "rbd", []string{"-p", mirrorBlockPool.Name, "mirror", "pool", "status"}, cephClusterNamespace, operatorNamespace, false)
	if err != nil {
		logging.Error(err)
	}
}

func extractSecretData(ctx context.Context, k8sclientset kubernetes.Interface, operatorNamespace, cephClusterNamespace, secretName string) (*secretData, error) {
	secret, err := k8sclientset.CoreV1().Secrets(cephClusterNamespace).Get(ctx, secretName, v1.GetOptions{})
	if err != nil {
		return nil, err
	}
	decodeSecretData, err := base64.StdEncoding.DecodeString(string(secret.Data["token"]))
	if err != nil {
		return nil, err
	}

	var data *secretData
	err = json.Unmarshal(decodeSecretData, &data)
	if err != nil {
		return nil, err
	}
	return data, nil
}
07070100000033000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002100000000kubectl-rook-ceph-0.9.4/pkg/exec07070100000034000081A4000000000000000000000001680F0E8800000396000000000000000000000000000000000000002900000000kubectl-rook-ceph-0.9.4/pkg/exec/bash.go/*
Copyright 2023 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 exec

import (
	"os"
	"os/exec"

	"github.com/rook/kubectl-rook-ceph/pkg/logging"
)

func ExecuteBashCommand(command string) string {
	cmd := exec.Command("/bin/bash",
		"-c", // Command to run
		command,
	)
	cmd.Stderr = os.Stderr
	stdout, err := cmd.Output()
	if err != nil {
		logging.Fatal(err)
	}
	return string(stdout)
}
07070100000035000081A4000000000000000000000001680F0E8800001730000000000000000000000000000000000000002900000000kubectl-rook-ceph-0.9.4/pkg/exec/exec.go/*
Copyright 2023 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 exec

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"os"

	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/tools/remotecommand"
)

var (
	OperatorNamespace    string // operator namespae
	CephClusterNamespace string // Cephcluster namespace
)

func RunCommandInOperatorPod(ctx context.Context, clientsets *k8sutil.Clientsets, cmd string, args []string, operatorNamespace, clusterNamespace string, returnOutput bool) (string, error) {
	var pod v1.Pod
	var err error

	pod, err = k8sutil.WaitForPodToRun(ctx, clientsets.Kube, operatorNamespace, "app=rook-ceph-operator")
	if err != nil {
		return "", fmt.Errorf("failed to wait for operator pod to run. %w", err)
	}

	var stdout, stderr bytes.Buffer

	err = execCmdInPod(ctx, clientsets, cmd, pod.Name, "rook-ceph-operator", pod.Namespace, clusterNamespace, args, &stdout, &stderr, returnOutput)
	if err != nil {
		err = fmt.Errorf("%s. %w", stderr.String(), err)
	}
	var out string
	if returnOutput {
		out = stdout.String()
	}
	return out, err
}

func RunCommandInToolboxPod(ctx context.Context, clientsets *k8sutil.Clientsets, cmd string, args []string, clusterNamespace string, returnOutput bool) (string, error) {
	var pod v1.Pod
	var err error

	pod, err = k8sutil.WaitForPodToRun(ctx, clientsets.Kube, clusterNamespace, "app=rook-ceph-tools")
	if err != nil {
		return "", fmt.Errorf("failed to wait for operator pod to run. %w", err)
	}

	var stdout, stderr bytes.Buffer

	err = execCmdInPod(ctx, clientsets, cmd, pod.Name, "rook-ceph-tools", pod.Namespace, clusterNamespace, args, &stdout, &stderr, returnOutput)
	if err != nil {
		err := fmt.Errorf("failed to run command. %w", err)
		if !returnOutput {
			return "", err
		}
		return stdout.String(), err
	}
	if !returnOutput {
		return "", nil
	}

	fmt.Println(stderr.String())
	return stdout.String(), nil
}

func RunCommandInLabeledPod(ctx context.Context, clientsets *k8sutil.Clientsets, label, container, cmd string, args []string, clusterNamespace string, returnOutput bool) (string, error) {
	var list *v1.PodList
	var err error

	opts := metav1.ListOptions{LabelSelector: label}
	list, err = clientsets.Kube.CoreV1().Pods(clusterNamespace).List(ctx, opts)
	if err != nil || len(list.Items) == 0 {
		return "", fmt.Errorf("failed to get rook mon pod where the command could be executed. %w", err)
	}
	var stdout, stderr bytes.Buffer
	err = execCmdInPod(ctx, clientsets, cmd, list.Items[0].Name, container, list.Items[0].Namespace, clusterNamespace, args, &stdout, &stderr, returnOutput)
	if err != nil {
		err := fmt.Errorf("failed to run command. %w", err)
		if !returnOutput {
			return "", err
		}
		return stdout.String(), err
	}
	if !returnOutput {
		return "", nil
	}

	fmt.Println(stderr.String())
	return stdout.String(), nil
}

// execCmdInPod exec command on specific pod and wait the command's output.
func execCmdInPod(ctx context.Context, clientsets *k8sutil.Clientsets,
	command, podName, containerName, podNamespace, clusterNamespace string,
	args []string, stdout, stderr io.Writer, returnOutput bool) error {

	if len(args) < 1 {
		return fmt.Errorf("no arg passed to exec with %q command", command)
	}

	cmd := []string{}
	cmd = append(cmd, command)
	cmd = append(cmd, args...)

	if containerName == "rook-ceph-tools" {
		cmd = append(cmd, "--connect-timeout=10")
	} else if cmd[0] == "ceph" {
		if len(cmd) > 1 && cmd[1] == "daemon" {
			cmd = append(cmd, "--connect-timeout=10")
		} else {
			cmd = append(cmd, "--connect-timeout=10", fmt.Sprintf("--conf=/var/lib/rook/%s/%s.config", clusterNamespace, clusterNamespace))
		}
	} else if cmd[0] == "rbd" {
		cmd = append(cmd, fmt.Sprintf("--conf=/var/lib/rook/%s/%s.config", clusterNamespace, clusterNamespace))
	} else if cmd[0] == "rados" {
		cmd = append(cmd, fmt.Sprintf("--conf=/var/lib/rook/%s/%s.config", clusterNamespace, clusterNamespace))
	} else if cmd[0] == "radosgw-admin" {
		cmd = append(cmd, fmt.Sprintf("--conf=/var/lib/rook/%s/%s.config", clusterNamespace, clusterNamespace))
	}

	// Prepare the API URL used to execute another process within the Pod.  In
	// this case, we'll run a remote shell.
	req := clientsets.Kube.CoreV1().RESTClient().
		Post().
		Namespace(podNamespace).
		Resource("pods").
		Name(podName).
		SubResource("exec").
		VersionedParams(&v1.PodExecOptions{
			Container: containerName,
			Command:   cmd,
			Stdout:    true,
			Stderr:    true,
			TTY:       false,
		}, scheme.ParameterCodec)

	exec, err := remotecommand.NewSPDYExecutor(clientsets.KubeConfig, "POST", req.URL())
	if err != nil {
		return fmt.Errorf("failed to create SPDYExecutor. %w", err)
	}

	// returnOutput is true, the command's output will be print on shell directly with os.Stdout or os.Stderr
	if !returnOutput {
		// Connect this process' std{in,out,err} to the remote shell process.
		err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{
			Stdout: os.Stdout,
			Stderr: os.Stderr,
			Tty:    false,
		})
	} else {
		// Connect this process' std{in,out,err} to the remote shell process.
		err = exec.StreamWithContext(ctx, remotecommand.StreamOptions{
			Stdout: stdout,
			Stderr: stderr,
			Tty:    false,
		})
	}
	if err != nil {
		return fmt.Errorf("failed to run command. %w", err)
	}
	return nil
}
07070100000036000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002700000000kubectl-rook-ceph-0.9.4/pkg/filesystem07070100000037000081A4000000000000000000000001680F0E88000062C7000000000000000000000000000000000000003400000000kubectl-rook-ceph-0.9.4/pkg/filesystem/subvolume.go/*
Copyright 2023 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 subvolume

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"syscall"

	snapclient "github.com/kubernetes-csi/external-snapshotter/client/v8/clientset/versioned/typed/volumesnapshot/v1"
	"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"
)

type fsStruct struct {
	Name         string
	MetadataName string `json:"metadata_pool"`
	data         []string
}

type subVolumeInfo struct {
	svg   string
	fs    string
	state string
}

type snapshotInfo struct {
	volumeHandle   string
	snapshotHandle string
}

type monitor struct {
	ClusterID string
	Monitors  []string
}

const (
	inUse             = "in-use"
	stale             = "stale"
	staleWithSnapshot = "stale-with-snapshot"
	snapshotRetained  = "snapshot-retained"
)

func List(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace string, includeStaleOnly bool) {

	subvolumeNames := getK8sRefSubvolume(ctx, clientsets)
	snapshotHandles := getK8sRefSnapshotHandle(ctx, clientsets)
	listCephFSSubvolumes(ctx, clientsets, operatorNamespace, clusterNamespace, includeStaleOnly, subvolumeNames, snapshotHandles)
}

// checkForExternalStorage checks if the external mode is enabled.
func checkForExternalStorage(ctx context.Context, clientsets *k8sutil.Clientsets, clusterNamespace string) bool {
	enable := false
	cephclusters, err := clientsets.Rook.CephV1().CephClusters(clusterNamespace).List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(fmt.Errorf("failed to list CephClusters in namespace %q: %v", clusterNamespace, err))
	}
	for i := range cephclusters.Items {
		enable = cephclusters.Items[i].Spec.External.Enable
		if enable == true {
			break
		}
	}
	return enable
}

// getExternalClusterDetails gets the required mon-ip, id and key to connect to the
// ceph cluster.
func getExternalClusterDetails(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace string) (string, string, string) {
	var adminId, adminKey, m string

	scList, err := clientsets.Kube.CoreV1().Secrets(clusterNamespace).List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(fmt.Errorf("Error fetching secrets in namespace %q: %v", clusterNamespace, err))
	}
	for i := range scList.Items {
		if strings.HasPrefix(scList.Items[i].ObjectMeta.Name, "rook-csi-cephfs-provisioner") {
			data := scList.Items[i].Data
			if data == nil {
				logging.Fatal(fmt.Errorf("Secret data is empty for %s/%s", clusterNamespace, scList.Items[i].ObjectMeta.Name))
			}
			adminId = string(data["adminID"])
			adminKey = string(data["adminKey"])
			break

		}
	}

	cm, err := clientsets.Kube.CoreV1().ConfigMaps(clusterNamespace).Get(ctx, "rook-ceph-mon-endpoints", v1.GetOptions{})
	if err != nil {
		logging.Fatal(fmt.Errorf("Error fetching configmaps %s/rook-ceph-mon-endpoints: %v", clusterNamespace, err))
	}

	if len(cm.Data) == 0 || cm.Data == nil {
		logging.Fatal(fmt.Errorf("Configmap data is empty for %s/rook-ceph-mon-endpoints", clusterNamespace))
	}
	monpoint := cm.Data["csi-cluster-config-json"]
	var monip []monitor
	json.Unmarshal([]byte(monpoint), &monip)
	for _, mp := range monip {
		if len(mp.Monitors) == 0 || mp.Monitors[0] == "" {
			logging.Fatal(fmt.Errorf("mon ip for %s/rook-ceph-mon-endpoints with clusterID:%q is empty", clusterNamespace, mp.ClusterID))
		}
		m = mp.Monitors[0]
	}

	return m, adminId, adminKey
}

// getk8sRefSubvolume returns the k8s ref for the subvolumes
func getK8sRefSubvolume(ctx context.Context, clientsets *k8sutil.Clientsets) map[string]subVolumeInfo {
	pvList, err := clientsets.Kube.CoreV1().PersistentVolumes().List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(fmt.Errorf("Error fetching PVs: %v\n", err))
	}
	subvolumeNames := make(map[string]subVolumeInfo)
	for _, pv := range pvList.Items {
		if pv.Spec.CSI != nil {
			driverName := pv.Spec.CSI.Driver
			if strings.Contains(driverName, "cephfs.csi.ceph.com") {
				subvolumePath := pv.Spec.CSI.VolumeAttributes["subvolumePath"]
				name, err := getSubvolumeNameFromPath(subvolumePath)
				if err != nil {
					logging.Error(err, "failed to get subvolume name")
					continue
				}
				subvolumeNames[name] = subVolumeInfo{}
			}
		}
	}
	return subvolumeNames
}

// getSubvolumeNameFromPath get the subvolumename from the path.
// subvolumepath: /volumes/csi/csi-vol-6a99b552-fdcc-441d-b1e6-a522a85a503d/5f4e4caa-f835-41ba-83c1-5bbd57f6aedf
// subvolumename: csi-vol-6a99b552-fdcc-441d-b1e6-a522a85a503d
func getSubvolumeNameFromPath(path string) (string, error) {
	splitSubvol := strings.Split(path, "/")
	if len(splitSubvol) < 4 {
		return "", fmt.Errorf("failed to get name from subvolumepath: %s", path)
	}
	name := splitSubvol[3]

	return name, nil
}

// getk8sRefSnapshotHandle returns the snapshothandle for k8s ref of the volume snapshots
func getK8sRefSnapshotHandle(ctx context.Context, clientsets *k8sutil.Clientsets) map[string]snapshotInfo {

	snapConfig, err := snapclient.NewForConfig(clientsets.KubeConfig)
	if err != nil {
		logging.Fatal(err)
	}
	snapList, err := snapConfig.VolumeSnapshotContents().List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(fmt.Errorf("Error fetching volumesnapshotcontents: %v\n", err))
	}

	snapshotHandles := make(map[string]snapshotInfo)
	for _, snap := range snapList.Items {
		driverName := snap.Spec.Driver
		if snap.Status != nil && snap.Status.SnapshotHandle != nil && strings.Contains(driverName, "cephfs.csi.ceph.com") {

			snapshotHandleId := getSnapshotHandleId(*snap.Status.SnapshotHandle)
			// map the snapshotHandle id to later lookup for the subvol id and
			// match the subvolume snapshot.
			snapshotHandles[snapshotHandleId] = snapshotInfo{}
		}
	}

	return snapshotHandles
}

// getSnapshotHandleId gets the id from snapshothandle
// SnapshotHandle: 0001-0009-rook-ceph-0000000000000001-17b95621-
// 58e8-4676-bc6a-39e928f19d23
// SnapshotHandleId: 17b95621-58e8-4676-bc6a-39e928f19d23
func getSnapshotHandleId(snapshotHandle string) string {
	// get the snaps id from snapshot handle
	splitSnapshotHandle := strings.SplitAfterN(snapshotHandle, "-", 6)
	if len(splitSnapshotHandle) < 6 {
		return ""
	}
	snapshotHandleId := splitSnapshotHandle[len(splitSnapshotHandle)-1]

	return snapshotHandleId
}

// runCommand checks for the presence of externalcluster and runs the command accordingly.
func runCommand(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace, cmd string, args []string) (string, error) {
	if checkForExternalStorage(ctx, clientsets, clusterNamespace) {
		m, admin_id, admin_key := getExternalClusterDetails(ctx, clientsets, operatorNamespace, clusterNamespace)
		args = append(args, "-m", m, "--id", admin_id, "--key", admin_key)
	}
	list, err := exec.RunCommandInOperatorPod(ctx, clientsets, cmd, args, operatorNamespace, clusterNamespace, true)

	return list, err
}

// listCephFSSubvolumes list all the subvolumes
func listCephFSSubvolumes(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace string, includeStaleOnly bool, subvolumeNames map[string]subVolumeInfo, snapshotHandles map[string]snapshotInfo) {

	// getFilesystem gets the filesystem
	fsstruct, err := getFileSystem(ctx, clientsets, operatorNamespace, clusterNamespace)
	if err != nil {
		logging.Error(err, "failed to get filesystem")
		return
	}
	fmt.Println("Filesystem  Subvolume  SubvolumeGroup  State")

	// this iterates over the filesystems and subvolumegroup to get the list of subvolumes that exist
	for _, fs := range fsstruct {
		// gets the subvolumegroup in the filesystem
		subvolg, err := getSubvolumeGroup(ctx, clientsets, operatorNamespace, clusterNamespace, fs.Name)
		if err != nil {
			logging.Error(err, "failed to get subvolume groups")
			continue
		}
		for _, svg := range subvolg {
			cmd := "ceph"
			args := []string{"fs", "subvolume", "ls", fs.Name, svg.Name, "--format", "json"}
			svList, err := runCommand(ctx, clientsets, operatorNamespace, clusterNamespace, cmd, args)
			if err != nil {
				logging.Error(err, "failed to get subvolumes of %q", fs.Name)
				continue
			}
			subvol := unMarshaljson(svList)
			if len(subvol) == 0 {
				continue
			}
			// append the subvolume which doesn't have any snapshot attached to it.
			for _, sv := range subvol {
				state, err := getSubvolumeState(ctx, clientsets, operatorNamespace, clusterNamespace, fs.Name, sv.Name, svg.Name)
				// subvolume info returns error in case of pending clone or if it is not ready
				// it is suggested to delete the pvc before deleting the subvolume.
				if err != nil {
					if errors.Is(err, syscall.EAGAIN) {
						logging.Warning("Found pending clone: %q", sv.Name)
						logging.Warning("Please delete the pending pv if any before deleting the subvolume %s", sv.Name)
						logging.Warning("To avoid stale resources, please scale down the cephfs deployment before deleting the subvolume.")
						continue
					}
					logging.Fatal(fmt.Errorf("failed to get subvolume state: %q %q", sv.Name, err))

				}
				// Assume the volume is stale unless proven otherwise
				stalevol := true
				// lookup for subvolume in list of the PV references
				_, ok := subvolumeNames[sv.Name]
				if ok {
					// The volume is not stale if a PV was found
					stalevol = false
				}
				status := stale
				if !stalevol {
					if includeStaleOnly {
						continue
					}
					status = inUse
				} else {
					// check the state of the stale subvolume
					// if it is snapshot-retained then skip listing it.
					if state == snapshotRetained {
						status = snapshotRetained
						continue
					}
					// check if the stale subvolume has snapshots.
					if checkSnapshot(ctx, clientsets, operatorNamespace, clusterNamespace, fs.Name, sv.Name, svg.Name, snapshotHandles) {
						status = staleWithSnapshot
					}

				}
				subvolumeNames[sv.Name] = subVolumeInfo{fs.Name, svg.Name, state}
				fmt.Println(fs.Name, sv.Name, svg.Name, status)
			}
		}
	}
}

// getSubvolumeState returns the state of the subvolume
func getSubvolumeState(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace, fsName, SubVol, SubvolumeGroup string) (string, error) {
	cmd := "ceph"
	args := []string{"fs", "subvolume", "info", fsName, SubVol, SubvolumeGroup, "--format", "json"}

	subVolumeInfo, errvol := runCommand(ctx, clientsets, operatorNamespace, clusterNamespace, cmd, args)
	if errvol != nil {
		logging.Error(errvol, "failed to get subvolume info")
		return "", errvol
	}
	var info map[string]interface{}
	err := json.Unmarshal([]byte(subVolumeInfo), &info)
	if err != nil {
		logging.Fatal(fmt.Errorf("failed to unmarshal: %q", err))
	}
	state, ok := info["state"].(string)
	if !ok {
		logging.Fatal(fmt.Errorf("failed to get the state of subvolume: %q", SubVol))
	}
	return state, nil
}

// gets list of filesystem
func getFileSystem(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace string) ([]fsStruct, error) {

	cmd := "ceph"
	args := []string{"fs", "ls", "--format", "json"}

	fsList, err := runCommand(ctx, clientsets, operatorNamespace, clusterNamespace, cmd, args)
	if err != nil {
		logging.Error(err, "failed to get filesystems")
		return []fsStruct{}, err
	}
	fsstruct := unMarshaljson(fsList)
	if len(fsstruct) == 0 {
		logging.Fatal(fmt.Errorf("no filesystem found"))
	}
	return fsstruct, nil
}

// checkSnapshot checks if there are any snapshots in the subvolume
// it also check for the stale snapshot and if found, deletes the snapshot.
func checkSnapshot(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace, fs, sv, svg string, snapshotHandles map[string]snapshotInfo) bool {

	cmd := "ceph"
	args := []string{"fs", "subvolume", "snapshot", "ls", fs, sv, svg, "--format", "json"}

	snapList, err := runCommand(ctx, clientsets, operatorNamespace, clusterNamespace, cmd, args)
	if err != nil {
		logging.Error(err, "failed to get subvolume snapshots of %q/%q/%q", fs, sv, svg)
		return false
	}
	snap := unMarshaljson(snapList)
	// check for stale subvolume snapshot
	// we have the list of snapshothandleid's from the
	// volumesnapshotcontent. Looking up for snapid in it
	// will confirm if we have stale snapshot or not.
	for _, s := range snap {
		_, snapId := getSnapOmapVal(s.Name)
		// lookup for the snapid in the k8s snapshot handle list
		_, ok := snapshotHandles[snapId]
		if !ok {
			// delete stale snapshot
			deleteSnapshot(ctx, clientsets, operatorNamespace, clusterNamespace, fs, sv, svg, s.Name)
		}
	}
	if len(snap) == 0 {
		return false
	}
	return true

}

// gets the list of subvolumegroup for the specified filesystem
func getSubvolumeGroup(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace, fs string) ([]fsStruct, error) {
	cmd := "ceph"
	args := []string{"fs", "subvolumegroup", "ls", fs, "--format", "json"}

	svgList, err := runCommand(ctx, clientsets, operatorNamespace, clusterNamespace, cmd, args)
	if err != nil {
		logging.Error(err, "failed to get subvolume groups for filesystem %q", fs)
		return []fsStruct{}, err
	}
	subvolg := unMarshaljson(svgList)
	if len(subvolg) == 0 {
		logging.Fatal(fmt.Errorf("no subvolumegroups found for filesystem %q", fs))
	}
	return subvolg, nil
}

func unMarshaljson(list string) []fsStruct {
	var unmarshal []fsStruct
	errg := json.Unmarshal([]byte(list), &unmarshal)
	if errg != nil {
		logging.Fatal(errg)
	}
	return unmarshal
}

// deleteSnapshot deletes the subvolume snapshot
func deleteSnapshot(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, cephClusterNamespace, fs, subvol, svg, snap string) {

	deleteOmapForSnapshot(ctx, clientsets, operatorNamespace, cephClusterNamespace, snap, fs)
	cmd := "ceph"
	args := []string{"fs", "subvolume", "snapshot", "rm", fs, subvol, snap, svg}

	_, err := runCommand(ctx, clientsets, operatorNamespace, cephClusterNamespace, cmd, args)
	if err != nil {
		logging.Fatal(err, "failed to delete subvolume snapshot of %s/%s/%s/%s", fs, svg, subvol, snap)
	}
}

func Delete(ctx context.Context, clientsets *k8sutil.Clientsets, OperatorNamespace, CephClusterNamespace, fs, subvol, svg string) {
	k8sSubvolume := getK8sRefSubvolume(ctx, clientsets)
	_, check := k8sSubvolume[subvol]
	if !check {
		deleteOmapForSubvolume(ctx, clientsets, OperatorNamespace, CephClusterNamespace, subvol, fs)
		cmd := "ceph"
		args := []string{"fs", "subvolume", "rm", fs, subvol, svg, "--retain-snapshots"}

		_, err := runCommand(ctx, clientsets, OperatorNamespace, CephClusterNamespace, cmd, args)
		if err != nil {
			logging.Fatal(err, "failed to delete subvolume of %s/%s/%s", fs, svg, subvol)
		}
		logging.Info("subvolume %s/%s/%s deleted", fs, svg, subvol)

	} else {
		logging.Info("subvolume %s/%s/%s is not stale", fs, svg, subvol)
	}
}

func getMetadataPoolName(ctx context.Context, clientsets *k8sutil.Clientsets, OperatorNamespace, CephClusterNamespace, fs string) (string, error) {
	fsstruct, err := getFileSystem(ctx, clientsets, OperatorNamespace, CephClusterNamespace)
	if err != nil {
		return "", err
	}

	for _, pool := range fsstruct {
		if pool.Name == fs {
			return pool.MetadataName, nil
		}
	}
	return "", fmt.Errorf("metadataPool not found for %q filesystem", fs)
}

// deleteOmap deletes omap object and key for the given subvolume.
func deleteOmapForSubvolume(ctx context.Context, clientsets *k8sutil.Clientsets, OperatorNamespace, CephClusterNamespace, subVol, fs string) {
	logging.Info("Deleting the omap object and key for subvolume %q", subVol)
	omapkey := getOmapKey(ctx, clientsets, OperatorNamespace, CephClusterNamespace, subVol, fs)
	omapval, subvolId := getOmapVal(subVol)
	poolName, err := getMetadataPoolName(ctx, clientsets, OperatorNamespace, CephClusterNamespace, fs)
	if err != nil || poolName == "" {
		logging.Fatal(fmt.Errorf("pool name not found: %q", err))
	}
	nfsClusterName := getNfsClusterName(ctx, clientsets, OperatorNamespace, CephClusterNamespace, subVol, fs)
	if nfsClusterName != "" {
		exportPath := getNfsExportPath(ctx, clientsets, OperatorNamespace, CephClusterNamespace, nfsClusterName, subvolId)
		if exportPath == "" {
			logging.Info("export path not found for subvol %q: %q", subVol, nfsClusterName)
		} else {
			cmd := "ceph"
			args := []string{"nfs", "export", "delete", nfsClusterName, exportPath}
			_, err := runCommand(ctx, clientsets, OperatorNamespace, CephClusterNamespace, cmd, args)
			if err != nil {
				logging.Fatal(err, "failed to delete export for subvol %q: %q %q", subVol, nfsClusterName, exportPath)
			}
			logging.Info("nfs export: %q %q deleted", nfsClusterName, exportPath)
		}
	}
	if omapval != "" {
		cmd := "rados"
		args := []string{"rm", omapval, "-p", poolName, "--namespace", "csi"}

		// remove omap object.
		_, err := runCommand(ctx, clientsets, OperatorNamespace, CephClusterNamespace, cmd, args)
		if err != nil {
			logging.Fatal(err, "failed to remove omap object for subvolume %q", subVol)
		}
		logging.Info("omap object:%q deleted", omapval)

	}
	if omapkey != "" {
		cmd := "rados"
		args := []string{"rmomapkey", "csi.volumes.default", omapkey, "-p", poolName, "--namespace", "csi"}

		// remove omap key.
		_, err := runCommand(ctx, clientsets, OperatorNamespace, CephClusterNamespace, cmd, args)
		if err != nil {
			logging.Fatal(err, "failed to remove omap key for subvolume %q", subVol)
		}
		logging.Info("omap key:%q deleted", omapkey)

	}
}

// deleteOmapForSnapshot deletes omap object and key for the given snapshot.
func deleteOmapForSnapshot(ctx context.Context, clientsets *k8sutil.Clientsets, OperatorNamespace, CephClusterNamespace, snap, fs string) {
	logging.Info("Deleting the omap object and key for snapshot %q", snap)
	snapomapkey := getSnapOmapKey(ctx, clientsets, OperatorNamespace, CephClusterNamespace, snap, fs)
	snapomapval, _ := getSnapOmapVal(snap)
	poolName, err := getMetadataPoolName(ctx, clientsets, OperatorNamespace, CephClusterNamespace, fs)
	if err != nil || poolName == "" {
		logging.Fatal(fmt.Errorf("pool name not found: %q", err))
	}
	cmd := "rados"
	if snapomapval != "" {
		args := []string{"rm", snapomapval, "-p", poolName, "--namespace", "csi"}

		// remove omap object.
		_, err := runCommand(ctx, clientsets, OperatorNamespace, CephClusterNamespace, cmd, args)
		if err != nil {
			logging.Fatal(err, "failed to remove omap object for snapshot %q", snap)
		}
		logging.Info("omap object:%q deleted", snapomapval)

	}
	if snapomapkey != "" {
		args := []string{"rmomapkey", "csi.snaps.default", snapomapkey, "-p", poolName, "--namespace", "csi"}

		// remove omap key.
		_, err := runCommand(ctx, clientsets, OperatorNamespace, CephClusterNamespace, cmd, args)
		if err != nil {
			logging.Fatal(err, "failed to remove omap key for snapshot %q", snap)
		}
		logging.Info("omap key:%q deleted", snapomapkey)

	}
}

// getOmapKey gets the omap key and value details for a given subvolume.
// Deletion of omap object required the subvolumeName which is of format
// csi.volume.subvolume, where subvolume is the name of subvolume that needs to be
// deleted.
// similarly to delete of omap key requires csi.volume.ompakey, where
// omapkey is the pv name which is extracted the omap object.
func getOmapKey(ctx context.Context, clientsets *k8sutil.Clientsets, OperatorNamespace, CephClusterNamespace, subVol, fs string) string {

	poolName, err := getMetadataPoolName(ctx, clientsets, OperatorNamespace, CephClusterNamespace, fs)
	if err != nil || poolName == "" {
		logging.Fatal(fmt.Errorf("pool name not found: %q", err))
	}
	omapval, _ := getOmapVal(subVol)

	args := []string{"getomapval", omapval, "csi.volname", "-p", poolName, "--namespace", "csi", "/dev/stdout"}
	cmd := "rados"
	pvname, err := runCommand(ctx, clientsets, OperatorNamespace, CephClusterNamespace, cmd, args)
	if err != nil || pvname == "" {
		logging.Info("No PV found for subvolume %s: %s", subVol, err)
		return ""
	}
	// omap key is for format csi.volume.pvc-fca205e5-8788-4132-979c-e210c0133182
	// hence, attaching pvname to required prefix.
	omapkey := "csi.volume." + pvname

	return omapkey
}

// getSnapOmapKey gets the omap key and value details for a given snapshot.
// Deletion of omap object required the snapshotName which is of format
// csi.snap.snapid.
// similarly to delete of omap key requires csi.snap.ompakey, where
// omapkey is the snapshotcontent name which is extracted the omap object.
func getSnapOmapKey(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, cephClusterNamespace, snap, fs string) string {

	poolName, err := getMetadataPoolName(ctx, clientsets, operatorNamespace, cephClusterNamespace, fs)
	if err != nil || poolName == "" {
		logging.Fatal(fmt.Errorf("pool name not found: %q", err))
	}
	snapomapval, _ := getSnapOmapVal(snap)

	args := []string{"getomapval", snapomapval, "csi.snapname", "-p", poolName, "--namespace", "csi", "/dev/stdout"}
	cmd := "rados"
	snapshotcontentname, err := runCommand(ctx, clientsets, operatorNamespace, cephClusterNamespace, cmd, args)
	if snapshotcontentname == "" && err == nil {
		logging.Info("No snapshot content found for snapshot")
		return ""
	}
	if err != nil {
		logging.Fatal(fmt.Errorf("Error getting snapshot content for snapshot %s: %s", snap, err))
	}
	// omap key is for format csi.snap.snapshotcontent-fca205e5-8788-4132-979c-e210c0133182
	// hence, attaching pvname to required prefix.
	snapomapkey := "csi.snap." + snapshotcontentname

	return snapomapkey
}

// getNfsClusterName returns the cluster name from the omap.
// csi.nfs.cluster
// value (26 bytes) :
// 00000000  6f 63 73 2d 73 74 6f 72  61 67 65 63 6c 75 73 74  |my-cluster-cephn|
// 00000010  65 72 2d 63 65 70 68 6e  66 73                    |fs|
// 0000001a
func getNfsClusterName(ctx context.Context, clientsets *k8sutil.Clientsets, OperatorNamespace, CephClusterNamespace, subVol, fs string) string {

	poolName, err := getMetadataPoolName(ctx, clientsets, OperatorNamespace, CephClusterNamespace, fs)
	if err != nil || poolName == "" {
		logging.Fatal(fmt.Errorf("pool name not found %q: %q", poolName, err))
	}
	omapval, _ := getOmapVal(subVol)

	args := []string{"getomapval", omapval, "csi.nfs.cluster", "-p", poolName, "--namespace", "csi", "/dev/stdout"}
	cmd := "rados"
	nfscluster, err := runCommand(ctx, clientsets, OperatorNamespace, CephClusterNamespace, cmd, args)
	if err != nil || nfscluster == "" {
		logging.Info("nfs cluster not found for subvolume %s: %s %s", subVol, poolName, err)
		return ""
	}

	return nfscluster
}

func getNfsExportPath(ctx context.Context, clientsets *k8sutil.Clientsets, OperatorNamespace, CephClusterNamespace, clusterName, subvolId string) string {

	args := []string{"nfs", "export", "ls", clusterName}
	cmd := "ceph"
	exportList, err := runCommand(ctx, clientsets, OperatorNamespace, CephClusterNamespace, cmd, args)
	if err != nil || exportList == "" {
		logging.Info("No export path found for cluster %s: %s", clusterName, err)
		return ""
	}

	var unmarshalexportpath []string
	var exportPath string

	err = json.Unmarshal([]byte(exportList), &unmarshalexportpath)
	if err != nil {
		logging.Info("failed to unmarshal export list: %q", err)
		return ""
	}

	// Extract the value from the unmarshalexportpath
	if len(unmarshalexportpath) > 0 {
		// get the export which matches the subvolume id
		for _, uxp := range unmarshalexportpath {
			if strings.Contains(uxp, subvolId) {
				exportPath = uxp
			}
		}
	}

	return exportPath
}

// func getOmapVal is used to get the omapval from the given subvolume
// omapval is of format csi.volume.427774b4-340b-11ed-8d66-0242ac110005
// which is similar to volume name csi-vol-427774b4-340b-11ed-8d66-0242ac110005
// hence, replacing 'csi-vol-' to 'csi.volume.' to get the omapval
// it also returns the subvolume id
func getOmapVal(subVol string) (string, string) {

	splitSubvol := strings.SplitAfterN(subVol, "-", 3)
	if len(splitSubvol) < 3 {
		return "", ""
	}
	subvolId := splitSubvol[len(splitSubvol)-1]
	omapval := "csi.volume." + subvolId

	return omapval, subvolId
}

// func getSnapOmapVal is used to get the omapval from the given snapshot
// omapval is of format csi.snap.427774b4-340b-11ed-8d66-0242ac110005
// which is similar to volume name csi-snap-427774b4-340b-11ed-8d66-0242ac110005
// hence, replacing 'csi-snap-' to 'csi.snap.'
func getSnapOmapVal(snap string) (string, string) {

	splitSnap := strings.SplitAfterN(snap, "-", 3)
	if len(splitSnap) < 3 {
		return "", ""
	}
	snapId := splitSnap[len(splitSnap)-1]
	snapomapval := "csi.snap." + snapId

	return snapomapval, snapId
}
07070100000038000081A4000000000000000000000001680F0E880000110E000000000000000000000000000000000000003900000000kubectl-rook-ceph-0.9.4/pkg/filesystem/subvolume_test.go/*
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 subvolume

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestGetOmapVal(t *testing.T) {

	tests := []struct {
		name     string
		val      string
		subvolid string
	}{
		{
			name:     "csi-vol-427774b4-340b-11ed-8d66-0242ac110005",
			val:      "csi.volume.427774b4-340b-11ed-8d66-0242ac110005",
			subvolid: "427774b4-340b-11ed-8d66-0242ac110005",
		},
		{
			name:     "nfs-export-427774b4-340b-11ed-8d66-0242ac110005",
			val:      "csi.volume.427774b4-340b-11ed-8d66-0242ac110005",
			subvolid: "427774b4-340b-11ed-8d66-0242ac110005",
		},
		{
			name:     "",
			val:      "",
			subvolid: "",
		},
		{
			name:     "csi-427774b4-340b-11ed-8d66-0242ac11000",
			val:      "csi.volume.340b-11ed-8d66-0242ac11000",
			subvolid: "340b-11ed-8d66-0242ac11000",
		},
		{
			name:     "csi-427774b440b11ed8d660242ac11000",
			val:      "",
			subvolid: "",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if val, subvolid := getOmapVal(tt.name); val != tt.val && subvolid != tt.subvolid {
				t.Errorf("getOmapVal()= got val %v, want val %v,got subvolid %v want subvolid %v", val, tt.val, subvolid, tt.subvolid)
			}
		})
	}
}

func TestGetSubvolumeNameFromPath(t *testing.T) {

	tests := []struct {
		path string
		name string
		err  error
	}{
		{
			path: "/volumes/csi/csi-vol-6a99b552-fdcc-441d-b1e6-a522a85a503d/5f4e4caa-f835-41ba-83c1-5bbd57f6aedf",
			name: "csi-vol-6a99b552-fdcc-441d-b1e6-a522a85a503d",
		},
		{
			path: "",
			err:  fmt.Errorf("failed to get name from subvolumepath: "),
		},
		{
			path: "/volumes/csi-vol-6a99b552-fdcc-441d-b1e6-a522a85a503d/5f4e4caa-f835-41ba-83c1-5bbd57f6aedf",
			name: "5f4e4caa-f835-41ba-83c1-5bbd57f6aedf",
		},
		{
			path: "csi-vol-6a99b552-fdcc-441d-b1e6-a522a85a503d/5f4e4caa-f835-41ba-83c1-5bbd57f6aedf",
			err:  fmt.Errorf(`failed to get name from subvolumepath: csi-vol-6a99b552-fdcc-441d-b1e6-a522a85a503d/5f4e4caa-f835-41ba-83c1-5bbd57f6aedf`),
		},
	}
	for _, tt := range tests {
		t.Run(tt.path, func(t *testing.T) {
			name, err := getSubvolumeNameFromPath(tt.path)
			if err != nil {
				assert.Error(t, err)
				assert.Equal(t, tt.err.Error(), err.Error())
				return
			}
			assert.Equal(t, name, tt.name)
		})
	}
}

func TestGetSnapOmapVal(t *testing.T) {

	tests := []struct {
		name   string
		val    string
		snapid string
	}{
		{
			name:   "csi-snap-427774b4-340b-11ed-8d66-0242ac110005",
			val:    "csi.snap.427774b4-340b-11ed-8d66-0242ac110005",
			snapid: "427774b4-340b-11ed-8d66-0242ac110005",
		},
		{
			name:   "",
			val:    "",
			snapid: "",
		},
		{
			name:   "csi-427774b4-340b-11ed-8d66-0242ac11000",
			val:    "csi.snap.340b-11ed-8d66-0242ac11000",
			snapid: "340b-11ed-8d66-0242ac11000",
		},
		{
			name:   "csi-427774b440b11ed8d660242ac11000",
			val:    "",
			snapid: "",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if val, snapid := getSnapOmapVal(tt.name); val != tt.val && snapid != tt.snapid {
				t.Errorf("getSnapOmapVal()= got val %v, want val %v,got snapid %v want snapid %v", val, tt.val, snapid, tt.snapid)
			}
		})
	}
}

func TestGetSnapshotHandleId(t *testing.T) {

	tests := []struct {
		name string
		val  string
	}{
		{
			name: "0001-0009-rook-ceph-0000000000000001-17b95621-58e8-4676-bc6a-39e928f19d23",
			val:  "17b95621-58e8-4676-bc6a-39e928f19d23",
		},
		{
			name: "",
			val:  "",
		},
		{
			name: "0001-0009-rook-0000000000000001-17b95621-58e8-4676-bc6a-39e928f19d23",
			val:  "58e8-4676-bc6a-39e928f19d23",
		},
		{
			name: "rook-427774b440b11ed8d660242ac11000",
			val:  "",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if val := getSnapshotHandleId(tt.name); val != tt.val {
				assert.Equal(t, val, tt.val)
			}
		})
	}
}
07070100000039000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002C00000000kubectl-rook-ceph-0.9.4/pkg/flatten-rbd-pvc0707010000003A000081A4000000000000000000000001680F0E880000104F000000000000000000000000000000000000003F00000000kubectl-rook-ceph-0.9.4/pkg/flatten-rbd-pvc/flatten_rbd_pvc.gopackage flatten_rbd_pvc

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/rook/kubectl-rook-ceph/pkg/exec"
	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type RBDInfoOutput struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

type Watcher struct {
	Address string `json:"address"`
}

type RBDStatusOutput struct {
	Watchers []Watcher `json:"watchers"`
}

func FlattenRBDPVC(ctx context.Context, clientSets *k8sutil.Clientsets, operatorNamespace, clusterNamespace, namespace, pvcName string, allowInUse bool) {
	pvc, err := clientSets.Kube.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, 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))
	}

	shouldDeleteTempImage := false
	if pvc.Spec.DataSource != nil {
		switch pvc.Spec.DataSource.Kind {
		case "PersistentVolumeClaim":
			shouldDeleteTempImage = true
		case "VolumeSnapshot":
		default:
			logging.Fatal(fmt.Errorf("PVC %s is not a cloned image", pvcName))
		}
	}

	pvName := pvc.Spec.VolumeName
	pv, err := clientSets.Kube.CoreV1().PersistentVolumes().Get(ctx, 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 doesn't contains `imageName` in VolumeAttributes", pvName))
	}
	poolName, ok := pv.Spec.CSI.VolumeAttributes["pool"]
	if !ok {
		logging.Fatal(fmt.Errorf("PV %s doesn't contains `pool` in VolumeAttributes", pvName))
	}

	if !allowInUse {
		out, err := exec.RunCommandInOperatorPod(ctx, clientSets, "rbd", []string{"-p", poolName, "status", imageName, "--format=json"}, operatorNamespace, clusterNamespace, false)
		if err != nil {
			logging.Fatal(fmt.Errorf("failed to stat %s/%s", poolName, imageName))
		}
		var status RBDStatusOutput
		json.Unmarshal([]byte(out), &status)
		if len(status.Watchers) > 0 {
			logging.Fatal(fmt.Errorf("flatten in-use pvc %s is not allowed. If you want to do, run with `--allow-in-use` option", pvcName))
		}
	}

	if shouldDeleteTempImage {
		deleteTempImage(ctx, clientSets, operatorNamespace, clusterNamespace, poolName, imageName)
	}
	logging.Info("flattening the target RBD image %s/%s", poolName, imageName)
	_, err = exec.RunCommandInOperatorPod(ctx, clientSets, "ceph", []string{"rbd", "task", "add", "flatten", fmt.Sprintf("%s/%s", poolName, imageName)}, operatorNamespace, clusterNamespace, false)
	if err != nil {
		logging.Fatal(fmt.Errorf("failed to flatten %s/%s", poolName, imageName))
	}
}

func deleteTempImage(ctx context.Context, clientSets *k8sutil.Clientsets, operatorNamespace, cephClusterNamespace, poolName, imageName string) {
	tempImageName := imageName + "-temp"

	out, err := exec.RunCommandInOperatorPod(ctx, clientSets, "rbd", []string{"-p", poolName, "info", "--format=json", tempImageName}, operatorNamespace, cephClusterNamespace, false)
	if err != nil {
		logging.Error(fmt.Errorf("failed to run `rbd info` for rbd image %s/%s", poolName, tempImageName))
		return
	}
	var info RBDInfoOutput
	json.Unmarshal([]byte(out), &info)
	id := info.ID
	logging.Info("removing the temporary RBD image %s/%s if exist", poolName, tempImageName)
	_, err = exec.RunCommandInOperatorPod(ctx, clientSets, "rbd", []string{"-p", poolName, "trash", "mv", tempImageName}, operatorNamespace, cephClusterNamespace, false)
	if err != nil {
		logging.Fatal(fmt.Errorf("failed to move rbd image %s/%s to trash", poolName, tempImageName))
	}
	if id != "" {
		_, err = exec.RunCommandInOperatorPod(ctx, clientSets, "ceph", []string{"rbd", "task", "add", "trash", "remove", fmt.Sprintf("%s/%s", poolName, id)}, operatorNamespace, cephClusterNamespace, false)
		if err != nil {
			logging.Fatal(fmt.Errorf("failed to create a task to remove %s/%s from trash", poolName, id))
		}
	}
}
0707010000003B000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002300000000kubectl-rook-ceph-0.9.4/pkg/health0707010000003C000081A4000000000000000000000001680F0E8800001DD5000000000000000000000000000000000000002D00000000kubectl-rook-ceph-0.9.4/pkg/health/health.go/*
Copyright 2023 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 health

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"strings"

	"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/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

type cephStatus struct {
	PgMap  pgMap        `json:"pgmap"`
	Health healthStatus `json:"health"`
}

type healthStatus struct {
	Status string `json:"status"`
}

type pgMap struct {
	PgsByState []PgStateEntry `json:"pgs_by_state"`
}

type PgStateEntry struct {
	StateName string `json:"state_name"`
	Count     int    `json:"count"`
}

func Health(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace string) {
	logging.Info("Checking if at least three mon pods are running on different nodes")
	checkPodsOnNodes(ctx, clientsets.Kube, clusterNamespace, "app=rook-ceph-mon")

	fmt.Println()
	logging.Info("Checking mon quorum and ceph health details")
	checkMonQuorum(ctx, clientsets, operatorNamespace, clusterNamespace)

	fmt.Println()
	logging.Info("Checking if at least three osd pods are running on different nodes")
	checkPodsOnNodes(ctx, clientsets.Kube, clusterNamespace, "app=rook-ceph-osd")

	fmt.Println()
	CheckAllPodsStatus(ctx, clientsets.Kube, operatorNamespace, clusterNamespace)

	fmt.Println()
	logging.Info("Checking placement group status")
	checkPgStatus(ctx, clientsets, operatorNamespace, clusterNamespace)

	fmt.Println()
	logging.Info("Checking if at least one mgr pod is running")
	checkMgrPodsStatusAndCounts(ctx, clientsets.Kube, clusterNamespace)
}

func checkPodsOnNodes(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace, label string) {
	var daemonType string
	if strings.Contains(label, "osd") {
		daemonType = "osd"
	} else if strings.Contains(label, "mon") {
		daemonType = "mon"
	}

	opts := metav1.ListOptions{LabelSelector: label}
	podList, err := k8sclientset.CoreV1().Pods(clusterNamespace).List(ctx, opts)
	if err != nil {
		logging.Error(fmt.Errorf("failed to list %s pods with label %s: %v", daemonType, opts.LabelSelector, err))
	}

	var nodeList = make(map[string]string)
	for i := range podList.Items {
		nodeName := podList.Items[i].Spec.NodeName
		if _, okay := nodeList[nodeName]; !okay {
			nodeList[nodeName] = podList.Items[i].Name
		}
	}

	if len(nodeList) < 3 {
		logging.Warning("At least three %s pods should running on different nodes\n", daemonType)
	}

	for i := range podList.Items {
		fmt.Printf("%s\t%s\t%s\t%s\n", podList.Items[i].Name, podList.Items[i].Status.Phase, podList.Items[i].Namespace, podList.Items[i].Spec.NodeName)
	}
}

func checkMonQuorum(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace string) {
	cephHealthDetails, _ := unMarshalCephStatus(ctx, clientsets, operatorNamespace, clusterNamespace)
	if cephHealthDetails == "HEALTH_OK" {
		logging.Info(cephHealthDetails)
	} else if cephHealthDetails == "HEALTH_WARN" {
		logging.Warning(cephHealthDetails)
	} else if cephHealthDetails == "HEALTH_ERR" {
		logging.Error(fmt.Errorf(cephHealthDetails))
	}
}

func CheckAllPodsStatus(ctx context.Context, k8sclientset kubernetes.Interface, operatorNamespace, clusterNamespace string) {
	var podNotRunning, podRunning []v1.Pod
	podRunning, podNotRunning = getPodRunningStatus(ctx, k8sclientset, operatorNamespace)
	if operatorNamespace != clusterNamespace {
		clusterRunningPod, clusterNotRunningPod := getPodRunningStatus(ctx, k8sclientset, clusterNamespace)
		podRunning = append(podRunning, clusterRunningPod...)
		podNotRunning = append(podNotRunning, clusterNotRunningPod...)
	}

	logging.Info("Pods that are in 'Running' or `Succeeded` status")
	for i := range podRunning {
		fmt.Printf("%s \t %s \t %s\t %s\n", podRunning[i].Name, podRunning[i].Status.Phase, podRunning[i].Namespace, podRunning[i].Spec.NodeName)
	}

	fmt.Println()
	logging.Warning("Pods that are 'Not' in 'Running' status")
	for i := range podNotRunning {
		fmt.Printf("%s \t %s \t %s \t %s\n", podNotRunning[i].Name, podNotRunning[i].Status.Phase, podNotRunning[i].Namespace, podNotRunning[i].Spec.NodeName)
	}
}

func getPodRunningStatus(ctx context.Context, k8sclientset kubernetes.Interface, namespace string) ([]v1.Pod, []v1.Pod) {
	var podNotRunning, podRunning []v1.Pod
	podList, err := k8sclientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{})
	if err != nil {
		logging.Error(fmt.Errorf("\nfailed to list pods in namespace %s: %v\n", namespace, err))
	}

	for i := range podList.Items {
		if podList.Items[i].Status.Phase != v1.PodRunning && podList.Items[i].Status.Phase != v1.PodSucceeded {
			podNotRunning = append(podNotRunning, podList.Items[i])
		} else {
			podRunning = append(podRunning, podList.Items[i])
		}
	}
	return podRunning, podNotRunning
}

func checkPgStatus(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace string) {
	_, pgStateEntryList := unMarshalCephStatus(ctx, clientsets, operatorNamespace, clusterNamespace)
	for _, pgStatus := range pgStateEntryList {
		if pgStatus.StateName == "active+clean" {
			logging.Info("\tPgState: %s, PgCount: %d", pgStatus.StateName, pgStatus.Count)
		} else if strings.Contains(pgStatus.StateName, "down") || strings.Contains(pgStatus.StateName, "incomplete") || strings.Contains(pgStatus.StateName, "snaptrim_error") {
			logging.Error(fmt.Errorf("\tPgState: %s, PgCount: %d", pgStatus.StateName, pgStatus.Count))
		} else {
			logging.Warning("\tPgState: %s, PgCount: %d", pgStatus.StateName, pgStatus.Count)
		}
	}
}

func checkMgrPodsStatusAndCounts(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace string) {
	opts := metav1.ListOptions{LabelSelector: "app=rook-ceph-mgr"}
	podList, err := k8sclientset.CoreV1().Pods(clusterNamespace).List(ctx, opts)
	if err != nil {
		logging.Error(fmt.Errorf("\nfailed to list mgr pods with label %s: %v\n", opts.LabelSelector, err))
		return
	}

	if len(podList.Items) < 1 {
		logging.Warning("At least one mgr pod should be running")
	}

	for i := range podList.Items {
		fmt.Printf("%s\t%s\t%s\t%s\n", podList.Items[i].Name, podList.Items[i].Status.Phase, podList.Items[i].Namespace, podList.Items[i].Spec.NodeName)
	}
}

func unMarshalCephStatus(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace string) (string, []PgStateEntry) {
	cephStatusOut, err := exec.RunCommandInOperatorPod(ctx, clientsets, "ceph", []string{"-s", "--format", "json"}, operatorNamespace, clusterNamespace, true)
	if err != nil {
		logging.Fatal(err, "failed to get the status of ceph cluster")
	}

	ecodedText := base64.StdEncoding.EncodeToString([]byte(cephStatusOut))
	decodeCephStatus, err := base64.StdEncoding.DecodeString(ecodedText)
	if err != nil {
		logging.Fatal(err)
	}
	var cephStatus *cephStatus

	err = json.Unmarshal(decodeCephStatus, &cephStatus)
	if err != nil {
		logging.Fatal(err)
	}
	return cephStatus.Health.Status, cephStatus.PgMap.PgsByState
}
0707010000003D000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002400000000kubectl-rook-ceph-0.9.4/pkg/k8sutil0707010000003E000081A4000000000000000000000001680F0E880000044C000000000000000000000000000000000000002F00000000kubectl-rook-ceph-0.9.4/pkg/k8sutil/context.go/*
Copyright 2023 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 k8sutil

import (
	"k8s.io/client-go/dynamic"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"

	rookclient "github.com/rook/rook/pkg/client/clientset/versioned"
)

type Clientsets struct {
	// The Kubernetes config used for these client sets
	KubeConfig *rest.Config

	// Kube is a connection to the core Kubernetes API
	Kube kubernetes.Interface

	// Rook is a typed connection to the rook API
	Rook rookclient.Interface

	// Dynamic is used for manage dynamic resources
	Dynamic dynamic.Interface
}
0707010000003F000081A4000000000000000000000001680F0E8800000C50000000000000000000000000000000000000002F00000000kubectl-rook-ceph-0.9.4/pkg/k8sutil/dynamic.go/*
Copyright 2023 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 k8sutil

import (
	"context"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
)

func (c *Clientsets) ListResourcesDynamically(
	ctx context.Context,
	group string,
	version string,
	resource string,
	namespace string,
) ([]unstructured.Unstructured, error) {
	resourceId := schema.GroupVersionResource{
		Group:    group,
		Version:  version,
		Resource: resource,
	}

	list, err := c.Dynamic.Resource(resourceId).Namespace(namespace).
		List(ctx, metav1.ListOptions{})

	if err != nil {
		return nil, err
	}

	return list.Items, nil
}

func (c *Clientsets) DeleteResourcesDynamically(
	ctx context.Context,
	group string,
	version string,
	resource string,
	namespace string,
	resourceName string,
) error {

	resourceId := schema.GroupVersionResource{
		Group:    group,
		Version:  version,
		Resource: resource,
	}
	err := c.Dynamic.Resource(resourceId).Namespace(namespace).
		Delete(ctx, resourceName, metav1.DeleteOptions{})

	if err != nil {
		return err
	}
	return nil
}

func (c *Clientsets) PatchResourcesDynamically(
	ctx context.Context,
	group string,
	version string,
	resource string,
	namespace string,
	resourceName string,
	pt types.PatchType,
	data []byte,
) error {

	resourceId := schema.GroupVersionResource{
		Group:    group,
		Version:  version,
		Resource: resource,
	}

	_, err := c.Dynamic.Resource(resourceId).Namespace(namespace).
		Patch(ctx, resourceName, pt, data, metav1.PatchOptions{})

	if err != nil {
		return err
	}
	return nil
}

func (c *Clientsets) GetResourcesDynamically(
	ctx context.Context,
	group string,
	version string,
	resource string,
	name string,
	namespace string,
) (*unstructured.Unstructured, error) {
	resourceId := schema.GroupVersionResource{
		Group:    group,
		Version:  version,
		Resource: resource,
	}

	item, err := c.Dynamic.Resource(resourceId).Namespace(namespace).
		Get(ctx, name, metav1.GetOptions{})

	if err != nil {
		return nil, err
	}

	return item, nil
}

func (c *Clientsets) CreateResourcesDynamically(
	ctx context.Context,
	group string,
	version string,
	resource string,
	name *unstructured.Unstructured,
	namespace string,
) (*unstructured.Unstructured, error) {
	resourceId := schema.GroupVersionResource{
		Group:    group,
		Version:  version,
		Resource: resource,
	}

	item, err := c.Dynamic.Resource(resourceId).Namespace(namespace).
		Create(ctx, name, metav1.CreateOptions{})

	if err != nil {
		return nil, err
	}

	return item, nil
}
07070100000040000081A4000000000000000000000001680F0E88000006AA000000000000000000000000000000000000003100000000kubectl-rook-ceph-0.9.4/pkg/k8sutil/interface.go/*
Copyright 2023 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 k8sutil

import (
	"context"

	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/types"
)

//go:generate mockgen -package=k8sutil --build_flags=--mod=mod -destination=mocks.go github.com/rook/kubectl-rook-ceph/pkg/k8sutil ClientsetsInterface
type ClientsetsInterface interface {
	CreateResourcesDynamically(ctx context.Context, group string, version string, resource string, name *unstructured.Unstructured, namespace string) (*unstructured.Unstructured, error)
	ListResourcesDynamically(ctx context.Context, group string, version string, resource string, namespace string) ([]unstructured.Unstructured, error)
	GetResourcesDynamically(ctx context.Context, group string, version string, resource string, name string, namespace string) (*unstructured.Unstructured, error)
	DeleteResourcesDynamically(ctx context.Context, group string, version string, resource string, namespace string, resourceName string) error
	PatchResourcesDynamically(ctx context.Context, group string, version string, resource string, namespace string, resourceName string, pt types.PatchType, data []byte) error
}
07070100000041000081A4000000000000000000000001680F0E8800001210000000000000000000000000000000000000002F00000000kubectl-rook-ceph-0.9.4/pkg/k8sutil/k8sutil.go/*
Copyright 2023 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 k8sutil

import (
	"context"
	"fmt"
	"time"

	"github.com/rook/kubectl-rook-ceph/pkg/logging"

	appsv1 "k8s.io/api/apps/v1"
	autoscalingv1 "k8s.io/api/autoscaling/v1"
	corev1 "k8s.io/api/core/v1"
	k8sErrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/client-go/kubernetes"
)

func RestartDeployment(ctx context.Context, k8sclientset kubernetes.Interface, namespace, deploymentName string) {
	deploymentsClient := k8sclientset.AppsV1().Deployments(namespace)
	data := fmt.Sprintf(`{"spec": {"template": {"metadata": {"annotations": {"kubectl.kubernetes.io/restartedAt": "%s"}}}}}`, time.Now().String())
	_, err := deploymentsClient.Patch(ctx, deploymentName, types.StrategicMergePatchType, []byte(data), v1.PatchOptions{})
	if err != nil {
		logging.Error(fmt.Errorf("Failed to delete deployment %s: %v", deploymentName, err))
	}

	logging.Info("deployment.apps/%s restarted\n", deploymentName)
}

func WaitForPodToRun(ctx context.Context, k8sclientset kubernetes.Interface, namespace, labelSelector string) (corev1.Pod, error) {
	opts := v1.ListOptions{LabelSelector: labelSelector, FieldSelector: "status.phase=Running"}
	for i := 0; i < 60; i++ {
		pod, err := k8sclientset.CoreV1().Pods(namespace).List(ctx, opts)
		if err != nil {
			return corev1.Pod{}, fmt.Errorf("failed to list pods with labels matching %s", labelSelector)
		}
		if len(pod.Items) != 0 {
			if pod.Items[0].Status.Phase == corev1.PodRunning && pod.Items[0].DeletionTimestamp.IsZero() {
				return pod.Items[0], nil
			}
		}

		logging.Info("waiting for pod with label %q in namespace %q to be running", labelSelector, namespace)
		time.Sleep(time.Second * 5)
	}

	return corev1.Pod{}, fmt.Errorf("No pod with labels matching %s", labelSelector)
}

func UpdateConfigMap(ctx context.Context, k8sclientset kubernetes.Interface, namespace, configMapName, key, value string) {
	cm, err := k8sclientset.CoreV1().ConfigMaps(namespace).Get(ctx, configMapName, v1.GetOptions{})
	if err != nil {
		logging.Fatal(err)
	}

	if cm.Data == nil {
		cm.Data = map[string]string{}
	}

	cm.Data[key] = value
	_, err = k8sclientset.CoreV1().ConfigMaps(namespace).Update(ctx, cm, v1.UpdateOptions{})
	if err != nil {
		logging.Fatal(err)
	}

	logging.Info("configmap/%s patched\n", configMapName)
}

func SetDeploymentScale(ctx context.Context, k8sclientset kubernetes.Interface, namespace, deploymentName string, scaleCount int) error {
	scale := &autoscalingv1.Scale{
		ObjectMeta: v1.ObjectMeta{
			Name:      deploymentName,
			Namespace: namespace,
		},
		Spec: autoscalingv1.ScaleSpec{
			Replicas: int32(scaleCount),
		},
	}
	_, err := k8sclientset.AppsV1().Deployments(namespace).UpdateScale(ctx, deploymentName, scale, v1.UpdateOptions{})
	if err != nil {
		return fmt.Errorf("failed to update scale of deployment %s. %v\n", deploymentName, err)
	}
	return nil
}

func GetDeployment(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace, deploymentName string) (*appsv1.Deployment, error) {
	logging.Info("fetching the deployment %s to be running\n", deploymentName)
	deployment, err := k8sclientset.AppsV1().Deployments(clusterNamespace).Get(ctx, deploymentName, v1.GetOptions{})
	if err != nil {
		return nil, err
	}

	logging.Info("deployment %s exists\n", deploymentName)
	return deployment, nil
}

func DeleteDeployment(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace string, deployment string) {
	logging.Info("removing deployment %s", deployment)
	var gracePeriod int64
	propagation := metav1.DeletePropagationForeground
	options := &metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod, PropagationPolicy: &propagation}

	err := k8sclientset.AppsV1().Deployments(clusterNamespace).Delete(ctx, deployment, *options)
	if err != nil {
		if k8sErrors.IsNotFound(err) {
			logging.Info("the server could not find the requested deployment: %s", deployment)
			return
		}
		logging.Fatal(err)
	}
}
07070100000042000081A4000000000000000000000001680F0E8800001505000000000000000000000000000000000000002D00000000kubectl-rook-ceph-0.9.4/pkg/k8sutil/mocks.go// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/rook/kubectl-rook-ceph/pkg/k8sutil (interfaces: ClientsetsInterface)

// Package k8sutil is a generated GoMock package.
package k8sutil

import (
	context "context"
	reflect "reflect"

	gomock "github.com/golang/mock/gomock"
	unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	types "k8s.io/apimachinery/pkg/types"
)

// MockClientsetsInterface is a mock of ClientsetsInterface interface.
type MockClientsetsInterface struct {
	ctrl     *gomock.Controller
	recorder *MockClientsetsInterfaceMockRecorder
}

// MockClientsetsInterfaceMockRecorder is the mock recorder for MockClientsetsInterface.
type MockClientsetsInterfaceMockRecorder struct {
	mock *MockClientsetsInterface
}

// NewMockClientsetsInterface creates a new mock instance.
func NewMockClientsetsInterface(ctrl *gomock.Controller) *MockClientsetsInterface {
	mock := &MockClientsetsInterface{ctrl: ctrl}
	mock.recorder = &MockClientsetsInterfaceMockRecorder{mock}
	return mock
}

// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockClientsetsInterface) EXPECT() *MockClientsetsInterfaceMockRecorder {
	return m.recorder
}

// CreateResourcesDynamically mocks base method.
func (m *MockClientsetsInterface) CreateResourcesDynamically(arg0 context.Context, arg1, arg2, arg3 string, arg4 *unstructured.Unstructured, arg5 string) (*unstructured.Unstructured, error) {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "CreateResourcesDynamically", arg0, arg1, arg2, arg3, arg4, arg5)
	ret0, _ := ret[0].(*unstructured.Unstructured)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// CreateResourcesDynamically indicates an expected call of CreateResourcesDynamically.
func (mr *MockClientsetsInterfaceMockRecorder) CreateResourcesDynamically(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateResourcesDynamically", reflect.TypeOf((*MockClientsetsInterface)(nil).CreateResourcesDynamically), arg0, arg1, arg2, arg3, arg4, arg5)
}

// DeleteResourcesDynamically mocks base method.
func (m *MockClientsetsInterface) DeleteResourcesDynamically(arg0 context.Context, arg1, arg2, arg3, arg4, arg5 string) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "DeleteResourcesDynamically", arg0, arg1, arg2, arg3, arg4, arg5)
	ret0, _ := ret[0].(error)
	return ret0
}

// DeleteResourcesDynamically indicates an expected call of DeleteResourcesDynamically.
func (mr *MockClientsetsInterfaceMockRecorder) DeleteResourcesDynamically(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteResourcesDynamically", reflect.TypeOf((*MockClientsetsInterface)(nil).DeleteResourcesDynamically), arg0, arg1, arg2, arg3, arg4, arg5)
}

// GetResourcesDynamically mocks base method.
func (m *MockClientsetsInterface) GetResourcesDynamically(arg0 context.Context, arg1, arg2, arg3, arg4, arg5 string) (*unstructured.Unstructured, error) {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "GetResourcesDynamically", arg0, arg1, arg2, arg3, arg4, arg5)
	ret0, _ := ret[0].(*unstructured.Unstructured)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// GetResourcesDynamically indicates an expected call of GetResourcesDynamically.
func (mr *MockClientsetsInterfaceMockRecorder) GetResourcesDynamically(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResourcesDynamically", reflect.TypeOf((*MockClientsetsInterface)(nil).GetResourcesDynamically), arg0, arg1, arg2, arg3, arg4, arg5)
}

// ListResourcesDynamically mocks base method.
func (m *MockClientsetsInterface) ListResourcesDynamically(arg0 context.Context, arg1, arg2, arg3, arg4 string) ([]unstructured.Unstructured, error) {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "ListResourcesDynamically", arg0, arg1, arg2, arg3, arg4)
	ret0, _ := ret[0].([]unstructured.Unstructured)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

// ListResourcesDynamically indicates an expected call of ListResourcesDynamically.
func (mr *MockClientsetsInterfaceMockRecorder) ListResourcesDynamically(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListResourcesDynamically", reflect.TypeOf((*MockClientsetsInterface)(nil).ListResourcesDynamically), arg0, arg1, arg2, arg3, arg4)
}

// PatchResourcesDynamically mocks base method.
func (m *MockClientsetsInterface) PatchResourcesDynamically(arg0 context.Context, arg1, arg2, arg3, arg4, arg5 string, arg6 types.PatchType, arg7 []byte) error {
	m.ctrl.T.Helper()
	ret := m.ctrl.Call(m, "PatchResourcesDynamically", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
	ret0, _ := ret[0].(error)
	return ret0
}

// PatchResourcesDynamically indicates an expected call of PatchResourcesDynamically.
func (mr *MockClientsetsInterfaceMockRecorder) PatchResourcesDynamically(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7 interface{}) *gomock.Call {
	mr.mock.ctrl.T.Helper()
	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PatchResourcesDynamically", reflect.TypeOf((*MockClientsetsInterface)(nil).PatchResourcesDynamically), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
}
07070100000043000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002400000000kubectl-rook-ceph-0.9.4/pkg/logging07070100000044000081A4000000000000000000000001680F0E88000005FC000000000000000000000000000000000000002B00000000kubectl-rook-ceph-0.9.4/pkg/logging/log.go/*
Copyright 2023 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 logging

import (
	"fmt"
	"os"

	"github.com/fatih/color"
)

func Info(output string, args ...interface{}) {
	blue := color.New(color.FgBlue).SprintFunc()
	if output != "" {
		fmt.Fprintf(os.Stderr, blue("Info: "))
		fmt.Fprintf(os.Stderr, output, args...)
	}

	fmt.Fprintf(os.Stderr, "\n")
}

func Warning(output string, args ...interface{}) {
	yellow := color.New(color.FgYellow).SprintFunc()
	fmt.Fprintf(os.Stderr, yellow("Warning: "))
	fmt.Fprintf(os.Stderr, output, args...)
	fmt.Fprintf(os.Stderr, "\n")
}

func Error(err error, args ...interface{}) {
	red := color.New(color.FgRed).SprintFunc()
	fmt.Fprintf(os.Stderr, red("Error: "))
	fmt.Fprintf(os.Stderr, err.Error(), args...)
	fmt.Fprintf(os.Stderr, "\n")
}

func Fatal(err error, args ...interface{}) {
	red := color.New(color.FgRed).SprintFunc()
	fmt.Fprintf(os.Stderr, red("Error: "))
	fmt.Fprintf(os.Stderr, err.Error(), args...)
	fmt.Fprintf(os.Stderr, "\n")
	os.Exit(1)
}
07070100000045000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002800000000kubectl-rook-ceph-0.9.4/pkg/maintenance07070100000046000081A4000000000000000000000001680F0E88000010F1000000000000000000000000000000000000003D00000000kubectl-rook-ceph-0.9.4/pkg/maintenance/start_maintenance.go/*
Copyright 2023 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 maintenance

import (
	"context"
	"fmt"
	"time"

	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"

	appsv1 "k8s.io/api/apps/v1"
	kerrors "k8s.io/apimachinery/pkg/api/errors"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

func StartMaintenance(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace, deploymentName, alternateImageValue string) {
	err := startmaintenance(ctx, k8sclientset, clusterNamespace, deploymentName, alternateImageValue)
	if err != nil {
		logging.Fatal(err)
	}
}

func startmaintenance(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace, deploymentName, alternateImageValue string) error {
	originalDeployment, err := k8sutil.GetDeployment(ctx, k8sclientset, clusterNamespace, deploymentName)
	if err != nil {
		return fmt.Errorf("Missing mon or osd deployment name %s. %v\n", deploymentName, err)
	}

	// We need to dereference the deployment as it is required for the maintenance deployment
	deployment := *originalDeployment

	if alternateImageValue != "" {
		logging.Info("setting maintenance image to %s\n", alternateImageValue)
		deployment.Spec.Template.Spec.Containers[0].Image = alternateImageValue
	}

	labels := deployment.Labels
	labels["ceph.rook.io/do-not-reconcile"] = "true"

	deployment.Spec.Template.Spec.Containers[0].LivenessProbe = nil
	deployment.Spec.Template.Spec.Containers[0].StartupProbe = nil

	logging.Info("setting maintenance command to main container")

	deployment.Spec.Template.Spec.Containers[0].Command = []string{"sleep", "infinity"}
	deployment.Spec.Template.Spec.Containers[0].Args = []string{}

	labelSelector := fmt.Sprintf("ceph_daemon_type=%s,ceph_daemon_id=%s", deployment.Spec.Template.Labels["ceph_daemon_type"], deployment.Spec.Template.Labels["ceph_daemon_id"])
	deploymentPodName, err := k8sutil.WaitForPodToRun(ctx, k8sclientset, clusterNamespace, labelSelector)
	if err != nil {
		return err
	}

	if err := k8sutil.SetDeploymentScale(ctx, k8sclientset, clusterNamespace, deployment.Name, 0); err != nil {
		return err
	}

	logging.Info("deployment %s scaled down\n", deployment.Name)
	logging.Info("waiting for the deployment pod %s to be deleted\n", deploymentPodName.Name)

	err = waitForPodDeletion(ctx, k8sclientset, clusterNamespace, deploymentName)
	if err != nil {
		return err
	}

	maintenanceDeploymentSpec := &appsv1.Deployment{
		ObjectMeta: v1.ObjectMeta{
			Name:      fmt.Sprintf("%s-maintenance", deploymentName),
			Namespace: clusterNamespace,
			Labels:    labels,
		},
		Spec: deployment.Spec,
	}

	maintenanceDeployment, err := k8sclientset.AppsV1().Deployments(clusterNamespace).Create(ctx, maintenanceDeploymentSpec, v1.CreateOptions{})
	if err != nil {
		return fmt.Errorf("Error creating deployment %s. %v\n", maintenanceDeploymentSpec, err)
	}
	logging.Info("ensure the maintenance deployment %s is scaled up\n", deploymentName)

	if err := k8sutil.SetDeploymentScale(ctx, k8sclientset, clusterNamespace, maintenanceDeployment.Name, 1); err != nil {
		return err
	}

	pod, err := k8sutil.WaitForPodToRun(ctx, k8sclientset, clusterNamespace, labelSelector)
	if err != nil {
		logging.Fatal(err)
	}

	logging.Info("pod %s is ready for maintenance operations", pod.Name)
	return nil
}

func waitForPodDeletion(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace, podName string) error {
	for i := 0; i < 60; i++ {
		_, err := k8sclientset.CoreV1().Pods(clusterNamespace).Get(ctx, podName, v1.GetOptions{})
		if kerrors.IsNotFound(err) {
			return nil
		}

		logging.Info("waiting for pod %q to be deleted\n", podName)
		time.Sleep(time.Second * 5)
	}

	return fmt.Errorf("failed to delete pod %s", podName)
}
07070100000047000081A4000000000000000000000001680F0E88000008DB000000000000000000000000000000000000003C00000000kubectl-rook-ceph-0.9.4/pkg/maintenance/stop_maintenance.go/*
Copyright 2023 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 maintenance

import (
	"context"
	"fmt"
	"strings"

	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"

	kerrors "k8s.io/apimachinery/pkg/api/errors"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

func StopMaintenance(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace, deploymentName string) {

	err := stopMaintenance(ctx, k8sclientset, clusterNamespace, deploymentName)
	if err != nil {
		logging.Fatal(err)
	}
}

func stopMaintenance(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace, deploymentName string) error {
	if !strings.HasSuffix(deploymentName, "-maintenance") {
		deploymentName = deploymentName + "-maintenance"
	}

	maintenanceDeployment, err := k8sutil.GetDeployment(ctx, k8sclientset, clusterNamespace, deploymentName)
	if err != nil {
		return fmt.Errorf("Missing mon or osd maintenance deployment name %s. %v\n", deploymentName, err)
	}

	logging.Info("removing maintenance mode from deployment %s\n", maintenanceDeployment.Name)
	err = k8sclientset.AppsV1().Deployments(clusterNamespace).Delete(ctx, maintenanceDeployment.Name, v1.DeleteOptions{})
	if err != nil && !kerrors.IsNotFound(err) {
		return fmt.Errorf("Error deleting deployment %s: %v", maintenanceDeployment.Name, err)
	}

	original_deployment_name := strings.ReplaceAll(deploymentName, "-maintenance", "")
	if err := k8sutil.SetDeploymentScale(ctx, k8sclientset, clusterNamespace, original_deployment_name, 1); err != nil {
		return err
	}
	logging.Info("Successfully deleted maintenance deployment and restored deployment %q", original_deployment_name)
	return nil
}
07070100000048000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002100000000kubectl-rook-ceph-0.9.4/pkg/mons07070100000049000081A4000000000000000000000001680F0E8800000696000000000000000000000000000000000000003200000000kubectl-rook-ceph-0.9.4/pkg/mons/mon_endpoints.go/*
Copyright 2023 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 mons

import (
	"context"
	"fmt"
	"net"
	"regexp"

	"github.com/rook/kubectl-rook-ceph/pkg/logging"

	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

const MonConfigMap = "rook-ceph-mon-endpoints"

func ParseMonEndpoint(monEndpoint string) (string, string, error) {
	host, port, err := net.SplitHostPort(monEndpoint)
	if err != nil {
		return "", "", fmt.Errorf("failed to split host and port from endpoint %s: %v", monEndpoint, err)
	}

	if ip := net.ParseIP(host); ip == nil {
		return "", "", fmt.Errorf("invalid IP address in endpoint: %s", host)
	}

	return host, port, nil
}

func GetMonEndpoint(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace string) string {
	monCm, err := k8sclientset.CoreV1().ConfigMaps(clusterNamespace).Get(ctx, MonConfigMap, v1.GetOptions{})
	if err != nil {
		logging.Error(fmt.Errorf("failed to get mon configmap %s %v", MonConfigMap, err))
	}

	monData := monCm.Data["data"]
	reg, err := regexp.Compile("[^0-9,.:]+")
	if err != nil {
		logging.Fatal(err)
	}
	return reg.ReplaceAllLiteralString(monData, "")
}
0707010000004A000081A4000000000000000000000001680F0E8800000BD5000000000000000000000000000000000000003700000000kubectl-rook-ceph-0.9.4/pkg/mons/mon_endpoints_test.go/*
Copyright 2023 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 mons

import (
	"context"
	"testing"

	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/stretchr/testify/assert"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes/fake"
)

func TestParseMonEndpoint(t *testing.T) {
	tests := []struct {
		name         string
		endpoint     string
		expectedHost string
		expectedPort string
		expectError  bool
	}{
		{
			name:         "Valid IPv4 endpoint",
			endpoint:     "192.168.1.1:6789",
			expectedHost: "192.168.1.1",
			expectedPort: "6789",
			expectError:  false,
		},
		{
			name:         "Valid IPv6 endpoint",
			endpoint:     "[2001:db8::1]:6789",
			expectedHost: "2001:db8::1",
			expectedPort: "6789",
			expectError:  false,
		},
		{
			name:         "Invalid endpoint - missing port",
			endpoint:     "192.168.1.1",
			expectedHost: "",
			expectedPort: "",
			expectError:  true,
		},
		{
			name:         "Invalid endpoint - invalid IPv4 address",
			endpoint:     "192.168.1.300:6789",
			expectedHost: "",
			expectedPort: "",
			expectError:  true,
		},
		{
			name:         "Invalid endpoint - invalid IPv6 format",
			endpoint:     "2001:db8::1:6789",
			expectedHost: "",
			expectedPort: "",
			expectError:  true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			host, port, err := ParseMonEndpoint(tt.endpoint)

			if (err != nil) != tt.expectError {
				t.Errorf("ParseMonEndpoint() error = %v, expectError = %v", err, tt.expectError)
				return
			}

			if tt.expectError {
				return
			}

			if host != tt.expectedHost {
				t.Errorf("ParseMonEndpoint() host = %v, expected %v", host, tt.expectedHost)
			}
			if port != tt.expectedPort {
				t.Errorf("ParseMonEndpoint() port = %v, expected %v", port, tt.expectedPort)
			}
		})
	}
}

func TestGetMonEndpoint(t *testing.T) {
	ctx := context.TODO()
	newClient := fake.NewSimpleClientset
	k8s := newClient()
	clientsets := k8sutil.Clientsets{
		Kube: k8s,
	}
	ns := "rook-ceph"
	cm := &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      MonConfigMap,
			Namespace: ns,
		},
		Data: map[string]string{
			"data": "10.96.52.53:6789",
		},
	}
	_, err := clientsets.Kube.CoreV1().ConfigMaps(ns).Create(ctx, cm, metav1.CreateOptions{})
	assert.NoError(t, err)
	monData := GetMonEndpoint(context.TODO(), clientsets.Kube, ns)
	assert.Equal(t, "10.96.52.53:6789", monData)
	assert.NotEqual(t, "10.96.52.54:6789", monData)
}
0707010000004B000081A4000000000000000000000001680F0E880000336A000000000000000000000000000000000000003300000000kubectl-rook-ceph-0.9.4/pkg/mons/restore_quorum.go/*
Copyright 2023 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 mons

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/rook/kubectl-rook-ceph/pkg/exec"
	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	"github.com/rook/kubectl-rook-ceph/pkg/maintenance"

	kerrors "k8s.io/apimachinery/pkg/api/errors"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
)

func RestoreQuorum(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace, goodMon string) {
	err := validateMonIsUp(ctx, clientsets, clusterNamespace, goodMon)
	if err != nil {
		logging.Fatal(err)
	}

	err = restoreQuorum(ctx, clientsets, operatorNamespace, clusterNamespace, goodMon)
	if err != nil {
		logging.Fatal(err)
	}
}

func restoreQuorum(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace, goodMon string) error {
	monCm, err := clientsets.Kube.CoreV1().ConfigMaps(clusterNamespace).Get(ctx, MonConfigMap, v1.GetOptions{})
	if err != nil {
		return fmt.Errorf("failed to get mon configmap %s %v", MonConfigMap, err)
	}

	monData := monCm.Data["data"]
	monEndpoints := strings.Split(monData, ",")

	badMons, goodMonPublicIp, goodMonPort, err := getMonDetails(goodMon, monEndpoints)
	if err != nil {
		return err
	}

	if goodMonPublicIp == "" {
		return fmt.Errorf("good mon %s not found", goodMon)
	}

	fsidSecret, err := clientsets.Kube.CoreV1().Secrets(clusterNamespace).Get(ctx, "rook-ceph-mon", v1.GetOptions{})
	if err != nil {
		return fmt.Errorf("failed to get mon configmap %s %v", MonConfigMap, err)
	}

	cephFsid := string(fsidSecret.Data["fsid"])
	if cephFsid == "" {
		return fmt.Errorf("ceph cluster fsid not found")
	}

	logging.Info("printing fsid secret %s\n", cephFsid)
	logging.Info("Check for the running toolbox")

	_, err = k8sutil.GetDeployment(ctx, clientsets.Kube, clusterNamespace, "rook-ceph-tools")
	if err != nil {
		return fmt.Errorf("failed to deployment rook-ceph-tools. %v", err)
	}

	toolBox, err := k8sutil.WaitForPodToRun(ctx, clientsets.Kube, clusterNamespace, "app=rook-ceph-tools")
	if err != nil || toolBox.Name == "" {
		return fmt.Errorf("failed to get the running toolbox")
	}

	logging.Info("Restoring mon quorum to mon %s %s\n", goodMon, goodMonPublicIp)
	logging.Info("The mons to discard are: %s\n", badMons)
	logging.Info("The cluster fsid is %s\n", cephFsid)

	var answer string
	logging.Warning("Are you sure you want to restore the quorum to mon %s? If so, enter 'yes-really-restore'\n", goodMon)
	fmt.Scanf("%s", &answer)
	err = PromptToContinueOrCancel("yes-really-restore", answer)
	if err != nil {
		return fmt.Errorf("restoring the mon quorum for mon %s is cancelled. Got %s want 'yes-really-restore'", goodMon, answer)
	}
	logging.Info("proceeding with resorting quorum")

	logging.Info("Waiting for operator pod to stop")
	err = k8sutil.SetDeploymentScale(ctx, clientsets.Kube, operatorNamespace, "rook-ceph-operator", 0)
	if err != nil {
		return fmt.Errorf("failed to stop deployment rook-ceph-operator. %v", err)
	}
	logging.Info("rook-ceph-operator deployment scaled down")

	logging.Info("Waiting for bad mon pod to stop")
	for _, badMon := range badMons {
		err = k8sutil.SetDeploymentScale(ctx, clientsets.Kube, clusterNamespace, fmt.Sprintf("rook-ceph-mon-%s", badMon), 0)
		if err != nil {
			return fmt.Errorf("deployment %s still exist. %v", fmt.Sprintf("rook-ceph-mon-%s", badMon), err)
		}
		logging.Info("deployment.apps/%s scaled\n", fmt.Sprintf("rook-ceph-mon-%s", badMon))
	}

	maintenance.StartMaintenance(ctx, clientsets.Kube, clusterNamespace, fmt.Sprintf("rook-ceph-mon-%s", goodMon), "")

	maintenanceDeploymentSpec, err := k8sutil.GetDeployment(ctx, clientsets.Kube, clusterNamespace, fmt.Sprintf("rook-ceph-mon-%s-maintenance", goodMon))
	if err != nil {
		return fmt.Errorf("failed to deployment rook-ceph-mon-%s-maintenance", goodMon)
	}

	labelSelector := fmt.Sprintf("ceph_daemon_type=%s,ceph_daemon_id=%s", maintenanceDeploymentSpec.Spec.Template.Labels["ceph_daemon_type"], maintenanceDeploymentSpec.Spec.Template.Labels["ceph_daemon_id"])
	_, err = k8sutil.WaitForPodToRun(ctx, clientsets.Kube, clusterNamespace, labelSelector)
	if err != nil {
		return fmt.Errorf("failed to start deployment %s", fmt.Sprintf("rook-ceph-mon-%s-maintenance", goodMon))
	}

	updateMonMap(ctx, clientsets, clusterNamespace, labelSelector, cephFsid, goodMon, goodMonPublicIp, badMons)

	logging.Info("Restoring the mons in the rook-ceph-mon-endpoints configmap to the good mon")
	monCm.Data["data"] = fmt.Sprintf("%s=%s:%s", goodMon, goodMonPublicIp, goodMonPort)

	_, err = clientsets.Kube.CoreV1().ConfigMaps(clusterNamespace).Update(ctx, monCm, v1.UpdateOptions{})
	if err != nil {
		logging.Error(fmt.Errorf("failed to update mon configmap %s %v", MonConfigMap, err))
	}

	logging.Info("Stopping the maintenance pod for mon %s.\n", goodMon)
	maintenance.StopMaintenance(ctx, clientsets.Kube, clusterNamespace, fmt.Sprintf("rook-ceph-mon-%s", goodMon))

	logging.Info("Check that the restored mon is responding")
	err = waitForMonStatusResponse(ctx, clientsets, clusterNamespace)
	if err != nil {
		return err
	}

	err = removeBadMonsResources(ctx, clientsets.Kube, clusterNamespace, badMons)
	if err != nil {
		return err
	}

	logging.Info("Mon quorum was successfully restored to mon %s\n", goodMon)
	logging.Info("Only a single mon is currently running")
	logging.Info("Enter 'continue' to start the operator and expand to full mon quorum again")

	fmt.Scanln(&answer)
	err = PromptToContinueOrCancel("continue", answer)
	if err != nil {
		return fmt.Errorf("skipping operator start to expand full mon quorum. %s", answer)
	}
	logging.Info("proceeding with resorting quorum")

	err = k8sutil.SetDeploymentScale(ctx, clientsets.Kube, operatorNamespace, "rook-ceph-operator", 1)
	if err != nil {
		return fmt.Errorf("failed to start deployment rook-ceph-operator. %v", err)
	}

	return nil
}

func updateMonMap(ctx context.Context, clientsets *k8sutil.Clientsets, clusterNamespace, labelSelector, cephFsid, goodMon, goodMonPublicIp string, badMons []string) {
	logging.Info("Started maintenance pod, restoring the mon quorum in the maintenance pod")

	monmapPath := "/tmp/monmap"

	monMapArgs := []string{
		fmt.Sprintf("--fsid=%s", cephFsid),
		"--keyring=/etc/ceph/keyring-store/keyring",
		"--log-to-stderr=true",
		"--err-to-stderr=true",
		"--mon-cluster-log-to-stderr=true",
		"--log-stderr-prefix=debug",
		"--default-log-to-file=false",
		"--default-mon-cluster-log-to-file=false",
		"--mon-host=$(ROOK_CEPH_MON_HOST)",
		"--mon-initial-members=$(ROOK_CEPH_MON_INITIAL_MEMBERS)",
		fmt.Sprintf("--id=%s", goodMon),
		"--foreground",
		fmt.Sprintf("--public-addr=%s", goodMonPublicIp),
		fmt.Sprintf("--setuser-match-path=/var/lib/ceph/mon/ceph-%s/store.db", goodMon),
	}

	extractMonMap := []string{fmt.Sprintf("--extract-monmap=%s", monmapPath)}
	extractMonMapArgs := append(monMapArgs, extractMonMap...)

	logging.Info("Extracting the monmap")
	_, err := exec.RunCommandInLabeledPod(ctx, clientsets, labelSelector, "mon", "ceph-mon", extractMonMapArgs, clusterNamespace, false)
	if err != nil {
		logging.Fatal(err, "failed to extract monmap")
	}

	logging.Info("Printing monmap")
	_, err = exec.RunCommandInLabeledPod(ctx, clientsets, labelSelector, "mon", "monmaptool", []string{"--print", monmapPath}, clusterNamespace, false)
	if err != nil {
		logging.Fatal(err, "failed to print monmap")
	}

	// remove all the mons except the good one
	for _, badMonId := range badMons {
		logging.Info("Removing mon %s.\n", badMonId)
		_, err = exec.RunCommandInLabeledPod(ctx, clientsets, labelSelector, "mon", "monmaptool", []string{monmapPath, "--rm", badMonId}, clusterNamespace, false)
		if err != nil {
			logging.Fatal(err, "failed to remove mon %s", badMonId)
		}
	}

	injectMonMap := []string{fmt.Sprintf("--inject-monmap=%s", monmapPath)}
	injectMonMapArgs := append(monMapArgs, injectMonMap...)

	logging.Info("Injecting the monmap")
	_, err = exec.RunCommandInLabeledPod(ctx, clientsets, labelSelector, "mon", "ceph-mon", injectMonMapArgs, clusterNamespace, false)
	if err != nil {
		logging.Fatal(err, "failed to inject the monmap")
	}

	logging.Info("Finished updating the monmap!")

	logging.Info("Printing final monmap")
	_, err = exec.RunCommandInLabeledPod(ctx, clientsets, labelSelector, "mon", "monmaptool", []string{"--print", monmapPath}, clusterNamespace, false)
	if err != nil {
		logging.Fatal(err, "failed to print final monmap")
	}
}

func removeBadMonsResources(ctx context.Context, k8sclientset kubernetes.Interface, clusterNamespace string, badMons []string) error {
	logging.Info("Purging the bad mons %v\n", badMons)

	for _, badMon := range badMons {
		logging.Info("purging bad mon: %s\n", badMon)
		err := k8sclientset.AppsV1().Deployments(clusterNamespace).Delete(ctx, fmt.Sprintf("rook-ceph-mon-%s", badMon), v1.DeleteOptions{})
		if err != nil {
			return fmt.Errorf("failed to delete deployment %s", fmt.Sprintf("rook-ceph-mon-%s", badMon))
		}
		err = k8sclientset.CoreV1().Services(clusterNamespace).Delete(ctx, fmt.Sprintf("rook-ceph-mon-%s", badMon), v1.DeleteOptions{})
		if err != nil && !kerrors.IsNotFound(err) {
			return fmt.Errorf("failed to delete service %s", fmt.Sprintf("rook-ceph-mon-%s", badMon))
		}

		err = k8sclientset.CoreV1().PersistentVolumeClaims(clusterNamespace).Delete(ctx, fmt.Sprintf("rook-ceph-mon-%s", badMon), v1.DeleteOptions{})
		if err != nil && !kerrors.IsNotFound(err) {
			return fmt.Errorf("failed to delete pvc %s", fmt.Sprintf("rook-ceph-mon-%s", badMon))
		}
	}
	return nil
}

func wait(i int, output string) {
	logging.Info("%d: waiting for ceph status to confirm single mon quorum. \n", i+1)
	logging.Info("current ceph status output %s\n", output)
	logging.Info("sleeping for 5 seconds")
	time.Sleep(5 * time.Second)
}

func waitForMonStatusResponse(ctx context.Context, clientsets *k8sutil.Clientsets, clusterNamespace string) error {
	maxRetries := 20

	for i := 0; i < maxRetries; i++ {
		output, err := exec.RunCommandInToolboxPod(ctx, clientsets, "ceph", []string{"status"}, clusterNamespace, true)
		if err != nil {
			logging.Error(fmt.Errorf("failed to get the status of ceph cluster. %v", err))
			wait(i, "")
			continue
		}
		if strings.Contains(output, "HEALTH_WARN") || strings.Contains(output, "HEALTH_OK") || strings.Contains(output, "HEALTH_ERROR") {
			logging.Info("finished waiting for ceph status %s\n", output)
			break
		}
		if i == maxRetries-1 {
			return fmt.Errorf("timed out waiting for mon quorum to respond")
		}
		wait(i, output)
	}

	return nil
}

func getMonDetails(goodMon string, monEndpoints []string) ([]string, string, string, error) {
	var goodMonPublicIp, goodMonPort string
	var badMons []string

	for _, m := range monEndpoints {
		monName, monEndpoint, ok := strings.Cut(m, "=")
		if !ok {
			return []string{}, "", "", fmt.Errorf("failed to fetch mon endpoint")
		} else if monName == goodMon {
			host, port, err := ParseMonEndpoint(monEndpoint)
			if err != nil {
				return []string{}, "", "", err
			}

			goodMonPublicIp = host
			goodMonPort = port
		} else {
			badMons = append(badMons, monName)
		}
		logging.Info("mon=%s, endpoints=%s\n", monName, monEndpoint)
	}

	return badMons, goodMonPublicIp, goodMonPort, nil
}

func validateMonIsUp(ctx context.Context, clientsets *k8sutil.Clientsets, clusterNamespace, monID string) error {
	args := []string{"daemon", fmt.Sprintf("mon.%s", monID), "mon_status"}
	out, err := exec.RunCommandInLabeledPod(ctx, clientsets, fmt.Sprintf("mon=%s", monID), "mon", "ceph", args, clusterNamespace, true)
	if err != nil {
		return fmt.Errorf("failed to run command ceph daemon mon.%s mon_status %v", monID, err)
	}

	type monStatus struct {
		State string `json:"state"`
	}
	var monStatusOut monStatus
	err = json.Unmarshal([]byte(out), &monStatusOut)
	if err != nil {
		return fmt.Errorf("failed to unmarshal mon stat output %v", err)
	}

	logging.Info("mon %q state is %q", monID, monStatusOut.State)

	if monStatusOut.State == "leader" || monStatusOut.State == "peon" || monStatusOut.State == "probing" {
		return nil
	}

	return fmt.Errorf("mon %q in %q state but must be in leader/peon state", monID, monStatusOut.State)
}

func PromptToContinueOrCancel(expectedAnswer, answer string) error {
	if skip, ok := os.LookupEnv("ROOK_PLUGIN_SKIP_PROMPTS"); ok && skip == "true" {
		logging.Info("skipped prompt since ROOK_PLUGIN_SKIP_PROMPTS=true")
		return nil
	}

	if answer == expectedAnswer {
		return nil
	}

	return fmt.Errorf("cancelled")
}
0707010000004C000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002000000000kubectl-rook-ceph-0.9.4/pkg/rbd0707010000004D000081A4000000000000000000000001680F0E8800001356000000000000000000000000000000000000002700000000kubectl-rook-ceph-0.9.4/pkg/rbd/rbd.gopackage 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"
)

type poolData struct {
	imageList     []string
	namespaceList []string
}

// ListImages retrieves and displays Ceph block pools and their associated images.
func ListImages(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace string) {
	blockPoolNames := fetchBlockPools(ctx, clientsets, clusterNamespace)
	blockPoolNames = fetchBlockPoolNamespaces(ctx, clientsets, clusterNamespace, blockPoolNames)
	retrieveRBDImages(ctx, clientsets, operatorNamespace, clusterNamespace, blockPoolNames)
	printBlockPoolNames(blockPoolNames)
}

// fetchBlockPools retrieves the list of CephBlockPools and initializes the poolData map.
func fetchBlockPools(ctx context.Context, clientsets *k8sutil.Clientsets, clusterNamespace string) map[string]poolData {
	blockPoolList, err := clientsets.Rook.CephV1().CephBlockPools(clusterNamespace).List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(fmt.Errorf("failed to list CephBlockPools: %w", err))
	}
	blockPoolNames := make(map[string]poolData)
	for _, blockPool := range blockPoolList.Items {
		if strings.Contains(blockPool.Name, "builtin") {
			continue
		}
		blockPoolNames[blockPool.Name] = poolData{
			imageList:     []string{},
			namespaceList: []string{},
		}
	}
	return blockPoolNames
}

// fetchBlockPoolNamespaces retrieves the CephBlockPoolRadosNamespaces and associates them with pools.
func fetchBlockPoolNamespaces(ctx context.Context, clientsets *k8sutil.Clientsets, clusterNamespace string, blockPoolNames map[string]poolData) map[string]poolData {
	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 {
		name := blockPoolNamespace.Spec.Name
		if name == "" {
			name = blockPoolNamespace.ObjectMeta.Name
		}

		if poolInfo, exists := blockPoolNames[blockPoolNamespace.Spec.BlockPoolName]; exists {
			poolInfo.namespaceList = append(poolInfo.namespaceList, name)
			blockPoolNames[blockPoolNamespace.Spec.BlockPoolName] = poolInfo
		}
	}
	return blockPoolNames
}

// retrieveRBDImages fetches RBD images for each pool and namespace.
func retrieveRBDImages(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace string, blockPoolNames map[string]poolData) {
	for poolName, poolInfo := range blockPoolNames {
		if len(poolInfo.namespaceList) == 0 {
			images, err := getRBDImages(ctx, clientsets, poolName, "", operatorNamespace, clusterNamespace)
			if err != nil {
				logging.Fatal(fmt.Errorf("failed to list images for pool %s: %w", poolName, err))
			}
			poolInfo.imageList = images
			blockPoolNames[poolName] = poolInfo
		} else {
			for _, namespace := range poolInfo.namespaceList {
				images, err := getRBDImages(ctx, clientsets, poolName, namespace, operatorNamespace, clusterNamespace)
				if err != nil {
					logging.Fatal(fmt.Errorf("failed to list images for pool %s and namespace %s: %w", poolName, namespace, err))
				}
				poolInfo.imageList = append(poolInfo.imageList, images...)
				blockPoolNames[poolName] = poolInfo
			}
		}
	}
}

// getRBDImages runs the RBD command to fetch images for a pool and namespace.
func getRBDImages(ctx context.Context, clientsets *k8sutil.Clientsets, poolName, namespace, operatorNamespace, clusterNamespace string) ([]string, error) {
	cmd := "rbd"
	args := []string{"ls", "--pool=" + poolName}
	if namespace != "" {
		args = append(args, "--namespace="+namespace)
	}
	output, err := exec.RunCommandInOperatorPod(ctx, clientsets, cmd, args, operatorNamespace, clusterNamespace, true)
	if err != nil {
		return nil, fmt.Errorf("failed to list RBD images: %w", err)
	}
	// Check if the output is empty
	if strings.TrimSpace(output) == "" {
		return []string{"---"}, nil
	}
	return strings.Fields(output), nil
}

// printBlockPoolNames prints the block pools and their associated images in a tabular format.
func printBlockPoolNames(blockPoolNames map[string]poolData) {
	writer := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	defer writer.Flush()

	fmt.Fprintln(writer, "poolName\timageName\tnamespace\t")
	fmt.Fprintln(writer, "--------\t---------\t---------\t")
	for poolName, poolInfo := range blockPoolNames {
		if len(poolInfo.namespaceList) == 0 {
			for _, image := range poolInfo.imageList {
				fmt.Fprintf(writer, "%s\t%s\t---\t\n", poolName, image)
			}
		} else {
			for i := 0; i < len(poolInfo.namespaceList); i++ {
				fmt.Fprintf(writer, "%s\t%s\t%s\t\n", poolName, poolInfo.imageList[i], poolInfo.namespaceList[i])
			}
		}
	}
}
0707010000004E000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002400000000kubectl-rook-ceph-0.9.4/pkg/restore0707010000004F000081A4000000000000000000000001680F0E8800002770000000000000000000000000000000000000002B00000000kubectl-rook-ceph-0.9.4/pkg/restore/crd.go/*
Copyright 2023 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 restore

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/pkg/errors"
	"github.com/rook/kubectl-rook-ceph/pkg/crds"
	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	"github.com/rook/kubectl-rook-ceph/pkg/mons"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/types"
)

type CustomResource struct {
	Group    string
	Version  string
	Resource string
}

func RestoreCrd(ctx context.Context, k8sclientset *k8sutil.Clientsets, operatorNamespace, clusterNamespace,
	groupName, versionResource, operatorName string, customResources []CustomResource, args []string) {
	crd := args[0]

	var crName string
	var crdResource unstructured.Unstructured
	if len(args) == 2 {
		crName = args[1]
	}

	logging.Info("Detecting which resources to restore for crd %q", crd)
	crdList, err := k8sclientset.ListResourcesDynamically(ctx, groupName, versionResource, crd, clusterNamespace)
	if err != nil {
		logging.Fatal(fmt.Errorf("Failed to list resources for crd %v", err))
	}
	if len(crdList) == 0 {
		logging.Info("No Ceph CRDs found to restore")
		return
	}

	for _, cr := range crdList {
		if cr.GetDeletionTimestamp() != nil && (crName == "" || crName == cr.GetName()) {
			crName = cr.GetName()
			crdResource = *cr.DeepCopy()
			break
		}
	}

	if crName == "" {
		logging.Info("Nothing to do here, no %q resources in deleted state", crd)
		return
	}

	logging.Info("Restoring CR %s", crName)
	var answer string
	logging.Warning("The resource %s was found deleted. Do you want to restore it? yes | no\n", crName)
	fmt.Scanf("%s", &answer)
	err = mons.PromptToContinueOrCancel("yes", answer)
	if err != nil {
		logging.Fatal(fmt.Errorf("Restoring the resource %s cancelled", crName))
	}
	logging.Info("Proceeding with restoring deleting CR")

	logging.Info("Scaling down the operator")
	err = k8sutil.SetDeploymentScale(ctx, k8sclientset.Kube, operatorNamespace, operatorName, 0)
	if err != nil {
		deploy, er := k8sutil.GetDeployment(ctx, k8sclientset.Kube, operatorNamespace, operatorName)
		if er != nil && !apierrors.IsNotFound(er) {
			logging.Fatal(er)
		}
		if deploy.Status.ReadyReplicas != 0 {
			logging.Fatal(fmt.Errorf("Failed to scale down the operator deployment. %v", err))
		}
	}

	webhookConfigName := "rook-ceph-webhook"
	logging.Info("Deleting validating webhook %s if present", webhookConfigName)
	err = k8sclientset.Kube.AdmissionregistrationV1().ValidatingWebhookConfigurations().Delete(ctx, webhookConfigName, v1.DeleteOptions{})
	if err != nil && !apierrors.IsNotFound(err) {
		logging.Fatal(fmt.Errorf("failed to delete validating webhook %s. %v", webhookConfigName, err))
	}

	removeOwnerRefOfUID(ctx, k8sclientset, operatorNamespace, clusterNamespace, string(crdResource.GetUID()), customResources)

	logging.Info("Removing finalizers from %s/%s", crd, crName)

	jsonPatchData, _ := json.Marshal(crds.DefaultResourceRemoveFinalizers)
	err = k8sclientset.PatchResourcesDynamically(ctx, groupName, versionResource, crd, clusterNamespace, crName, types.MergePatchType, jsonPatchData)
	if err != nil {
		logging.Fatal(fmt.Errorf("Failed to update resource %q for crd. %v", crName, err))
	}

	crdResource.SetResourceVersion("")
	crdResource.SetUID("")
	crdResource.SetSelfLink("")
	crdResource.SetCreationTimestamp(v1.Time{})
	logging.Info("Re-creating the CR %s from dynamic resource", crd)
	_, err = k8sclientset.CreateResourcesDynamically(ctx, groupName, versionResource, crd, &crdResource, clusterNamespace)
	if err != nil {
		logging.Fatal((fmt.Errorf("Failed to create updated resource %q for crd. %v", crName, err)))
	}

	logging.Info("Scaling up the operator")
	err = k8sutil.SetDeploymentScale(ctx, k8sclientset.Kube, operatorNamespace, operatorName, 1)
	if err != nil {
		logging.Fatal(errors.Wrapf(err, "Operator pod still being scaled up"))
	}

	logging.Info("CR is successfully restored. Please watch the operator logs and check the crd")
}

func removeOwnerRefOfUID(ctx context.Context, k8sclientset *k8sutil.Clientsets, operatorNamespace, clusterNamespace, targetUID string, customResources []CustomResource) {
	logging.Info("Removing ownerreferences from resources with matching uid %s", targetUID)

	for _, crd := range customResources {
		gvr := schema.GroupVersionResource{
			Group:    crd.Group,
			Version:  crd.Version,
			Resource: crd.Resource,
		}

		crList, err := k8sclientset.ListResourcesDynamically(ctx, crd.Group, crd.Version, crd.Resource, clusterNamespace)
		if err != nil {
			logging.Warning("Failed to list %s: %v", crd.Resource, err)
			continue
		}

		for _, cr := range crList {
			updated := false
			owners := cr.GetOwnerReferences()
			newOwners := []v1.OwnerReference{}

			for _, owner := range owners {
				if string(owner.UID) != targetUID {
					newOwners = append(newOwners, owner)
				} else {
					updated = true
				}
			}

			if updated {
				logging.Info("Removing ownerReference for %s/%s", crd.Resource, cr.GetName())
				cr.SetOwnerReferences(newOwners)

				_, err := k8sclientset.Dynamic.Resource(gvr).Namespace(clusterNamespace).Update(ctx, &cr, v1.UpdateOptions{})
				if err != nil {
					logging.Fatal(fmt.Errorf("Failed to update ownerReferences for %s/%s: %v", crd.Resource, cr.GetName(), err))
				}
			}
		}
	}
	secrets, err := k8sclientset.Kube.CoreV1().Secrets(clusterNamespace).List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(errors.Wrapf(err, "Failed to list secrets"))
	}

	for _, secret := range secrets.Items {
		for _, owner := range secret.OwnerReferences {
			if string(owner.UID) == targetUID {
				logging.Info("Removing owner references for secret %s", secret.Name)
				// Remove ownerReferences.
				secret.OwnerReferences = nil

				// Update the Secret without ownerReferences.
				_, err := k8sclientset.Kube.CoreV1().Secrets(clusterNamespace).Update(ctx, &secret, v1.UpdateOptions{})
				if err != nil {
					logging.Fatal(errors.Wrapf(err, "Failed to update ownerReferences for secret %s", secret.Name))
				}
				logging.Info("Removed ownerReference for Secret: %s\n", secret.Name)
			}
		}
	}

	cms, err := k8sclientset.Kube.CoreV1().ConfigMaps(clusterNamespace).List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(errors.Wrapf(err, "Failed to list configMaps"))
	}

	for _, cm := range cms.Items {
		for _, owner := range cm.OwnerReferences {
			if string(owner.UID) == targetUID {
				logging.Info("Removing owner references for configmaps %s", cm.Name)
				// Remove ownerReferences.
				cm.OwnerReferences = nil

				// Update the Secret without ownerReferences.
				_, err := k8sclientset.Kube.CoreV1().ConfigMaps(clusterNamespace).Update(ctx, &cm, v1.UpdateOptions{})
				if err != nil {
					logging.Fatal(errors.Wrapf(err, "Failed to update ownerReferences for configmaps %s", cm.Name))
				}
				logging.Info("Removed ownerReference for configmap: %s\n", cm.Name)
			}
		}
	}

	services, err := k8sclientset.Kube.CoreV1().Services(clusterNamespace).List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(errors.Wrapf(err, "Failed to list services"))
	}

	for _, service := range services.Items {
		for _, owner := range service.OwnerReferences {
			if string(owner.UID) == targetUID {
				logging.Info("Removing owner references for service %s", service.Name)
				// Remove ownerReferences.
				service.OwnerReferences = nil

				// Update the Secret without ownerReferences.
				_, err := k8sclientset.Kube.CoreV1().Services(clusterNamespace).Update(ctx, &service, v1.UpdateOptions{})
				if err != nil {
					logging.Fatal(errors.Wrapf(err, "Failed to update ownerReferences for service %s", service.Name))
				}
				logging.Info("Removed ownerReference for service: %s\n", service.Name)
			}
		}
	}

	deploys, err := k8sclientset.Kube.AppsV1().Deployments(clusterNamespace).List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(errors.Wrapf(err, "Failed to list deployments"))
	}

	for _, deploy := range deploys.Items {
		for _, owner := range deploy.OwnerReferences {
			if string(owner.UID) == targetUID {
				logging.Info("Removing owner references for deployment %s", deploy.Name)
				// Remove ownerReferences.
				deploy.OwnerReferences = nil

				// Update the Secret without ownerReferences.
				_, err := k8sclientset.Kube.AppsV1().Deployments(clusterNamespace).Update(ctx, &deploy, v1.UpdateOptions{})
				if err != nil {
					logging.Fatal(errors.Wrapf(err, "Failed to update ownerReferences for deployemt %s", deploy.Name))
				}
				logging.Info("Removed ownerReference for deployment: %s\n", deploy.Name)
			}
		}
	}

	pvcs, err := k8sclientset.Kube.CoreV1().PersistentVolumeClaims(clusterNamespace).List(ctx, v1.ListOptions{})
	if err != nil {
		logging.Fatal(errors.Wrapf(err, "Failed to list pvc"))
	}

	for _, pvc := range pvcs.Items {
		for _, owner := range pvc.OwnerReferences {
			if string(owner.UID) == targetUID {
				logging.Info("Removing owner references for pvc %s", pvc.Name)
				// Remove ownerReferences.
				pvc.OwnerReferences = nil

				// Update the Secret without ownerReferences.
				_, err := k8sclientset.Kube.CoreV1().PersistentVolumeClaims(clusterNamespace).Update(ctx, &pvc, v1.UpdateOptions{})
				if err != nil {
					logging.Fatal(errors.Wrapf(err, "Failed to update ownerReferences for pvc %s", pvc.Name))
				}
				logging.Info("Removed ownerReference for pvc: %s\n", pvc.Name)
			}
		}
	}
}
07070100000050000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000002100000000kubectl-rook-ceph-0.9.4/pkg/rook07070100000051000081A4000000000000000000000001680F0E88000007E4000000000000000000000000000000000000002E00000000kubectl-rook-ceph-0.9.4/pkg/rook/purge_osd.go/*
Copyright 2023 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 rook

import (
	"context"
	"fmt"

	exec "github.com/rook/kubectl-rook-ceph/pkg/exec"
	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	"github.com/rook/kubectl-rook-ceph/pkg/mons"

	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func PurgeOsds(ctx context.Context, clientsets *k8sutil.Clientsets, operatorNamespace, clusterNamespace, osdIds, flag string) {
	monCm, err := clientsets.Kube.CoreV1().ConfigMaps(clusterNamespace).Get(ctx, mons.MonConfigMap, v1.GetOptions{})
	if err != nil {
		logging.Fatal(fmt.Errorf("failed to get mon configmap %s %v", mons.MonConfigMap, err))
	}

	monEndPoint := monCm.Data["data"]
	cephArgs := []string{
		"auth", "print-key", "client.admin",
	}

	adminKey, err := exec.RunCommandInOperatorPod(ctx, clientsets, "ceph", cephArgs, operatorNamespace, clusterNamespace, true)
	if err != nil {
		logging.Fatal(err, "failed to get ceph key")
	}

	cmd := "/bin/sh"
	args := []string{
		"-c",
		fmt.Sprintf("export ROOK_MON_ENDPOINTS=%s ROOK_CEPH_USERNAME=client.admin ROOK_CEPH_SECRET=%s ROOK_CONFIG_DIR=/var/lib/rook && rook ceph osd remove --osd-ids=%s --force-osd-removal=%s", monEndPoint, adminKey, osdIds, flag),
	}
	logging.Info("Running purge osd command")

	_, err = exec.RunCommandInOperatorPod(ctx, clientsets, cmd, args, operatorNamespace, clusterNamespace, false)
	if err != nil {
		logging.Fatal(err, "failed to remove osd %s", osdIds)
	}
}
07070100000052000081A4000000000000000000000001680F0E8800000820000000000000000000000000000000000000002B00000000kubectl-rook-ceph-0.9.4/pkg/rook/status.go/*
Copyright 2023 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 rook

import (
	"context"
	"fmt"
	"os"

	"github.com/rook/kubectl-rook-ceph/pkg/crds"
	"github.com/rook/kubectl-rook-ceph/pkg/k8sutil"
	"github.com/rook/kubectl-rook-ceph/pkg/logging"
	"gopkg.in/yaml.v3"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

func PrintCustomResourceStatus(ctx context.Context, k8sclientset *k8sutil.Clientsets, clusterNamespace string, arg []string) {
	if len(arg) == 1 && arg[0] == "all" {
		for _, resource := range crds.CephResources {
			printStatus(ctx, k8sclientset, clusterNamespace, resource)
		}
	} else if len(arg) == 1 {
		printStatus(ctx, k8sclientset, clusterNamespace, arg[0])
	} else {
		printStatus(ctx, k8sclientset, clusterNamespace, "cephclusters")
	}

}

func printStatus(ctx context.Context, k8sclientset *k8sutil.Clientsets, clusterNamespace, resource string) {
	items, err := k8sclientset.ListResourcesDynamically(ctx, crds.CephRookIoGroup, crds.CephRookResourcesVersion, resource, clusterNamespace)
	if err != nil {
		logging.Fatal(err)
	}

	if len(items) == 0 {
		logging.Info("resource %s was not found on the cluster", resource)
	}

	for _, crResource := range items {
		status, _, err := unstructured.NestedMap(crResource.Object, "status")
		if err != nil {
			fmt.Printf("Error accessing 'status': %v\n", err)
			os.Exit(1)
		}
		statusYamlData, err := yaml.Marshal(status)
		if err != nil {
			logging.Fatal(err)
		}
		logging.Info(fmt.Sprint(resource, " ", crResource.GetName()))
		fmt.Println(string(statusYamlData))
	}
}
07070100000053000041ED000000000000000000000002680F0E8800000000000000000000000000000000000000000000001E00000000kubectl-rook-ceph-0.9.4/tests07070100000054000081ED000000000000000000000001680F0E8800000AFE000000000000000000000000000000000000002E00000000kubectl-rook-ceph-0.9.4/tests/collect-logs.sh#!/usr/bin/env bash

set -x

# User parameters
: "${CLUSTER_NAMESPACE:="rook-ceph"}"
: "${OPERATOR_NAMESPACE:="$CLUSTER_NAMESPACE"}"
: "${LOG_DIR:="test"}"

LOG_DIR="${LOG_DIR%/}" # remove trailing slash if necessary
mkdir -p "${LOG_DIR}"

CEPH_CMD="kubectl -n ${CLUSTER_NAMESPACE} exec deploy/rook-ceph-tools -- ceph --connect-timeout 10"

$CEPH_CMD -s >"${LOG_DIR}"/ceph-status.txt
$CEPH_CMD osd dump >"${LOG_DIR}"/ceph-osd-dump.txt
$CEPH_CMD report >"${LOG_DIR}"/ceph-report.txt

NAMESPACES=("$CLUSTER_NAMESPACE")
if [[ "$OPERATOR_NAMESPACE" != "$CLUSTER_NAMESPACE" ]]; then
    NAMESPACES+=("$OPERATOR_NAMESPACE")
fi

for NAMESPACE in "${NAMESPACES[@]}"; do
    # each namespace is a sub-directory for easier debugging
    NS_DIR="${LOG_DIR}"/namespace-"${NAMESPACE}"
    mkdir "${NS_DIR}"

    # describe every one of the k8s resources in the namespace which rook commonly uses
    for KIND in 'pod' 'deployment' 'job' 'daemonset' 'cm'; do
        kubectl -n "$NAMESPACE" get "$KIND" -o wide >"${NS_DIR}"/"$KIND"-list.txt
        for resource in $(kubectl -n "$NAMESPACE" get "$KIND" -o jsonpath='{.items[*].metadata.name}'); do
            kubectl -n "$NAMESPACE" describe "$KIND" "$resource" >"${NS_DIR}"/"$KIND"-describe--"$resource".txt

            # collect logs for pods along the way
            if [[ "$KIND" == 'pod' ]]; then
                kubectl -n "$NAMESPACE" logs --all-containers "$resource" >"${NS_DIR}"/logs--"$resource".txt
            fi
        done
    done

    # secret need `-oyaml` to read the content instead of `describe` since secrets `describe` will be encrypted.
    # so keeping it in a different block.
    for secret in $(kubectl -n "$NAMESPACE" get secrets -o jsonpath='{.items[*].metadata.name}'); do
        kubectl -n "$NAMESPACE" get -o yaml secret "$secret" >"${NS_DIR}"/secret-describe--"$secret".txt
    done

    # describe every one of the custom resources in the namespace since all should be rook-related and
    # they aren't captured by 'kubectl get all'
    for CRD in $(kubectl get crds -o jsonpath='{.items[*].metadata.name}'); do
        for resource in $(kubectl -n "$NAMESPACE" get "$CRD" -o jsonpath='{.items[*].metadata.name}'); do
            crd_main_type="${CRD%%.*}" # e.g., for cephclusters.ceph.rook.io, only use 'cephclusters'
            kubectl -n "$NAMESPACE" get -o yaml "$CRD" "$resource" >"${NS_DIR}"/"$crd_main_type"-describe--"$resource".txt
        done
    done

    # do simple 'get all' calls for resources we don't often want to look at
    kubectl get all -n "$NAMESPACE" -o wide >"${NS_DIR}"/all-wide.txt
    kubectl get all -n "$NAMESPACE" -o yaml >"${NS_DIR}"/all-yaml.txt
done

sudo lsblk | sudo tee -a "${LOG_DIR}"/lsblk.txt
journalctl -o short-precise --dmesg >"${LOG_DIR}"/dmesg.txt
journalctl >"${LOG_DIR}"/journalctl.txt
07070100000055000081ED000000000000000000000001680F0E8800003D8B000000000000000000000000000000000000003600000000kubectl-rook-ceph-0.9.4/tests/github-action-helper.sh#!/usr/bin/env bash

set -xeEo pipefail

#############
# VARIABLES #
#############
: "${FUNCTION:=${1}}"

# source https://github.com/rook/rook
function find_extra_block_dev() {
  # shellcheck disable=SC2005 # redirect doesn't work with sudo, so use echo
  echo "$(sudo lsblk)" >/dev/stderr # print lsblk output to stderr for debugging in case of future errors
  # relevant lsblk --pairs example: (MOUNTPOINT identifies boot partition)(PKNAME is Parent dev ID)
  # NAME="sda15" SIZE="106M" TYPE="part" MOUNTPOINT="/boot/efi" PKNAME="sda"
  # NAME="sdb"   SIZE="75G"  TYPE="disk" MOUNTPOINT=""          PKNAME=""
  # NAME="sdb1"  SIZE="75G"  TYPE="part" MOUNTPOINT="/mnt"      PKNAME="sdb"
  boot_dev="$(sudo lsblk --noheading --list --output MOUNTPOINT,PKNAME | grep boot | awk '{print $2}')"
  echo "  == find_extra_block_dev(): boot_dev='$boot_dev'" >/dev/stderr # debug in case of future errors
  # --nodeps ignores partitions
  extra_dev="$(sudo lsblk --noheading --list --nodeps --output KNAME | grep -v loop | grep -v "$boot_dev" | head -1)"
  echo "  == find_extra_block_dev(): extra_dev='$extra_dev'" >/dev/stderr # debug in case of future errors
  echo "$extra_dev"                                                       # output of function
}

: "${BLOCK:=$(find_extra_block_dev)}"

# source https://github.com/rook/rook
use_local_disk() {
  BLOCK_DATA_PART="/dev/${BLOCK}1"
  sudo apt purge snapd -y
  sudo dmsetup version || true
  sudo swapoff --all --verbose
  sudo umount /mnt
  # search for the device since it keeps changing between sda and sdb
  sudo wipefs --all --force "$BLOCK_DATA_PART"
}

deploy_rook() {
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/common.yaml
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/crds.yaml
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/operator.yaml
  curl https://raw.githubusercontent.com/rook/rook/master/deploy/examples/cluster-test.yaml -o cluster-test.yaml
  sed -i "s|#deviceFilter:|deviceFilter: ${BLOCK/\/dev\//}|g" cluster-test.yaml
  sed -i '0,/count: 1/ s/count: 1/count: 3/' cluster-test.yaml
  kubectl create -f cluster-test.yaml
  wait_for_pod_to_be_ready_state rook-ceph
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/toolbox.yaml

  deploy_csi_driver_default_ns
}

deploy_rook_in_custom_namespace() {
  OPERATOR_NS=$1
  CLUSTER_NS=$2
  : "${OPERATOR_NS:=test-operator}"
  : "${CLUSTER_NS:=test-cluster}"

  kubectl create namespace test-operator # creating namespace manually because rook common.yaml create one namespace and here we need 2
  curl https://raw.githubusercontent.com/rook/rook/master/deploy/examples/common.yaml -o common.yaml
  deploy_with_custom_ns "$OPERATOR_NS" "$CLUSTER_NS" common.yaml
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/crds.yaml

  curl -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/operator.yaml -o operator.yaml
  deploy_with_custom_ns "$OPERATOR_NS" "$CLUSTER_NS" operator.yaml

  curl https://raw.githubusercontent.com/rook/rook/master/deploy/examples/cluster-test.yaml -o cluster-test.yaml
  sed -i "s|#deviceFilter:|deviceFilter: ${BLOCK/\/dev\//}|g" cluster-test.yaml
  sed -i '0,/count: 1/ s/count: 1/count: 3/' cluster-test.yaml
  deploy_with_custom_ns "$OPERATOR_NS" "$CLUSTER_NS" cluster-test.yaml
  wait_for_pod_to_be_ready_state $CLUSTER_NS

  curl -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/toolbox.yaml -o toolbox.yaml
  deploy_with_custom_ns "$OPERATOR_NS" "$CLUSTER_NS" toolbox.yaml

  deploy_csi_driver_custom_ns "$OPERATOR_NS" "$CLUSTER_NS"
}

create_sc_with_retain_policy() {
  export OPERATOR_NS=$1
  export CLUSTER_NS=$2

  curl https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/cephfs/storageclass.yaml -o storageclass.yaml
  sed -i "s|name: rook-cephfs|name: rook-cephfs-retain|g" storageclass.yaml
  sed -i "s|reclaimPolicy: Delete|reclaimPolicy: Retain|g" storageclass.yaml
  sed -i "s|provisioner: rook-ceph.cephfs.csi.ceph.com |provisioner: ${OPERATOR_NS}.cephfs.csi.ceph.com |g" storageclass.yaml
  deploy_with_custom_ns $OPERATOR_NS $CLUSTER_NS storageclass.yaml
}

create_stale_subvolume() {
  curl https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/cephfs/pvc.yaml -o pvc.yaml
  sed -i "s|name: cephfs-pvc|name: cephfs-pvc-retain|g" pvc.yaml
  sed -i "s|storageClassName: rook-cephfs|storageClassName: rook-cephfs-retain|g" pvc.yaml
  kubectl create -f pvc.yaml
  kubectl get pvc cephfs-pvc-retain
  wait_for_pvc_to_be_bound_state
  : "${PVNAME:=$(kubectl get pvc cephfs-pvc-retain -o=jsonpath='{.spec.volumeName}')}"
  kubectl get pvc cephfs-pvc-retain
  kubectl delete pvc cephfs-pvc-retain
  kubectl delete pv "$PVNAME"
}

deploy_with_custom_ns() {
  export OPERATOR_NS=$1
  export CLUSTER_NS=$2
  export MANIFEST=$3
  sed -i "s|rook-ceph # namespace:operator|${OPERATOR_NS} # namespace:operator|g" "${MANIFEST}"
  sed -i "s|rook-ceph # namespace:cluster|${CLUSTER_NS} # namespace:cluster|g" "${MANIFEST}"
  kubectl create -f "${MANIFEST}"
}

deploy_csi_driver_default_ns() {
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/filesystem-test.yaml
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/subvolumegroup.yaml
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/rbd/storageclass-test.yaml
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/rbd/pvc.yaml
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/cephfs/storageclass.yaml
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/cephfs/pvc.yaml
  deploy_csi_driver_rados_namespace
}

deploy_csi_driver_rados_namespace() {
  curl https://raw.githubusercontent.com/rook/rook/refs/heads/master/deploy/examples/pool-test.yaml -o pool_rados_ns.yaml
  sed -i "s|name: replicapool|name: blockpool-rados-ns |g" pool_rados_ns.yaml
  kubectl create -f pool_rados_ns.yaml
  wait_for_cephblockpool_ready_state "rook-ceph" "blockpool-rados-ns" 30

  curl https://raw.githubusercontent.com/rook/rook/refs/heads/master/deploy/examples/radosnamespace.yaml -o cephblockpoolradosnamespace_a.yaml
  sed -i "s|blockPoolName: replicapool|blockPoolName: blockpool-rados-ns |g" cephblockpoolradosnamespace_a.yaml
  kubectl create -f cephblockpoolradosnamespace_a.yaml
  wait_for_cephblockpoolradosnamespace_ready_state "rook-ceph" "namespace-a" 30

  curl https://raw.githubusercontent.com/rook/rook/refs/heads/master/deploy/examples/radosnamespace.yaml -o cephblockpoolradosnamespace_b.yaml
  sed -i "s|blockPoolName: replicapool|blockPoolName: blockpool-rados-ns |g" cephblockpoolradosnamespace_b.yaml
  sed -i "s|name: namespace-a|name: namespace-b |g" cephblockpoolradosnamespace_b.yaml
  kubectl create -f cephblockpoolradosnamespace_b.yaml
  wait_for_cephblockpoolradosnamespace_ready_state "rook-ceph" "namespace-b" 30

  cluster_id=$(kubectl -n rook-ceph get cephblockpoolradosnamespace/namespace-a -o jsonpath='{.status.info.clusterID}')
  echo "cluster_id=${cluster_id}"

  curl https://raw.githubusercontent.com/rook/rook/refs/heads/master/deploy/examples/csi/rbd/storageclass-test.yaml -o storageclass-rados-namespace.yaml
  sed -i "s|clusterID: rook-ceph # namespace:cluster|clusterID: ${cluster_id} |g" storageclass-rados-namespace.yaml
  sed -i "s|name: rook-ceph-block|name: rook-ceph-block-rados-namespace |g" storageclass-rados-namespace.yaml
  sed -i "s|pool: replicapool|pool: blockpool-rados-ns |g" storageclass-rados-namespace.yaml
  kubectl apply -f storageclass-rados-namespace.yaml

  curl https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/rbd/pvc.yaml -o pvc-rados-namespace.yaml
  sed -i "s|name: rbd-pvc|name: rbd-pvc-rados-namespace |g" pvc-rados-namespace.yaml
  sed -i "s|storageClassName: rook-ceph-block|storageClassName: rook-ceph-block-rados-namespace |g" pvc-rados-namespace.yaml
  kubectl create -f pvc-rados-namespace.yaml
}

deploy_csi_driver_custom_ns() {
  curl https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/rbd/storageclass-test.yaml -o storageclass-rbd-test.yaml
  sed -i "s|provisioner: rook-ceph.rbd.csi.ceph.com |provisioner: test-operator.rbd.csi.ceph.com |g" storageclass-rbd-test.yaml
  deploy_with_custom_ns "$1" "$2" storageclass-rbd-test.yaml

  curl https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/cephfs/storageclass.yaml -o storageclass-cephfs-test.yaml
  sed -i "s|provisioner: rook-ceph.cephfs.csi.ceph.com |provisioner: test-operator.cephfs.csi.ceph.com |g" storageclass-cephfs-test.yaml
  deploy_with_custom_ns "$1" "$2" storageclass-cephfs-test.yaml
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/rbd/pvc.yaml

  curl -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/filesystem-test.yaml -o filesystem.yaml
  deploy_with_custom_ns "$1" "$2" filesystem.yaml

  curl -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/subvolumegroup.yaml -o subvolumegroup.yaml
  deploy_with_custom_ns "$1" "$2" subvolumegroup.yaml
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/cephfs/pvc.yaml
}

wait_for_cephblockpoolradosnamespace_ready_state() {
  local cluster_ns=$1
  local namespace_name=$2
  local timeout_duration=${3:-10} # Default timeout to 10 seconds if not provided

  export cluster_ns namespace_name # Export variables for use in the subshell

  timeout "$timeout_duration" bash <<'EOF'
    set -x
    until [ "$(kubectl get CephBlockPoolRadosNamespace "$namespace_name" -n "$cluster_ns" -o jsonpath='{.status.phase}')" == "Ready" ]; do
      echo "Waiting for CephBlockPoolRadosNamespace '$namespace_name' to be in 'Ready' phase..."
      sleep 1
      kubectl get CephBlockPoolRadosNamespace -A
    done
    echo "CephBlockPoolRadosNamespace $namespace_name is in Ready phase!"
EOF

  timeout_command_exit_code
}

wait_for_cephblockpool_ready_state() {
  local cluster_ns=$1
  local blockpool_name=$2
  local timeout_duration=${3:-10} # Default timeout to 10 seconds if not provided

  export cluster_ns blockpool_name # Export variables for use in the subshell

  timeout "$timeout_duration" bash <<'EOF'
    set -x
    until [ "$(kubectl get CephBlockPool "$blockpool_name" -n "$cluster_ns" -o jsonpath='{.status.phase}')" == "Ready" ]; do
      echo "Waiting for CephBlockPool $blockpool_name to be in Ready phase"
      sleep 1
      kubectl get CephBlockPool -A
      kubectl describe CephBlockPool blockpool-rados-ns -n rook-ceph
      kubectl get CephBlockPool blockpool-rados-ns -n rook-ceph -o yaml
    done
    echo "CephBlockPool $blockpool_name is in Ready phase!"
EOF

  timeout_command_exit_code
}

wait_for_pvc_to_be_bound_state() {
  timeout 100 bash <<-'EOF'
    set -x
    until [ $(kubectl get pvc cephfs-pvc-retain -o jsonpath='{.status.phase}') == "Bound" ]; do
      echo "waiting for the pvc to be in bound state"
      sleep 1
    done
EOF
  timeout_command_exit_code
}

wait_for_pod_to_be_ready_state() {
  export cluster_ns=$1
  timeout 200 bash <<-'EOF'
    set -x
    until [ $(kubectl get pod -l app=rook-ceph-osd -n "${cluster_ns}" -o jsonpath='{.items[*].metadata.name}' -o custom-columns=READY:status.containerStatuses[*].ready | grep -c true) -eq 1 ]; do
      echo "waiting for the pods to be in ready state"
      sleep 1
    done
EOF
  timeout_command_exit_code
}

wait_for_operator_pod_to_be_ready_state() {
  export operator_ns=$1
  timeout 100 bash <<-'EOF'
    set -x
    until [ $(kubectl get pod -l app=rook-ceph-operator -n "${operator_ns}" -o jsonpath='{.items[*].metadata.name}' -o custom-columns=READY:status.containerStatuses[*].ready | grep -c true) -eq 1 ]; do
      echo "waiting for the operator to be in ready state"
      sleep 1
    done
EOF
  timeout_command_exit_code
}

wait_for_three_mons() {
  export namespace=$1
  timeout 150 bash <<-'EOF'
    set -x
    until [ $(kubectl -n $namespace get deploy -l app=rook-ceph-mon,mon_canary!=true | grep rook-ceph-mon | wc -l | awk '{print $1}' ) -eq 3 ]; do
      echo "$(date) waiting for three mon deployments to exist"
      sleep 2
    done
EOF
  timeout_command_exit_code
}

wait_for_deployment_to_be_running() {
  deployment=$1
  namespace=$2
  echo "Waiting for the pod from deployment \"$deployment\" to be running"
  kubectl -n "$namespace" wait deployment "$deployment" --for condition=Available=True --timeout=90s
}

wait_for_crd_to_be_ready() {
  export cluster_ns=$1
  timeout 150 bash <<-'EOF'
    until [ $(kubectl -n "${cluster_ns}" get cephcluster my-cluster -o=jsonpath='{.status.phase}') == "Ready" ]; do
      echo "Waiting for the CephCluster my-cluster to be in the Ready state..."
      sleep 2
    done
EOF
}

timeout_command_exit_code() {
  # timeout command return exit status 124 if command times out
  if [ $? -eq 124 ]; then
    echo "Timeout reached"
    exit 1
  fi
}

install_minikube_with_none_driver() {
  CRICTL_VERSION="v1.31.1"
  MINIKUBE_VERSION="v1.34.0"

  sudo apt update
  sudo apt install -y conntrack socat
  curl -LO https://storage.googleapis.com/minikube/releases/$MINIKUBE_VERSION/minikube_latest_amd64.deb
  sudo dpkg -i minikube_latest_amd64.deb
  rm -f minikube_latest_amd64.deb

  curl -LO https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.15/cri-dockerd_0.3.15.3-0.ubuntu-focal_amd64.deb
  sudo dpkg -i cri-dockerd_0.3.15.3-0.ubuntu-focal_amd64.deb
  rm -f cri-dockerd_0.3.15.3-0.ubuntu-focal_amd64.deb

  wget https://github.com/kubernetes-sigs/cri-tools/releases/download/$CRICTL_VERSION/crictl-$CRICTL_VERSION-linux-amd64.tar.gz
  sudo tar zxvf crictl-$CRICTL_VERSION-linux-amd64.tar.gz -C /usr/local/bin
  rm -f crictl-$CRICTL_VERSION-linux-amd64.tar.gz
  sudo sysctl fs.protected_regular=0

  CNI_PLUGIN_VERSION="v1.5.1"
  CNI_PLUGIN_TAR="cni-plugins-linux-amd64-$CNI_PLUGIN_VERSION.tgz" # change arch if not on amd64
  CNI_PLUGIN_INSTALL_DIR="/opt/cni/bin"

  curl -LO "https://github.com/containernetworking/plugins/releases/download/$CNI_PLUGIN_VERSION/$CNI_PLUGIN_TAR"
  sudo mkdir -p "$CNI_PLUGIN_INSTALL_DIR"
  sudo tar -xf "$CNI_PLUGIN_TAR" -C "$CNI_PLUGIN_INSTALL_DIR"
  rm "$CNI_PLUGIN_TAR"

  export MINIKUBE_HOME=$HOME CHANGE_MINIKUBE_NONE_USER=true KUBECONFIG=$HOME/.kube/config
  minikube start --kubernetes-version="$1" --driver=none --memory 6g --cpus=2 --addons ingress --cni=calico
}

install_external_snapshotter() {
  EXTERNAL_SNAPSHOTTER_VERSION=8.0.1
  curl -L "https://github.com/kubernetes-csi/external-snapshotter/archive/refs/tags/v${EXTERNAL_SNAPSHOTTER_VERSION}.zip" -o external-snapshotter.zip
  unzip -d /tmp external-snapshotter.zip
  cd "/tmp/external-snapshotter-${EXTERNAL_SNAPSHOTTER_VERSION}"

  kubectl kustomize client/config/crd | kubectl create -f -
  kubectl -n kube-system kustomize deploy/kubernetes/snapshot-controller | kubectl create -f -
}

wait_for_rbd_pvc_clone_to_be_bound() {
  kubectl create -f https://raw.githubusercontent.com/rook/rook/master/deploy/examples/csi/rbd/pvc-clone.yaml

  timeout 100 bash <<-'EOF'
    until [ $(kubectl get pvc rbd-pvc-clone -o jsonpath='{.status.phase}') == "Bound" ]; do
      echo "waiting for the pvc clone to be in bound state"
      sleep 1
    done
EOF
  timeout_command_exit_code
}

########
# MAIN #
########

FUNCTION="$1"
shift # remove function arg now that we've recorded it
# call the function with the remainder of the user-provided args
if ! $FUNCTION "$@"; then
  echo "Call to $FUNCTION was not successful" >&2
  exit 1
fi
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!794 blocks
openSUSE Build Service is sponsored by