rgw: controller for account management
PR only focuses on account creation, deletion and update. Signed-off-by: Santosh <sapillai@redhat.com>
This commit is contained in:
1 parent
b0ae620426
commit
c4ec7faee5
37 files changed
+2876
-75
No files matched your search
@@ -47,6 +47,11 @@ jobs:
|
||||
check-latest: true
|
||||
- name: govulncheck
|
||||
uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1.0.4
|
||||
env:
|
||||
# Required for go-ceph rgw/admin account APIs which are gated behind
|
||||
# the ceph_preview build tag. Can be removed when go-ceph promotes
|
||||
# the account API out of preview.
|
||||
GOFLAGS: "-tags=ceph_preview"
|
||||
|
||||
kube-api-lint:
|
||||
name: kube-api-lint
|
||||
|
||||
@@ -21,6 +21,12 @@ concurrency:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# Required for go-ceph rgw/admin account APIs which are gated behind
|
||||
# the ceph_preview build tag. Can be removed when go-ceph promotes
|
||||
# the account API out of preview.
|
||||
GOFLAGS: "-tags=ceph_preview"
|
||||
|
||||
jobs:
|
||||
TestCephHelmSuite:
|
||||
if: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && !contains(github.event.pull_request.labels.*.name, 'skip-ci') }}
|
||||
|
||||
@@ -16,6 +16,12 @@ defaults:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# Required for go-ceph rgw/admin account APIs which are gated behind
|
||||
# the ceph_preview build tag. Can be removed when go-ceph promotes
|
||||
# the account API out of preview.
|
||||
GOFLAGS: "-tags=ceph_preview"
|
||||
|
||||
# cancel the in-progress workflow when PR is refreshed.
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
|
||||
|
||||
@@ -21,6 +21,12 @@ concurrency:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# Required for go-ceph rgw/admin account APIs which are gated behind
|
||||
# the ceph_preview build tag. Can be removed when go-ceph promotes
|
||||
# the account API out of preview.
|
||||
GOFLAGS: "-tags=ceph_preview"
|
||||
|
||||
jobs:
|
||||
TestCephMultiClusterDeploySuite:
|
||||
if: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && !contains(github.event.pull_request.labels.*.name, 'skip-ci') }}
|
||||
|
||||
@@ -21,6 +21,12 @@ concurrency:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# Required for go-ceph rgw/admin account APIs which are gated behind
|
||||
# the ceph_preview build tag. Can be removed when go-ceph promotes
|
||||
# the account API out of preview.
|
||||
GOFLAGS: "-tags=ceph_preview"
|
||||
|
||||
jobs:
|
||||
TestCephObjectSuite:
|
||||
if: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && !contains(github.event.pull_request.labels.*.name, 'skip-ci') }}
|
||||
|
||||
@@ -21,6 +21,12 @@ concurrency:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# Required for go-ceph rgw/admin account APIs which are gated behind
|
||||
# the ceph_preview build tag. Can be removed when go-ceph promotes
|
||||
# the account API out of preview.
|
||||
GOFLAGS: "-tags=ceph_preview"
|
||||
|
||||
jobs:
|
||||
TestCephSmokeSuite:
|
||||
if: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && !contains(github.event.pull_request.labels.*.name, 'skip-ci') }}
|
||||
|
||||
@@ -21,6 +21,12 @@ concurrency:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# Required for go-ceph rgw/admin account APIs which are gated behind
|
||||
# the ceph_preview build tag. Can be removed when go-ceph promotes
|
||||
# the account API out of preview.
|
||||
GOFLAGS: "-tags=ceph_preview"
|
||||
|
||||
jobs:
|
||||
TestCephUpgradeSuite:
|
||||
if: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && !contains(github.event.pull_request.labels.*.name, 'skip-ci') }}
|
||||
|
||||
@@ -213,6 +213,11 @@ jobs:
|
||||
|
||||
TestCephObjectSuite:
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
# Required for go-ceph rgw/admin account APIs which are gated behind
|
||||
# the ceph_preview build tag. Can be removed when go-ceph promotes
|
||||
# the account API out of preview.
|
||||
GOFLAGS: "-tags=ceph_preview"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
---
|
||||
version: "2"
|
||||
run:
|
||||
build-tags:
|
||||
# Required for go-ceph rgw/admin account APIs which are gated behind
|
||||
# the ceph_preview build tag. Can be removed when go-ceph promotes
|
||||
# the account API out of preview.
|
||||
- ceph_preview
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
|
||||
Vendored
+4
-1
@@ -26,6 +26,9 @@
|
||||
"!Documentation/Helm-Charts",
|
||||
],
|
||||
"gopls": {
|
||||
"formatting.gofumpt": true
|
||||
"formatting.gofumpt": true,
|
||||
"buildFlags": [
|
||||
"-tags=ceph_preview"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -4648,6 +4648,60 @@ Allow any string so that over-specified legacy clusters do not break on CRD upda
|
||||
<td></td>
|
||||
</tr></tbody>
|
||||
</table>
|
||||
<h3 id="ceph.rook.io/v1.CephObjectStoreAccount">CephObjectStoreAccount
|
||||
</h3>
|
||||
<div>
|
||||
<p>CephObjectStoreAccount represent the RGW user account</p>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>metadata</code><br/>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#objectmeta-v1-meta">
|
||||
Kubernetes meta/v1.ObjectMeta
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
Refer to the Kubernetes API documentation for the fields of the
|
||||
<code>metadata</code> field.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>spec,omitzero</code><br/>
|
||||
<em>
|
||||
<a href="#ceph.rook.io/v1.ObjectStoreAccountSpec">
|
||||
ObjectStoreAccountSpec
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>status,omitzero</code><br/>
|
||||
<em>
|
||||
<a href="#ceph.rook.io/v1.ObjectStoreAccountStatus">
|
||||
ObjectStoreAccountStatus
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="ceph.rook.io/v1.CephStatus">CephStatus
|
||||
</h3>
|
||||
<p>
|
||||
@@ -11623,6 +11677,113 @@ If spec.sharedPools are also empty, then RGW pools (spec.dataPool and spec.metad
|
||||
</p>
|
||||
<div>
|
||||
</div>
|
||||
<h3 id="ceph.rook.io/v1.ObjectStoreAccountSpec">ObjectStoreAccountSpec
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em><a href="#ceph.rook.io/v1.CephObjectStoreAccount">CephObjectStoreAccount</a>)
|
||||
</p>
|
||||
<div>
|
||||
<p>ObjectStoreAccountSpec represent the spec of a RGW Account</p>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>store</code><br/>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Store is the CephObjectStore the account will be associated with</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>name</code><br/>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Name is the desired display name of the RGW account if different from the CephObjectStoreAccount CR name.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>accountID</code><br/>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>AccountID uniquely identifies an account and resource ownership. Format should be RGW followed by 17 digits
|
||||
(e.g., RGW00889737169837717). If not specified, the ID will be automatically generated.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="ceph.rook.io/v1.ObjectStoreAccountStatus">ObjectStoreAccountStatus
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em><a href="#ceph.rook.io/v1.CephObjectStoreAccount">CephObjectStoreAccount</a>)
|
||||
</p>
|
||||
<div>
|
||||
<p>ObjectStoreAccountStatus represents the status of a CephObjectStoreAccount resource</p>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>phase</code><br/>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>accountID</code><br/>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>AccountID associated with the RGW user account</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>observedGeneration</code><br/>
|
||||
<em>
|
||||
int64
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>ObservedGeneration is the latest generation observed by the controller.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="ceph.rook.io/v1.ObjectStoreHostingSpec">ObjectStoreHostingSpec
|
||||
</h3>
|
||||
<p>
|
||||
|
||||
@@ -47,7 +47,10 @@ SHELL := /usr/bin/env bash
|
||||
# Can be used or additional go build flags
|
||||
BUILDFLAGS ?=
|
||||
LDFLAGS ?=
|
||||
TAGS ?=
|
||||
# Required for go-ceph rgw/admin account APIs which are gated behind
|
||||
# the ceph_preview build tag. Can be removed when go-ceph promotes
|
||||
# the account API out of preview.
|
||||
TAGS ?= ceph_preview
|
||||
|
||||
# turn on more verbose build
|
||||
V ?= 0
|
||||
|
||||
@@ -149,6 +149,7 @@ rules:
|
||||
- cephnvmeofgateways
|
||||
- cephobjectstores
|
||||
- cephobjectstoreusers
|
||||
- cephobjectstoreaccounts
|
||||
- cephobjectrealms
|
||||
- cephobjectzonegroups
|
||||
- cephobjectzones
|
||||
@@ -176,6 +177,7 @@ rules:
|
||||
- cephnvmeofgateways/status
|
||||
- cephobjectstores/status
|
||||
- cephobjectstoreusers/status
|
||||
- cephobjectstoreaccounts/status
|
||||
- cephobjectrealms/status
|
||||
- cephobjectzonegroups/status
|
||||
- cephobjectzones/status
|
||||
@@ -200,6 +202,7 @@ rules:
|
||||
- cephnvmeofgateways/finalizers
|
||||
- cephobjectstores/finalizers
|
||||
- cephobjectstoreusers/finalizers
|
||||
- cephobjectstoreaccounts/finalizers
|
||||
- cephobjectrealms/finalizers
|
||||
- cephobjectzonegroups/finalizers
|
||||
- cephobjectzones/finalizers
|
||||
|
||||
@@ -12565,6 +12565,106 @@ spec:
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.19.0
|
||||
helm.sh/resource-policy: keep
|
||||
name: cephobjectstoreaccounts.ceph.rook.io
|
||||
spec:
|
||||
group: ceph.rook.io
|
||||
names:
|
||||
kind: CephObjectStoreAccount
|
||||
listKind: CephObjectStoreAccountList
|
||||
plural: cephobjectstoreaccounts
|
||||
singular: cephobjectstoreaccount
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .status.phase
|
||||
name: Phase
|
||||
type: string
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: CephObjectStoreAccount represent the RGW user account
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ObjectStoreAccountSpec represent the spec of a RGW Account
|
||||
properties:
|
||||
accountID:
|
||||
description: |-
|
||||
AccountID uniquely identifies an account and resource ownership. Format should be RGW followed by 17 digits
|
||||
(e.g., RGW00889737169837717). If not specified, the ID will be automatically generated.
|
||||
maxLength: 20
|
||||
minLength: 20
|
||||
pattern: ^RGW\d{17}$
|
||||
type: string
|
||||
x-kubernetes-validations:
|
||||
- message: accountID is immutable
|
||||
rule: self == oldSelf
|
||||
name:
|
||||
description: Name is the desired display name of the RGW account if different from the CephObjectStoreAccount CR name.
|
||||
maxLength: 2048
|
||||
minLength: 1
|
||||
pattern: ^[a-zA-Z0-9 ._-]+$
|
||||
type: string
|
||||
store:
|
||||
description: Store is the CephObjectStore the account will be associated with
|
||||
maxLength: 253
|
||||
minLength: 1
|
||||
type: string
|
||||
x-kubernetes-validations:
|
||||
- message: store is immutable
|
||||
rule: self == oldSelf
|
||||
required:
|
||||
- store
|
||||
type: object
|
||||
status:
|
||||
description: ObjectStoreAccountStatus represents the status of a CephObjectStoreAccount resource
|
||||
properties:
|
||||
accountID:
|
||||
description: AccountID associated with the RGW user account
|
||||
maxLength: 20
|
||||
minLength: 20
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: ObservedGeneration is the latest generation observed by the controller.
|
||||
format: int64
|
||||
type: integer
|
||||
phase:
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- metadata
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.19.0
|
||||
|
||||
@@ -379,6 +379,7 @@ rules:
|
||||
- cephnvmeofgateways
|
||||
- cephobjectstores
|
||||
- cephobjectstoreusers
|
||||
- cephobjectstoreaccounts
|
||||
- cephobjectrealms
|
||||
- cephobjectzonegroups
|
||||
- cephobjectzones
|
||||
@@ -406,6 +407,7 @@ rules:
|
||||
- cephnvmeofgateways/status
|
||||
- cephobjectstores/status
|
||||
- cephobjectstoreusers/status
|
||||
- cephobjectstoreaccounts/status
|
||||
- cephobjectrealms/status
|
||||
- cephobjectzonegroups/status
|
||||
- cephobjectzones/status
|
||||
@@ -430,6 +432,7 @@ rules:
|
||||
- cephnvmeofgateways/finalizers
|
||||
- cephobjectstores/finalizers
|
||||
- cephobjectstoreusers/finalizers
|
||||
- cephobjectstoreaccounts/finalizers
|
||||
- cephobjectrealms/finalizers
|
||||
- cephobjectzonegroups/finalizers
|
||||
- cephobjectzones/finalizers
|
||||
|
||||
@@ -12556,6 +12556,105 @@ spec:
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.19.0
|
||||
name: cephobjectstoreaccounts.ceph.rook.io
|
||||
spec:
|
||||
group: ceph.rook.io
|
||||
names:
|
||||
kind: CephObjectStoreAccount
|
||||
listKind: CephObjectStoreAccountList
|
||||
plural: cephobjectstoreaccounts
|
||||
singular: cephobjectstoreaccount
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .status.phase
|
||||
name: Phase
|
||||
type: string
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: CephObjectStoreAccount represent the RGW user account
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ObjectStoreAccountSpec represent the spec of a RGW Account
|
||||
properties:
|
||||
accountID:
|
||||
description: |-
|
||||
AccountID uniquely identifies an account and resource ownership. Format should be RGW followed by 17 digits
|
||||
(e.g., RGW00889737169837717). If not specified, the ID will be automatically generated.
|
||||
maxLength: 20
|
||||
minLength: 20
|
||||
pattern: ^RGW\d{17}$
|
||||
type: string
|
||||
x-kubernetes-validations:
|
||||
- message: accountID is immutable
|
||||
rule: self == oldSelf
|
||||
name:
|
||||
description: Name is the desired display name of the RGW account if different from the CephObjectStoreAccount CR name.
|
||||
maxLength: 2048
|
||||
minLength: 1
|
||||
pattern: ^[a-zA-Z0-9 ._-]+$
|
||||
type: string
|
||||
store:
|
||||
description: Store is the CephObjectStore the account will be associated with
|
||||
maxLength: 253
|
||||
minLength: 1
|
||||
type: string
|
||||
x-kubernetes-validations:
|
||||
- message: store is immutable
|
||||
rule: self == oldSelf
|
||||
required:
|
||||
- store
|
||||
type: object
|
||||
status:
|
||||
description: ObjectStoreAccountStatus represents the status of a CephObjectStoreAccount resource
|
||||
properties:
|
||||
accountID:
|
||||
description: AccountID associated with the RGW user account
|
||||
maxLength: 20
|
||||
minLength: 20
|
||||
type: string
|
||||
observedGeneration:
|
||||
description: ObservedGeneration is the latest generation observed by the controller.
|
||||
format: int64
|
||||
type: integer
|
||||
phase:
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- metadata
|
||||
- spec
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.19.0
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#################################################################################################################
|
||||
# Create an object store account to manage RGW resources.
|
||||
# kubectl create -f object-account.yaml
|
||||
#################################################################################################################
|
||||
|
||||
apiVersion: ceph.rook.io/v1
|
||||
kind: CephObjectStoreAccount
|
||||
metadata:
|
||||
name: my-account
|
||||
namespace: rook-ceph # namespace:cluster
|
||||
spec:
|
||||
# The object store in which the account will be created
|
||||
store: my-store
|
||||
# An optional name for the RGW account if different from the CephObjectStoreAccount CR name
|
||||
# name: "my-rgw-account"
|
||||
# An optional unique account ID. Format: RGW followed by 17 digits (e.g., RGW00889737169837717).
|
||||
# If not specified, Ceph will auto-generate the account ID.
|
||||
# accountID: "RGW00889737169837717"
|
||||
@@ -71,6 +71,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
&CephObjectStoreList{},
|
||||
&CephObjectStoreUser{},
|
||||
&CephObjectStoreUserList{},
|
||||
&CephObjectStoreAccount{},
|
||||
&CephObjectStoreAccountList{},
|
||||
&CephObjectRealm{},
|
||||
&CephObjectRealmList{},
|
||||
&CephObjectZoneGroup{},
|
||||
|
||||
@@ -2731,6 +2731,69 @@ type RGWServiceSpec struct {
|
||||
Annotations Annotations `json:"annotations,omitempty"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:noStatus
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
|
||||
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
|
||||
// +kubebuilder:subresource:status
|
||||
// CephObjectStoreAccount represent the RGW user account
|
||||
type CephObjectStoreAccount struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
// +required
|
||||
metav1.ObjectMeta `json:"metadata"`
|
||||
// +required
|
||||
Spec ObjectStoreAccountSpec `json:"spec,omitzero"`
|
||||
// +optional
|
||||
Status *ObjectStoreAccountStatus `json:"status,omitzero"` //nolint:kubeapilinter // MinProperties cannot be applied to a struct pointer field
|
||||
}
|
||||
|
||||
// ObjectStoreAccountSpec represent the spec of a RGW Account
|
||||
type ObjectStoreAccountSpec struct {
|
||||
// Store is the CephObjectStore the account will be associated with
|
||||
// +required
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=253
|
||||
// +kubebuilder:validation:XValidation:message="store is immutable",rule="self == oldSelf"
|
||||
Store string `json:"store,omitempty"`
|
||||
// Name is the desired display name of the RGW account if different from the CephObjectStoreAccount CR name.
|
||||
// +optional
|
||||
// +kubebuilder:validation:MinLength=1
|
||||
// +kubebuilder:validation:MaxLength=2048
|
||||
// +kubebuilder:validation:Pattern=`^[a-zA-Z0-9 ._-]+$`
|
||||
Name string `json:"name,omitempty"`
|
||||
// AccountID uniquely identifies an account and resource ownership. Format should be RGW followed by 17 digits
|
||||
// (e.g., RGW00889737169837717). If not specified, the ID will be automatically generated.
|
||||
// +optional
|
||||
// +kubebuilder:validation:MinLength=20
|
||||
// +kubebuilder:validation:MaxLength=20
|
||||
// +kubebuilder:validation:Pattern=`^RGW\d{17}$`
|
||||
// +kubebuilder:validation:XValidation:message="accountID is immutable",rule="self == oldSelf"
|
||||
AccountID string `json:"accountID,omitempty"`
|
||||
}
|
||||
|
||||
// ObjectStoreAccountStatus represents the status of a CephObjectStoreAccount resource
|
||||
type ObjectStoreAccountStatus struct {
|
||||
// +optional
|
||||
Phase string `json:"phase,omitempty"` //nolint:kubeapilinter // Conditions are preferred over Phase
|
||||
// +optional
|
||||
// AccountID associated with the RGW user account
|
||||
// +kubebuilder:validation:MinLength=20
|
||||
// +kubebuilder:validation:MaxLength=20
|
||||
AccountID string `json:"accountID,omitempty"`
|
||||
// ObservedGeneration is the latest generation observed by the controller.
|
||||
// +optional
|
||||
ObservedGeneration *int64 `json:"observedGeneration,omitempty"`
|
||||
}
|
||||
|
||||
// CephObjectStoreAccountList represents the Ceph object store accounts
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
type CephObjectStoreAccountList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata"`
|
||||
Items []CephObjectStoreAccount `json:"items"`
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +genclient:noStatus
|
||||
// +kubebuilder:resource:shortName=nfs,path=cephnfses
|
||||
|
||||
@@ -1621,6 +1621,71 @@ func (in *CephObjectStore) DeepCopyObject() runtime.Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CephObjectStoreAccount) DeepCopyInto(out *CephObjectStoreAccount) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
out.Spec = in.Spec
|
||||
if in.Status != nil {
|
||||
in, out := &in.Status, &out.Status
|
||||
*out = new(ObjectStoreAccountStatus)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CephObjectStoreAccount.
|
||||
func (in *CephObjectStoreAccount) DeepCopy() *CephObjectStoreAccount {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CephObjectStoreAccount)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CephObjectStoreAccount) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CephObjectStoreAccountList) DeepCopyInto(out *CephObjectStoreAccountList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CephObjectStoreAccount, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CephObjectStoreAccountList.
|
||||
func (in *CephObjectStoreAccountList) DeepCopy() *CephObjectStoreAccountList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CephObjectStoreAccountList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *CephObjectStoreAccountList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CephObjectStoreList) DeepCopyInto(out *CephObjectStoreList) {
|
||||
*out = *in
|
||||
@@ -4252,6 +4317,43 @@ func (in *ObjectSharedPoolsSpec) DeepCopy() *ObjectSharedPoolsSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ObjectStoreAccountSpec) DeepCopyInto(out *ObjectStoreAccountSpec) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectStoreAccountSpec.
|
||||
func (in *ObjectStoreAccountSpec) DeepCopy() *ObjectStoreAccountSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ObjectStoreAccountSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ObjectStoreAccountStatus) DeepCopyInto(out *ObjectStoreAccountStatus) {
|
||||
*out = *in
|
||||
if in.ObservedGeneration != nil {
|
||||
in, out := &in.ObservedGeneration, &out.ObservedGeneration
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectStoreAccountStatus.
|
||||
func (in *ObjectStoreAccountStatus) DeepCopy() *ObjectStoreAccountStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ObjectStoreAccountStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ObjectStoreHostingSpec) DeepCopyInto(out *ObjectStoreHostingSpec) {
|
||||
*out = *in
|
||||
|
||||
@@ -42,6 +42,7 @@ type CephV1Interface interface {
|
||||
CephNVMeOFGatewaysGetter
|
||||
CephObjectRealmsGetter
|
||||
CephObjectStoresGetter
|
||||
CephObjectStoreAccountsGetter
|
||||
CephObjectStoreUsersGetter
|
||||
CephObjectZonesGetter
|
||||
CephObjectZoneGroupsGetter
|
||||
@@ -109,6 +110,10 @@ func (c *CephV1Client) CephObjectStores(namespace string) CephObjectStoreInterfa
|
||||
return newCephObjectStores(c, namespace)
|
||||
}
|
||||
|
||||
func (c *CephV1Client) CephObjectStoreAccounts(namespace string) CephObjectStoreAccountInterface {
|
||||
return newCephObjectStoreAccounts(c, namespace)
|
||||
}
|
||||
|
||||
func (c *CephV1Client) CephObjectStoreUsers(namespace string) CephObjectStoreUserInterface {
|
||||
return newCephObjectStoreUsers(c, namespace)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
Copyright 2018 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
cephrookiov1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
|
||||
scheme "github.com/rook/rook/pkg/client/clientset/versioned/scheme"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
gentype "k8s.io/client-go/gentype"
|
||||
)
|
||||
|
||||
// CephObjectStoreAccountsGetter has a method to return a CephObjectStoreAccountInterface.
|
||||
// A group's client should implement this interface.
|
||||
type CephObjectStoreAccountsGetter interface {
|
||||
CephObjectStoreAccounts(namespace string) CephObjectStoreAccountInterface
|
||||
}
|
||||
|
||||
// CephObjectStoreAccountInterface has methods to work with CephObjectStoreAccount resources.
|
||||
type CephObjectStoreAccountInterface interface {
|
||||
Create(ctx context.Context, cephObjectStoreAccount *cephrookiov1.CephObjectStoreAccount, opts metav1.CreateOptions) (*cephrookiov1.CephObjectStoreAccount, error)
|
||||
Update(ctx context.Context, cephObjectStoreAccount *cephrookiov1.CephObjectStoreAccount, opts metav1.UpdateOptions) (*cephrookiov1.CephObjectStoreAccount, error)
|
||||
Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
|
||||
DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
|
||||
Get(ctx context.Context, name string, opts metav1.GetOptions) (*cephrookiov1.CephObjectStoreAccount, error)
|
||||
List(ctx context.Context, opts metav1.ListOptions) (*cephrookiov1.CephObjectStoreAccountList, error)
|
||||
Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
|
||||
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *cephrookiov1.CephObjectStoreAccount, err error)
|
||||
CephObjectStoreAccountExpansion
|
||||
}
|
||||
|
||||
// cephObjectStoreAccounts implements CephObjectStoreAccountInterface
|
||||
type cephObjectStoreAccounts struct {
|
||||
*gentype.ClientWithList[*cephrookiov1.CephObjectStoreAccount, *cephrookiov1.CephObjectStoreAccountList]
|
||||
}
|
||||
|
||||
// newCephObjectStoreAccounts returns a CephObjectStoreAccounts
|
||||
func newCephObjectStoreAccounts(c *CephV1Client, namespace string) *cephObjectStoreAccounts {
|
||||
return &cephObjectStoreAccounts{
|
||||
gentype.NewClientWithList[*cephrookiov1.CephObjectStoreAccount, *cephrookiov1.CephObjectStoreAccountList](
|
||||
"cephobjectstoreaccounts",
|
||||
c.RESTClient(),
|
||||
scheme.ParameterCodec,
|
||||
namespace,
|
||||
func() *cephrookiov1.CephObjectStoreAccount { return &cephrookiov1.CephObjectStoreAccount{} },
|
||||
func() *cephrookiov1.CephObjectStoreAccountList { return &cephrookiov1.CephObjectStoreAccountList{} },
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,10 @@ func (c *FakeCephV1) CephObjectStores(namespace string) v1.CephObjectStoreInterf
|
||||
return newFakeCephObjectStores(c, namespace)
|
||||
}
|
||||
|
||||
func (c *FakeCephV1) CephObjectStoreAccounts(namespace string) v1.CephObjectStoreAccountInterface {
|
||||
return newFakeCephObjectStoreAccounts(c, namespace)
|
||||
}
|
||||
|
||||
func (c *FakeCephV1) CephObjectStoreUsers(namespace string) v1.CephObjectStoreUserInterface {
|
||||
return newFakeCephObjectStoreUsers(c, namespace)
|
||||
}
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2018 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.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
|
||||
cephrookiov1 "github.com/rook/rook/pkg/client/clientset/versioned/typed/ceph.rook.io/v1"
|
||||
gentype "k8s.io/client-go/gentype"
|
||||
)
|
||||
|
||||
// fakeCephObjectStoreAccounts implements CephObjectStoreAccountInterface
|
||||
type fakeCephObjectStoreAccounts struct {
|
||||
*gentype.FakeClientWithList[*v1.CephObjectStoreAccount, *v1.CephObjectStoreAccountList]
|
||||
Fake *FakeCephV1
|
||||
}
|
||||
|
||||
func newFakeCephObjectStoreAccounts(fake *FakeCephV1, namespace string) cephrookiov1.CephObjectStoreAccountInterface {
|
||||
return &fakeCephObjectStoreAccounts{
|
||||
gentype.NewFakeClientWithList[*v1.CephObjectStoreAccount, *v1.CephObjectStoreAccountList](
|
||||
fake.Fake,
|
||||
namespace,
|
||||
v1.SchemeGroupVersion.WithResource("cephobjectstoreaccounts"),
|
||||
v1.SchemeGroupVersion.WithKind("CephObjectStoreAccount"),
|
||||
func() *v1.CephObjectStoreAccount { return &v1.CephObjectStoreAccount{} },
|
||||
func() *v1.CephObjectStoreAccountList { return &v1.CephObjectStoreAccountList{} },
|
||||
func(dst, src *v1.CephObjectStoreAccountList) { dst.ListMeta = src.ListMeta },
|
||||
func(list *v1.CephObjectStoreAccountList) []*v1.CephObjectStoreAccount {
|
||||
return gentype.ToPointerSlice(list.Items)
|
||||
},
|
||||
func(list *v1.CephObjectStoreAccountList, items []*v1.CephObjectStoreAccount) {
|
||||
list.Items = gentype.FromPointerSlice(items)
|
||||
},
|
||||
),
|
||||
fake,
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,8 @@ type CephObjectRealmExpansion interface{}
|
||||
|
||||
type CephObjectStoreExpansion interface{}
|
||||
|
||||
type CephObjectStoreAccountExpansion interface{}
|
||||
|
||||
type CephObjectStoreUserExpansion interface{}
|
||||
|
||||
type CephObjectZoneExpansion interface{}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright 2018 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.
|
||||
*/
|
||||
|
||||
// Code generated by informer-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
time "time"
|
||||
|
||||
apiscephrookiov1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
|
||||
versioned "github.com/rook/rook/pkg/client/clientset/versioned"
|
||||
internalinterfaces "github.com/rook/rook/pkg/client/informers/externalversions/internalinterfaces"
|
||||
cephrookiov1 "github.com/rook/rook/pkg/client/listers/ceph.rook.io/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// CephObjectStoreAccountInformer provides access to a shared informer and lister for
|
||||
// CephObjectStoreAccounts.
|
||||
type CephObjectStoreAccountInformer interface {
|
||||
Informer() cache.SharedIndexInformer
|
||||
Lister() cephrookiov1.CephObjectStoreAccountLister
|
||||
}
|
||||
|
||||
type cephObjectStoreAccountInformer struct {
|
||||
factory internalinterfaces.SharedInformerFactory
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewCephObjectStoreAccountInformer constructs a new informer for CephObjectStoreAccount type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewCephObjectStoreAccountInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
|
||||
return NewFilteredCephObjectStoreAccountInformer(client, namespace, resyncPeriod, indexers, nil)
|
||||
}
|
||||
|
||||
// NewFilteredCephObjectStoreAccountInformer constructs a new informer for CephObjectStoreAccount type.
|
||||
// Always prefer using an informer factory to get a shared informer instead of getting an independent
|
||||
// one. This reduces memory footprint and number of connections to the server.
|
||||
func NewFilteredCephObjectStoreAccountInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
|
||||
return cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.CephV1().CephObjectStoreAccounts(namespace).List(context.Background(), options)
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.CephV1().CephObjectStoreAccounts(namespace).Watch(context.Background(), options)
|
||||
},
|
||||
ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.CephV1().CephObjectStoreAccounts(namespace).List(ctx, options)
|
||||
},
|
||||
WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) {
|
||||
if tweakListOptions != nil {
|
||||
tweakListOptions(&options)
|
||||
}
|
||||
return client.CephV1().CephObjectStoreAccounts(namespace).Watch(ctx, options)
|
||||
},
|
||||
},
|
||||
&apiscephrookiov1.CephObjectStoreAccount{},
|
||||
resyncPeriod,
|
||||
indexers,
|
||||
)
|
||||
}
|
||||
|
||||
func (f *cephObjectStoreAccountInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
|
||||
return NewFilteredCephObjectStoreAccountInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
|
||||
}
|
||||
|
||||
func (f *cephObjectStoreAccountInformer) Informer() cache.SharedIndexInformer {
|
||||
return f.factory.InformerFor(&apiscephrookiov1.CephObjectStoreAccount{}, f.defaultInformer)
|
||||
}
|
||||
|
||||
func (f *cephObjectStoreAccountInformer) Lister() cephrookiov1.CephObjectStoreAccountLister {
|
||||
return cephrookiov1.NewCephObjectStoreAccountLister(f.Informer().GetIndexer())
|
||||
}
|
||||
@@ -52,6 +52,8 @@ type Interface interface {
|
||||
CephObjectRealms() CephObjectRealmInformer
|
||||
// CephObjectStores returns a CephObjectStoreInformer.
|
||||
CephObjectStores() CephObjectStoreInformer
|
||||
// CephObjectStoreAccounts returns a CephObjectStoreAccountInformer.
|
||||
CephObjectStoreAccounts() CephObjectStoreAccountInformer
|
||||
// CephObjectStoreUsers returns a CephObjectStoreUserInformer.
|
||||
CephObjectStoreUsers() CephObjectStoreUserInformer
|
||||
// CephObjectZones returns a CephObjectZoneInformer.
|
||||
@@ -143,6 +145,11 @@ func (v *version) CephObjectStores() CephObjectStoreInformer {
|
||||
return &cephObjectStoreInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// CephObjectStoreAccounts returns a CephObjectStoreAccountInformer.
|
||||
func (v *version) CephObjectStoreAccounts() CephObjectStoreAccountInformer {
|
||||
return &cephObjectStoreAccountInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
}
|
||||
|
||||
// CephObjectStoreUsers returns a CephObjectStoreUserInformer.
|
||||
func (v *version) CephObjectStoreUsers() CephObjectStoreUserInformer {
|
||||
return &cephObjectStoreUserInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
|
||||
|
||||
@@ -81,6 +81,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Ceph().V1().CephObjectRealms().Informer()}, nil
|
||||
case v1.SchemeGroupVersion.WithResource("cephobjectstores"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Ceph().V1().CephObjectStores().Informer()}, nil
|
||||
case v1.SchemeGroupVersion.WithResource("cephobjectstoreaccounts"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Ceph().V1().CephObjectStoreAccounts().Informer()}, nil
|
||||
case v1.SchemeGroupVersion.WithResource("cephobjectstoreusers"):
|
||||
return &genericInformer{resource: resource.GroupResource(), informer: f.Ceph().V1().CephObjectStoreUsers().Informer()}, nil
|
||||
case v1.SchemeGroupVersion.WithResource("cephobjectzones"):
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright 2018 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.
|
||||
*/
|
||||
|
||||
// Code generated by lister-gen. DO NOT EDIT.
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
cephrookiov1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
listers "k8s.io/client-go/listers"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// CephObjectStoreAccountLister helps list CephObjectStoreAccounts.
|
||||
// All objects returned here must be treated as read-only.
|
||||
type CephObjectStoreAccountLister interface {
|
||||
// List lists all CephObjectStoreAccounts in the indexer.
|
||||
// Objects returned here must be treated as read-only.
|
||||
List(selector labels.Selector) (ret []*cephrookiov1.CephObjectStoreAccount, err error)
|
||||
// CephObjectStoreAccounts returns an object that can list and get CephObjectStoreAccounts.
|
||||
CephObjectStoreAccounts(namespace string) CephObjectStoreAccountNamespaceLister
|
||||
CephObjectStoreAccountListerExpansion
|
||||
}
|
||||
|
||||
// cephObjectStoreAccountLister implements the CephObjectStoreAccountLister interface.
|
||||
type cephObjectStoreAccountLister struct {
|
||||
listers.ResourceIndexer[*cephrookiov1.CephObjectStoreAccount]
|
||||
}
|
||||
|
||||
// NewCephObjectStoreAccountLister returns a new CephObjectStoreAccountLister.
|
||||
func NewCephObjectStoreAccountLister(indexer cache.Indexer) CephObjectStoreAccountLister {
|
||||
return &cephObjectStoreAccountLister{listers.New[*cephrookiov1.CephObjectStoreAccount](indexer, cephrookiov1.Resource("cephobjectstoreaccount"))}
|
||||
}
|
||||
|
||||
// CephObjectStoreAccounts returns an object that can list and get CephObjectStoreAccounts.
|
||||
func (s *cephObjectStoreAccountLister) CephObjectStoreAccounts(namespace string) CephObjectStoreAccountNamespaceLister {
|
||||
return cephObjectStoreAccountNamespaceLister{listers.NewNamespaced[*cephrookiov1.CephObjectStoreAccount](s.ResourceIndexer, namespace)}
|
||||
}
|
||||
|
||||
// CephObjectStoreAccountNamespaceLister helps list and get CephObjectStoreAccounts.
|
||||
// All objects returned here must be treated as read-only.
|
||||
type CephObjectStoreAccountNamespaceLister interface {
|
||||
// List lists all CephObjectStoreAccounts in the indexer for a given namespace.
|
||||
// Objects returned here must be treated as read-only.
|
||||
List(selector labels.Selector) (ret []*cephrookiov1.CephObjectStoreAccount, err error)
|
||||
// Get retrieves the CephObjectStoreAccount from the indexer for a given namespace and name.
|
||||
// Objects returned here must be treated as read-only.
|
||||
Get(name string) (*cephrookiov1.CephObjectStoreAccount, error)
|
||||
CephObjectStoreAccountNamespaceListerExpansion
|
||||
}
|
||||
|
||||
// cephObjectStoreAccountNamespaceLister implements the CephObjectStoreAccountNamespaceLister
|
||||
// interface.
|
||||
type cephObjectStoreAccountNamespaceLister struct {
|
||||
listers.ResourceIndexer[*cephrookiov1.CephObjectStoreAccount]
|
||||
}
|
||||
@@ -130,6 +130,14 @@ type CephObjectStoreListerExpansion interface{}
|
||||
// CephObjectStoreNamespaceLister.
|
||||
type CephObjectStoreNamespaceListerExpansion interface{}
|
||||
|
||||
// CephObjectStoreAccountListerExpansion allows custom methods to be added to
|
||||
// CephObjectStoreAccountLister.
|
||||
type CephObjectStoreAccountListerExpansion interface{}
|
||||
|
||||
// CephObjectStoreAccountNamespaceListerExpansion allows custom methods to be added to
|
||||
// CephObjectStoreAccountNamespaceLister.
|
||||
type CephObjectStoreAccountNamespaceListerExpansion interface{}
|
||||
|
||||
// CephObjectStoreUserListerExpansion allows custom methods to be added to
|
||||
// CephObjectStoreUserLister.
|
||||
type CephObjectStoreUserListerExpansion interface{}
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/rook/rook/pkg/operator/ceph/nfs"
|
||||
"github.com/rook/rook/pkg/operator/ceph/nvmeof"
|
||||
"github.com/rook/rook/pkg/operator/ceph/object"
|
||||
objectaccount "github.com/rook/rook/pkg/operator/ceph/object/account"
|
||||
"github.com/rook/rook/pkg/operator/ceph/object/bucket"
|
||||
"github.com/rook/rook/pkg/operator/ceph/object/cosi"
|
||||
"github.com/rook/rook/pkg/operator/ceph/object/notification"
|
||||
@@ -93,6 +94,7 @@ var AddToManagerFuncs = []func(manager.Manager, *clusterd.Context, context.Conte
|
||||
subvolumegroup.Add,
|
||||
radosnamespace.Add,
|
||||
cosi.Add,
|
||||
objectaccount.Add,
|
||||
}
|
||||
|
||||
// AddToManagerOpFunc is a list of functions to add all Controllers to the Manager (entrypoint for
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright 2026 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 object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ceph/go-ceph/rgw/admin"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// GetAccount retrieves account information from RGW using the admin ops API.
|
||||
func GetAccount(ctx context.Context, adminOpsContext *AdminOpsContext, accountID string) (admin.Account, error) {
|
||||
if accountID == "" {
|
||||
return admin.Account{}, errors.New("account ID cannot be empty")
|
||||
}
|
||||
|
||||
account, err := adminOpsContext.AdminOpsClient.GetAccount(ctx, accountID)
|
||||
if err != nil {
|
||||
return admin.Account{}, errors.Wrapf(err, "failed to get account %q", accountID)
|
||||
}
|
||||
|
||||
return account, nil
|
||||
}
|
||||
|
||||
// CreateAccount creates a new RGW account using the admin ops API.
|
||||
// If account.ID is empty, Ceph will auto-generate the account ID.
|
||||
func CreateAccount(ctx context.Context, adminOpsContext *AdminOpsContext, account admin.Account) (admin.Account, error) {
|
||||
if account.Name == "" {
|
||||
return admin.Account{}, errors.New("account name cannot be empty")
|
||||
}
|
||||
|
||||
createdAccount, err := adminOpsContext.AdminOpsClient.CreateAccount(ctx, account)
|
||||
if err != nil {
|
||||
return admin.Account{}, errors.Wrapf(err, "failed to create account %q", account.Name)
|
||||
}
|
||||
|
||||
return createdAccount, nil
|
||||
}
|
||||
|
||||
// ModifyAccount modifies an existing RGW account.
|
||||
func ModifyAccount(ctx context.Context, adminOpsContext *AdminOpsContext, account admin.Account) (admin.Account, error) {
|
||||
if account.ID == "" {
|
||||
return admin.Account{}, errors.New("account ID cannot be empty")
|
||||
}
|
||||
|
||||
modifiedAccount, err := adminOpsContext.AdminOpsClient.ModifyAccount(ctx, account)
|
||||
if err != nil {
|
||||
return admin.Account{}, errors.Wrapf(err, "failed to modify account %q", account.ID)
|
||||
}
|
||||
|
||||
return modifiedAccount, nil
|
||||
}
|
||||
|
||||
// DeleteAccount removes an RGW account using the admin ops API.
|
||||
func DeleteAccount(ctx context.Context, adminOpsContext *AdminOpsContext, accountID string) error {
|
||||
if accountID == "" {
|
||||
return errors.New("account ID cannot be empty")
|
||||
}
|
||||
|
||||
err := adminOpsContext.AdminOpsClient.DeleteAccount(ctx, accountID)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to delete account %q", accountID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
Copyright 2026 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 account manages RGW accounts.
|
||||
package account
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"github.com/ceph/go-ceph/rgw/admin"
|
||||
"github.com/coreos/pkg/capnslog"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/tools/events"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
|
||||
cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
|
||||
"github.com/rook/rook/pkg/clusterd"
|
||||
cephclient "github.com/rook/rook/pkg/daemon/ceph/client"
|
||||
opcontroller "github.com/rook/rook/pkg/operator/ceph/controller"
|
||||
"github.com/rook/rook/pkg/operator/ceph/object"
|
||||
"github.com/rook/rook/pkg/operator/ceph/reporting"
|
||||
"github.com/rook/rook/pkg/operator/k8sutil"
|
||||
"github.com/rook/rook/pkg/util/log"
|
||||
)
|
||||
|
||||
const (
|
||||
controllerName = "ceph-object-store-account-controller"
|
||||
)
|
||||
|
||||
// newMultisiteAdminOpsCtxFunc helps us mocking the admin ops API client in unit test
|
||||
var newMultisiteAdminOpsCtxFunc = object.NewMultisiteAdminOpsContext
|
||||
|
||||
var logger = capnslog.NewPackageLogger("github.com/rook/rook", controllerName)
|
||||
|
||||
// Sets the type meta for the controller main object
|
||||
var controllerTypeMeta = metav1.TypeMeta{
|
||||
Kind: reflect.TypeFor[cephv1.CephObjectStoreAccount]().Name(),
|
||||
APIVersion: fmt.Sprintf("%s/%s", cephv1.CustomResourceGroup, cephv1.Version),
|
||||
}
|
||||
|
||||
// ReconcileObjectStoreAccount reconciles a CephObjectStoreAccount object
|
||||
type ReconcileObjectStoreAccount struct {
|
||||
client client.Client
|
||||
scheme *runtime.Scheme
|
||||
context *clusterd.Context
|
||||
objContext *object.AdminOpsContext
|
||||
cephClusterSpec *cephv1.ClusterSpec
|
||||
clusterInfo *cephclient.ClusterInfo
|
||||
opManagerContext context.Context
|
||||
recorder events.EventRecorder
|
||||
}
|
||||
|
||||
// Add creates a new CephObjectStoreAccount Controller and adds it to the Manager. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
// +kubebuilder:rbac:groups=ceph.rook.io,resources=cephobjectstoreaccounts,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=ceph.rook.io,resources=cephobjectstoreaccounts/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=ceph.rook.io,resources=cephobjectstoreaccounts/finalizers,verbs=update
|
||||
func Add(mgr manager.Manager, context *clusterd.Context, opManagerContext context.Context, opConfig opcontroller.OperatorConfig) error {
|
||||
return add(mgr, newReconciler(mgr, context, opManagerContext))
|
||||
}
|
||||
|
||||
// newReconciler returns a new reconcile.Reconciler
|
||||
func newReconciler(mgr manager.Manager, context *clusterd.Context, opManagerContext context.Context) reconcile.Reconciler {
|
||||
return &ReconcileObjectStoreAccount{
|
||||
client: mgr.GetClient(),
|
||||
scheme: mgr.GetScheme(),
|
||||
context: context,
|
||||
opManagerContext: opManagerContext,
|
||||
recorder: mgr.GetEventRecorder("rook-" + controllerName),
|
||||
}
|
||||
}
|
||||
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a new controller
|
||||
c, err := controller.New(controllerName, mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info("successfully started")
|
||||
|
||||
// Watch for changes on the CephObjectStoreAccount CRD object
|
||||
err = c.Watch(
|
||||
source.Kind(
|
||||
mgr.GetCache(),
|
||||
&cephv1.CephObjectStoreAccount{TypeMeta: controllerTypeMeta},
|
||||
&handler.TypedEnqueueRequestForObject[*cephv1.CephObjectStoreAccount]{},
|
||||
opcontroller.WatchControllerPredicate[*cephv1.CephObjectStoreAccount](mgr.GetScheme()),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reconcile reads that state of the cluster for a CephObjectStoreAccount object and makes changes based on the state read
|
||||
// and what is in the CephObjectStoreAccount.Spec
|
||||
// The Controller will requeue the Request to be processed again if the returned error is non-nil or
|
||||
// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
|
||||
func (r *ReconcileObjectStoreAccount) Reconcile(context context.Context, request reconcile.Request) (reconcile.Result, error) {
|
||||
defer opcontroller.RecoverAndLogException()
|
||||
// workaround because the rook logging mechanism is not compatible with the controller-runtime logging interface
|
||||
reconcileResponse, cephObjectStoreAccount, err := r.reconcile(request)
|
||||
if err != nil {
|
||||
r.updateStatus(k8sutil.ObservedGenerationNotAvailable, request.NamespacedName, k8sutil.ReconcileFailedStatus)
|
||||
log.NamedError(request.NamespacedName, logger, "failed to reconcile %v", err)
|
||||
}
|
||||
|
||||
return reporting.ReportReconcileResult(logger, r.recorder, request, &cephObjectStoreAccount, reconcileResponse, err)
|
||||
}
|
||||
|
||||
func (r *ReconcileObjectStoreAccount) reconcile(request reconcile.Request) (reconcile.Result, cephv1.CephObjectStoreAccount, error) {
|
||||
// Fetch the CephObjectStoreAccount instance
|
||||
cephObjectStoreAccount := &cephv1.CephObjectStoreAccount{}
|
||||
err := r.client.Get(r.opManagerContext, request.NamespacedName, cephObjectStoreAccount)
|
||||
if err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
log.NamedDebug(request.NamespacedName, logger, "CephObjectStoreAccount resource not found. Ignoring since object must be deleted.")
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, nil
|
||||
}
|
||||
// Error reading the object - requeue the request.
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, errors.Wrap(err, "failed to get CephObjectStoreAccount")
|
||||
}
|
||||
|
||||
// update observedGeneration local variable with current generation value,
|
||||
// because generation can be changed before reconcile got completed
|
||||
// CR status will be updated at end of reconcile, so to reflect the reconcile has finished
|
||||
observedGeneration := cephObjectStoreAccount.ObjectMeta.Generation
|
||||
|
||||
// Set a finalizer so we can do cleanup before the object goes away
|
||||
generationUpdated, err := opcontroller.AddFinalizerIfNotPresent(r.opManagerContext, r.client, cephObjectStoreAccount)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, errors.Wrap(err, "failed to add finalizer")
|
||||
}
|
||||
if generationUpdated {
|
||||
log.NamedInfo(request.NamespacedName, logger, "reconciling the object store account after adding finalizer")
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, nil
|
||||
}
|
||||
|
||||
// The CR was just created, initializing status fields
|
||||
if cephObjectStoreAccount.Status == nil {
|
||||
r.updateStatus(k8sutil.ObservedGenerationNotAvailable, request.NamespacedName, k8sutil.EmptyStatus)
|
||||
}
|
||||
|
||||
// Make sure a CephCluster is present otherwise do nothing
|
||||
cephCluster, isReadyToReconcile, cephClusterExists, reconcileResponse := opcontroller.IsReadyToReconcile(r.opManagerContext, r.client, request.NamespacedName, controllerName)
|
||||
if !isReadyToReconcile {
|
||||
// This handles the case where the Ceph Cluster is gone and we want to delete that CR
|
||||
// We skip the deleteAccount() function since everything is gone already
|
||||
//
|
||||
// Also, only remove the finalizer if the CephCluster is gone
|
||||
// If not, we should wait for it to be ready
|
||||
// This handles the case where the operator is not ready to accept Ceph command but the cluster exists
|
||||
if !cephObjectStoreAccount.GetDeletionTimestamp().IsZero() && !cephClusterExists {
|
||||
// Remove finalizer
|
||||
err = opcontroller.RemoveFinalizer(r.opManagerContext, r.client, cephObjectStoreAccount)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, errors.Wrap(err, "failed to remove finalizer")
|
||||
}
|
||||
|
||||
// Return and do not requeue. Successful deletion.
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, nil
|
||||
}
|
||||
return reconcileResponse, *cephObjectStoreAccount, nil
|
||||
}
|
||||
r.cephClusterSpec = &cephCluster.Spec
|
||||
|
||||
// Populate clusterInfo during each reconcile
|
||||
r.clusterInfo, _, _, err = opcontroller.LoadClusterInfo(r.context, r.opManagerContext, request.NamespacedName.Namespace, r.cephClusterSpec)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, errors.Wrap(err, "failed to populate cluster info")
|
||||
}
|
||||
|
||||
// Validate the object store has been initialized
|
||||
opsCtx, _, err := object.InitializeObjectStoreContext(r.context, r.clusterInfo, r.client, r.opManagerContext, cephObjectStoreAccount.Spec.Store, newMultisiteAdminOpsCtxFunc)
|
||||
if err != nil {
|
||||
if !cephObjectStoreAccount.GetDeletionTimestamp().IsZero() {
|
||||
// Remove finalizer
|
||||
err = opcontroller.RemoveFinalizer(r.opManagerContext, r.client, cephObjectStoreAccount)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, errors.Wrap(err, "failed to remove finalizer")
|
||||
}
|
||||
|
||||
// Return and do not requeue. Successful deletion.
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, nil
|
||||
}
|
||||
log.NamedDebug(request.NamespacedName, logger, "ObjectStore resource not ready, retrying in %q. %v",
|
||||
opcontroller.WaitForRequeueIfCephClusterNotReady.RequeueAfter.String(), err)
|
||||
return opcontroller.WaitForRequeueIfCephClusterNotReady, *cephObjectStoreAccount, err
|
||||
}
|
||||
r.objContext = opsCtx
|
||||
|
||||
// DELETE: the CR was deleted
|
||||
if !cephObjectStoreAccount.GetDeletionTimestamp().IsZero() {
|
||||
log.NamedDebug(request.NamespacedName, logger, "deleting object store account")
|
||||
r.recorder.Eventf(cephObjectStoreAccount, nil, corev1.EventTypeNormal, string(cephv1.ReconcileStarted), string(cephv1.ReconcileStarted), "deleting CephObjectStoreAccount %q", cephObjectStoreAccount.Name)
|
||||
|
||||
err := r.deleteAccount(cephObjectStoreAccount)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, errors.Wrapf(err, "failed to delete ceph object store account %q", cephObjectStoreAccount.Name)
|
||||
}
|
||||
|
||||
// Remove finalizer
|
||||
err = opcontroller.RemoveFinalizer(r.opManagerContext, r.client, cephObjectStoreAccount)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, errors.Wrap(err, "failed to remove finalizer")
|
||||
}
|
||||
|
||||
// Return and do not requeue. Successful deletion.
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, nil
|
||||
}
|
||||
|
||||
// CR is not deleted, continue reconciling
|
||||
|
||||
// Reconcile the account
|
||||
accountID, err := r.reconcileAccount(cephObjectStoreAccount)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, errors.Wrapf(err, "failed to reconcile account %q", cephObjectStoreAccount.Name)
|
||||
}
|
||||
|
||||
// Update the status with the account ID
|
||||
r.updateStatusWithAccountID(observedGeneration, request.NamespacedName, accountID)
|
||||
|
||||
return reconcile.Result{}, *cephObjectStoreAccount, nil
|
||||
}
|
||||
|
||||
// getAccountName returns the effective account name from the CR spec,
|
||||
// falling back to the CR name if spec.Name is not set.
|
||||
func getAccountName(cephObjectStoreAccount *cephv1.CephObjectStoreAccount) string {
|
||||
if cephObjectStoreAccount.Spec.Name != "" {
|
||||
return cephObjectStoreAccount.Spec.Name
|
||||
}
|
||||
return cephObjectStoreAccount.Name
|
||||
}
|
||||
|
||||
// getAccountID looks up an already-persisted account ID from the CR,
|
||||
// checking spec and status in priority order. It never generates
|
||||
// a new ID. Returns "" when no ID has been recorded yet.
|
||||
func getAccountID(cephObjectStoreAccount *cephv1.CephObjectStoreAccount) string {
|
||||
if cephObjectStoreAccount.Spec.AccountID != "" {
|
||||
return cephObjectStoreAccount.Spec.AccountID
|
||||
}
|
||||
if cephObjectStoreAccount.Status != nil && cephObjectStoreAccount.Status.AccountID != "" {
|
||||
return cephObjectStoreAccount.Status.AccountID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// getOrGenerateAccountID returns the existing account ID if one is persisted,
|
||||
// otherwise derives a deterministic ID from the CR's UID. This is used during
|
||||
// reconciliation to ensure the same ID is reused across retries, preventing
|
||||
// orphaned accounts if the operator crashes after creating an account but
|
||||
// before persisting the account ID to the CR status.
|
||||
func getOrGenerateAccountID(cephObjectStoreAccount *cephv1.CephObjectStoreAccount) (string, error) {
|
||||
if id := getAccountID(cephObjectStoreAccount); id != "" {
|
||||
return id, nil
|
||||
}
|
||||
if cephObjectStoreAccount.UID != "" {
|
||||
nsName := types.NamespacedName{Namespace: cephObjectStoreAccount.Namespace, Name: cephObjectStoreAccount.Name}
|
||||
log.NamedInfo(nsName, logger, "generating RGW account ID from the CR's UID")
|
||||
id, err := generateDeterministicAccountID(cephObjectStoreAccount.UID)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to generate deterministic account ID")
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// generateDeterministicAccountID derives a stable RGW account ID from the
|
||||
// CR's Kubernetes UID. It extracts 14 hex digits from the UUID, converts
|
||||
// them to a 17-digit decimal number, and prefixes it with "RGW". The same
|
||||
// UID always produces the same account ID.
|
||||
func generateDeterministicAccountID(uid types.UID) (string, error) {
|
||||
uidStr := string(uid)
|
||||
l := len(uidStr)
|
||||
if l < 14 {
|
||||
return "", fmt.Errorf("UID too short to generate account ID: %q", uidStr)
|
||||
}
|
||||
last12 := uidStr[l-12:]
|
||||
first2 := uidStr[:2]
|
||||
value, err := strconv.ParseUint(last12+first2, 16, 64)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse UID hex digits: %w", err)
|
||||
}
|
||||
return fmt.Sprintf("RGW%017d", value), nil
|
||||
}
|
||||
|
||||
func (r *ReconcileObjectStoreAccount) reconcileAccount(cephObjectStoreAccount *cephv1.CephObjectStoreAccount) (string, error) {
|
||||
accountID, err := getOrGenerateAccountID(cephObjectStoreAccount)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to get or generate account ID")
|
||||
}
|
||||
desiredAccount := admin.Account{
|
||||
ID: accountID,
|
||||
Name: getAccountName(cephObjectStoreAccount),
|
||||
}
|
||||
nsName := types.NamespacedName{Namespace: cephObjectStoreAccount.Namespace, Name: cephObjectStoreAccount.Name}
|
||||
|
||||
// Try to fetch the existing account
|
||||
liveAccountExists := true
|
||||
_, err = object.GetAccount(r.opManagerContext, r.objContext, desiredAccount.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, admin.ErrNoSuchKey) {
|
||||
log.NamedInfo(nsName, logger, "account %q does not exist", desiredAccount.ID)
|
||||
liveAccountExists = false
|
||||
} else {
|
||||
return "", errors.Wrapf(err, "failed to check if account exists")
|
||||
}
|
||||
}
|
||||
|
||||
// If Account exists then validate ownership and check if it needs to be updated
|
||||
if liveAccountExists {
|
||||
// Verify ownership before modifying an existing account. Ownership is confirmed if
|
||||
// the status already records the account ID (from a previous reconcile or from
|
||||
// the pre-creation bookmark persisted to status before account creation).
|
||||
hasOwnershipProof := cephObjectStoreAccount.Status != nil && cephObjectStoreAccount.Status.AccountID == desiredAccount.ID
|
||||
if !hasOwnershipProof {
|
||||
return "", fmt.Errorf("account ID %q already exists in RGW but is not managed by this CR; refusing to adopt a foreign account", desiredAccount.ID)
|
||||
}
|
||||
|
||||
log.NamedInfo(nsName, logger, "ensuring account %q is in sync", desiredAccount.ID)
|
||||
updatedAccount, err := object.ModifyAccount(r.opManagerContext, r.objContext, desiredAccount)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to modify account %q", desiredAccount.ID)
|
||||
}
|
||||
log.NamedInfo(nsName, logger, "successfully modified account %q", desiredAccount.ID)
|
||||
return updatedAccount.ID, nil
|
||||
}
|
||||
|
||||
// Persist the account ID to status before creating the account. This serves as a
|
||||
// creation bookmark so that if the operator crashes after creating the account but
|
||||
// before the final status update, the next reconcile can identify the account as
|
||||
// owned by this CR. The phase is not set to Ready here — that happens after
|
||||
// successful creation.
|
||||
if err := r.persistAccountIDToStatus(cephObjectStoreAccount, desiredAccount.ID); err != nil {
|
||||
return "", errors.Wrapf(err, "failed to persist account ID to status before creating account %q", desiredAccount.Name)
|
||||
}
|
||||
|
||||
// Account doesn't exist, create it
|
||||
log.NamedInfo(nsName, logger, "creating account %q", desiredAccount.Name)
|
||||
createdAccount, err := object.CreateAccount(r.opManagerContext, r.objContext, desiredAccount)
|
||||
if err != nil {
|
||||
if errors.Is(err, admin.ErrAccountAlreadyExists) {
|
||||
return "", fmt.Errorf("failed to create account with ID %q and name %q: an account with this ID or name already exists in RGW; ensure no conflicting account exists", desiredAccount.ID, desiredAccount.Name)
|
||||
}
|
||||
return "", errors.Wrapf(err, "failed to create account %q", desiredAccount.Name)
|
||||
}
|
||||
|
||||
log.NamedInfo(nsName, logger, "successfully created account %q with ID %q", desiredAccount.Name, createdAccount.ID)
|
||||
return createdAccount.ID, nil
|
||||
}
|
||||
|
||||
// persistAccountIDToStatus persists the account ID to the CR status before
|
||||
// creating the account in the backend. This is a no-op if the status already
|
||||
// contains the desired account ID. The phase is not modified here; it will be
|
||||
// set to Ready after the account is successfully created.
|
||||
func (r *ReconcileObjectStoreAccount) persistAccountIDToStatus(cephObjectStoreAccount *cephv1.CephObjectStoreAccount, accountID string) error {
|
||||
if cephObjectStoreAccount.Status != nil && cephObjectStoreAccount.Status.AccountID == accountID {
|
||||
return nil
|
||||
}
|
||||
// Re-fetch the latest version to avoid resourceVersion conflicts, since earlier
|
||||
// reconcile steps (e.g. updateStatus for initial empty status) may have updated
|
||||
// the object on the server, making our in-memory copy stale.
|
||||
nsName := types.NamespacedName{Namespace: cephObjectStoreAccount.Namespace, Name: cephObjectStoreAccount.Name}
|
||||
latest := &cephv1.CephObjectStoreAccount{}
|
||||
if err := r.client.Get(r.opManagerContext, nsName, latest); err != nil {
|
||||
return errors.Wrapf(err, "failed to get latest version of object %q", nsName)
|
||||
}
|
||||
if latest.Status == nil {
|
||||
latest.Status = &cephv1.ObjectStoreAccountStatus{}
|
||||
}
|
||||
latest.Status.AccountID = accountID
|
||||
if err := reporting.UpdateStatus(r.client, latest); err != nil {
|
||||
return errors.Wrapf(err, "failed to update object %q status", nsName)
|
||||
}
|
||||
// Update the caller's copy so subsequent checks see the persisted account ID
|
||||
cephObjectStoreAccount.Status = latest.Status
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ReconcileObjectStoreAccount) deleteAccount(cephObjectStoreAccount *cephv1.CephObjectStoreAccount) error {
|
||||
nsName := types.NamespacedName{Namespace: cephObjectStoreAccount.Namespace, Name: cephObjectStoreAccount.Name}
|
||||
accountID := getAccountID(cephObjectStoreAccount)
|
||||
if accountID == "" {
|
||||
log.NamedInfo(nsName, logger, "no account ID found, skipping deletion")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Only delete the account if we have ownership proof (status contains the account ID).
|
||||
// If the account ID is only in spec but was never successfully reconciled,
|
||||
// it means the controller never created/adopted this account, so we must
|
||||
// not delete what could be a foreign account.
|
||||
hasOwnershipProof := cephObjectStoreAccount.Status != nil && cephObjectStoreAccount.Status.AccountID == accountID
|
||||
if !hasOwnershipProof {
|
||||
log.NamedInfo(nsName, logger, "account %q was never successfully managed by this CR, skipping deletion to avoid removing a foreign account", accountID)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.NamedInfo(nsName, logger, "deleting account %q", accountID)
|
||||
|
||||
err := object.DeleteAccount(r.opManagerContext, r.objContext, accountID)
|
||||
if err != nil {
|
||||
// If account doesn't exist, consider it successful (idempotent)
|
||||
if errors.Is(err, admin.ErrNoSuchKey) {
|
||||
log.NamedInfo(nsName, logger, "account %q not found, considering deletion successful", accountID)
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(err, "failed to delete account %q", accountID)
|
||||
}
|
||||
|
||||
log.NamedInfo(nsName, logger, "successfully deleted account %q", accountID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ReconcileObjectStoreAccount) updateStatus(observedGeneration int64, name types.NamespacedName, status string) {
|
||||
account := &cephv1.CephObjectStoreAccount{}
|
||||
if err := r.client.Get(r.opManagerContext, name, account); err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
log.NamedDebug(name, logger, "CephObjectStoreAccount resource not found. Ignoring since object must be deleted.")
|
||||
return
|
||||
}
|
||||
log.NamedWarning(name, logger, "failed to retrieve object store account %q to update status. %v", name, err)
|
||||
return
|
||||
}
|
||||
if account.Status == nil {
|
||||
account.Status = &cephv1.ObjectStoreAccountStatus{}
|
||||
}
|
||||
|
||||
account.Status.Phase = status
|
||||
if observedGeneration != k8sutil.ObservedGenerationNotAvailable {
|
||||
account.Status.ObservedGeneration = &observedGeneration
|
||||
}
|
||||
if err := reporting.UpdateStatus(r.client, account); err != nil {
|
||||
log.NamedError(name, logger, "failed to set object store account %q status to %q. %v", name, status, err)
|
||||
return
|
||||
}
|
||||
log.NamedDebug(name, logger, "object store account %q status updated to %q", name, status)
|
||||
}
|
||||
|
||||
func (r *ReconcileObjectStoreAccount) updateStatusWithAccountID(observedGeneration int64, name types.NamespacedName, accountID string) {
|
||||
account := &cephv1.CephObjectStoreAccount{}
|
||||
if err := r.client.Get(r.opManagerContext, name, account); err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
log.NamedDebug(name, logger, "CephObjectStoreAccount resource not found. Ignoring since object must be deleted.")
|
||||
return
|
||||
}
|
||||
log.NamedWarning(name, logger, "failed to retrieve object store account %q to update status. %v", name, err)
|
||||
return
|
||||
}
|
||||
if account.Status == nil {
|
||||
account.Status = &cephv1.ObjectStoreAccountStatus{}
|
||||
}
|
||||
|
||||
account.Status.Phase = k8sutil.ReadyStatus
|
||||
account.Status.AccountID = accountID
|
||||
if observedGeneration != k8sutil.ObservedGenerationNotAvailable {
|
||||
account.Status.ObservedGeneration = &observedGeneration
|
||||
}
|
||||
if err := reporting.UpdateStatus(r.client, account); err != nil {
|
||||
log.NamedError(name, logger, "failed to update object store account %q status. %v", name, err)
|
||||
return
|
||||
}
|
||||
log.NamedDebug(name, logger, "object store account %q status updated with account ID %q", name, accountID)
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -114,7 +114,7 @@ const (
|
||||
RGWAdminOpsUserSecretName = "rgw-admin-ops-user"
|
||||
rgwAdminOpsUserAccessKey = "accessKey"
|
||||
rgwAdminOpsUserSecretKey = "secretKey"
|
||||
rgwAdminOpsUserCaps = "buckets=*;users=*;usage=read;metadata=read;zone=read"
|
||||
rgwAdminOpsUserCaps = "accounts=*;buckets=*;users=*;usage=read;metadata=read;zone=read"
|
||||
)
|
||||
|
||||
var rgwAdminOpsUserDisplayName = "RGW Admin Ops User"
|
||||
|
||||
@@ -43,6 +43,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
validation "k8s.io/apimachinery/pkg/util/validation"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -1280,3 +1281,71 @@ func SetDefaultRealm(objContext *Context, realmName string) error {
|
||||
log.NamedInfo(objContext.NsName(), logger, "successfully set realm %q as default", realmName+"/"+objContext.clusterInfo.Namespace)
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitializeObjectStoreContext finds the CephObjectStore by storeName, verifies it
|
||||
// is initialized (has running RGW pods or is external), creates a multisite context,
|
||||
// and initializes the admin ops API client.
|
||||
func InitializeObjectStoreContext(
|
||||
clusterdContext *clusterd.Context,
|
||||
clusterInfo *cephclient.ClusterInfo,
|
||||
k8sClient client.Client,
|
||||
opManagerContext context.Context,
|
||||
storeName string,
|
||||
newAdminOpsCtxFunc func(*Context, *cephv1.ObjectStoreSpec) (*AdminOpsContext, error),
|
||||
) (*AdminOpsContext, *cephv1.CephObjectStore, error) {
|
||||
store, err := getObjectStore(k8sClient, opManagerContext, storeName, clusterInfo.Namespace)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "failed to get object store %q", storeName)
|
||||
}
|
||||
|
||||
if !store.Spec.IsExternal() {
|
||||
if err := checkRGWPodsRunning(k8sClient, opManagerContext, clusterInfo.Namespace, storeName); err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "failed to detect if object store %q is initialized", storeName)
|
||||
}
|
||||
}
|
||||
|
||||
objContext, err := NewMultisiteContext(clusterdContext, clusterInfo, store)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "failed to create multisite context for object store %q", store.Name)
|
||||
}
|
||||
|
||||
opsContext, err := newAdminOpsCtxFunc(objContext, &store.Spec)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "failed to initialize rgw admin ops client api")
|
||||
}
|
||||
|
||||
return opsContext, store, nil
|
||||
}
|
||||
|
||||
func getObjectStore(k8sClient client.Client, ctx context.Context, storeName, namespace string) (*cephv1.CephObjectStore, error) {
|
||||
store := &cephv1.CephObjectStore{}
|
||||
if err := k8sClient.Get(ctx, types.NamespacedName{Name: storeName, Namespace: namespace}, store); err != nil {
|
||||
return nil, errors.Wrapf(err, "could not find CephObjectStore %q", storeName)
|
||||
}
|
||||
return store, nil
|
||||
}
|
||||
|
||||
func checkRGWPodsRunning(k8sClient client.Client, ctx context.Context, namespace, storeName string) error {
|
||||
pods := &v1.PodList{}
|
||||
listOpts := []client.ListOption{
|
||||
client.InNamespace(namespace),
|
||||
client.MatchingLabels(labelsForRgw(storeName)),
|
||||
}
|
||||
|
||||
if err := k8sClient.List(ctx, pods, listOpts...); err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
return errors.Wrap(err, "no rgw pod could not be found")
|
||||
}
|
||||
return errors.Wrap(err, "failed to list rgw pods")
|
||||
}
|
||||
|
||||
if len(pods.Items) > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("no rgw pod found")
|
||||
}
|
||||
|
||||
func labelsForRgw(name string) map[string]string {
|
||||
return map[string]string{"rgw": name, k8sutil.AppAttr: AppName}
|
||||
}
|
||||
@@ -493,14 +493,9 @@ func (r *ReconcileObjectStoreUser) createOrUpdateCephUser(u *cephv1.CephObjectSt
|
||||
}
|
||||
|
||||
func (r *ReconcileObjectStoreUser) initializeObjectStoreContext(u *cephv1.CephObjectStoreUser) error {
|
||||
err := r.objectStoreInitialized(u)
|
||||
opsContext, store, err := object.InitializeObjectStoreContext(r.context, r.clusterInfo, r.client, r.opManagerContext, u.Spec.Store, newMultisiteAdminOpsCtxFunc)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to detect if object store %q is initialized", u.Spec.Store)
|
||||
}
|
||||
|
||||
store, err := r.getObjectStore(u)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get object store %q", u.Spec.Store)
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if the object store allows users to be created in any namespace
|
||||
@@ -518,16 +513,6 @@ func (r *ReconcileObjectStoreUser) initializeObjectStoreContext(u *cephv1.CephOb
|
||||
return errors.Wrapf(err, "failed to get CephObjectStore %q advertise endpoint for object store user", u.Spec.Store)
|
||||
}
|
||||
r.advertiseEndpoint = advertiseEndpoint
|
||||
|
||||
objContext, err := object.NewMultisiteContext(r.context, r.clusterInfo, store)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Multisite failed to set on object context for object store user")
|
||||
}
|
||||
|
||||
opsContext, err := newMultisiteAdminOpsCtxFunc(objContext, &store.Spec)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to initialized rgw admin ops client api")
|
||||
}
|
||||
r.objContext = opsContext
|
||||
|
||||
return nil
|
||||
@@ -705,36 +690,6 @@ func (r *ReconcileObjectStoreUser) reconcileCephUserSecret(cephObjectStoreUser *
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileObjectStoreUser) objectStoreInitialized(cephObjectStoreUser *cephv1.CephObjectStoreUser) error {
|
||||
nsName := opcontroller.NsName(cephObjectStoreUser.Namespace, cephObjectStoreUser.Name)
|
||||
cephObjectStore, err := r.getObjectStore(cephObjectStoreUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.NamedDebug(nsName, logger, "CephObjectStore exists")
|
||||
|
||||
// If the rgw is external just return
|
||||
// since there are no pods running
|
||||
if cephObjectStore.Spec.IsExternal() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// There are no pods running when the cluster is external
|
||||
// Unless you pass the admin key...
|
||||
pods, err := r.getRgwPodList(cephObjectStoreUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if at least one pod is running
|
||||
if len(pods.Items) > 0 {
|
||||
log.NamedDebug(nsName, logger, "%d RGW pods found where object store user %q is created", len(pods.Items), cephObjectStoreUser.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("no rgw pod found")
|
||||
}
|
||||
|
||||
func (r *ReconcileObjectStoreUser) getObjectStore(user *cephv1.CephObjectStoreUser) (*cephv1.CephObjectStore, error) {
|
||||
storeName := user.Spec.Store
|
||||
nsName := client.ObjectKeyFromObject(user)
|
||||
@@ -759,27 +714,6 @@ func (r *ReconcileObjectStoreUser) getObjectStore(user *cephv1.CephObjectStoreUs
|
||||
return nil, errors.Errorf("could not find CephObjectStore %q referenced by CephObjectStoreUser %q", storeName, nsName)
|
||||
}
|
||||
|
||||
func (r *ReconcileObjectStoreUser) getRgwPodList(cephObjectStoreUser *cephv1.CephObjectStoreUser) (*corev1.PodList, error) {
|
||||
pods := &corev1.PodList{}
|
||||
|
||||
// check if ObjectStore is initialized
|
||||
// rook does this by starting the RGW pod(s)
|
||||
listOpts := []client.ListOption{
|
||||
client.InNamespace(clusterStoreNamespace(cephObjectStoreUser)),
|
||||
client.MatchingLabels(labelsForRgw(cephObjectStoreUser.Spec.Store)),
|
||||
}
|
||||
|
||||
err := r.client.List(r.opManagerContext, pods, listOpts...)
|
||||
if err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
return pods, errors.Wrap(err, "no rgw pod could not be found")
|
||||
}
|
||||
return pods, errors.Wrap(err, "failed to list rgw pods")
|
||||
}
|
||||
|
||||
return pods, nil
|
||||
}
|
||||
|
||||
// Namespace where the object store and cluster are expected to be found
|
||||
func clusterStoreNamespace(user *cephv1.CephObjectStoreUser) string {
|
||||
if user.Spec.ClusterNamespace != "" {
|
||||
@@ -818,10 +752,6 @@ func (r *ReconcileObjectStoreUser) validateUser(u *cephv1.CephObjectStoreUser) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func labelsForRgw(name string) map[string]string {
|
||||
return map[string]string{"rgw": name, k8sutil.AppAttr: appName}
|
||||
}
|
||||
|
||||
// updateStatus updates an object with a given status
|
||||
func (r *ReconcileObjectStoreUser) updateStatus(observedGeneration int64, name types.NamespacedName, status string) {
|
||||
user := &cephv1.CephObjectStoreUser{}
|
||||
|
||||
Reference in new issue
Block a user