diff --git a/deploy/charts/rook-ceph/templates/resources.yaml b/deploy/charts/rook-ceph/templates/resources.yaml index 90721c598e21..bea766e23572 100644 --- a/deploy/charts/rook-ceph/templates/resources.yaml +++ b/deploy/charts/rook-ceph/templates/resources.yaml @@ -100,6 +100,27 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .status.info.type + name: Type + type: string + - jsonPath: .status.info.failureDomain + name: FailureDomain + type: string + - jsonPath: .spec.replicated.size + name: Replication + priority: 1 + type: integer + - jsonPath: .spec.erasureCoded.codingChunks + name: EC-CodingChunks + priority: 1 + type: integer + - jsonPath: .spec.erasureCoded.dataChunks + name: EC-DataChunks + priority: 1 + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -671,6 +692,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -828,6 +852,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -5763,6 +5790,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -7919,6 +7949,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -10017,6 +10050,15 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .status.info.endpoint + name: Endpoint + type: string + - jsonPath: .status.info.secureEndpoint + name: SecureEndpoint + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -11511,6 +11553,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -11748,6 +11793,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -11841,6 +11889,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -12332,6 +12383,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: diff --git a/deploy/examples/crds.yaml b/deploy/examples/crds.yaml index c37d3dad7820..e6892599247a 100644 --- a/deploy/examples/crds.yaml +++ b/deploy/examples/crds.yaml @@ -102,6 +102,27 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .status.info.type + name: Type + type: string + - jsonPath: .status.info.failureDomain + name: FailureDomain + type: string + - jsonPath: .spec.replicated.size + name: Replication + priority: 1 + type: integer + - jsonPath: .spec.erasureCoded.codingChunks + name: EC-CodingChunks + priority: 1 + type: integer + - jsonPath: .spec.erasureCoded.dataChunks + name: EC-DataChunks + priority: 1 + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -671,6 +692,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -827,6 +851,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -5759,6 +5786,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -7913,6 +7943,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -10008,6 +10041,15 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .status.info.endpoint + name: Endpoint + type: string + - jsonPath: .status.info.secureEndpoint + name: SecureEndpoint + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -11501,6 +11543,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -11737,6 +11782,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -11829,6 +11877,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: @@ -12319,6 +12370,9 @@ spec: - jsonPath: .status.phase name: Phase type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date name: v1 schema: openAPIV3Schema: diff --git a/pkg/apis/ceph.rook.io/v1/types.go b/pkg/apis/ceph.rook.io/v1/types.go index 6a954e41fc00..6933bcb62b67 100755 --- a/pkg/apis/ceph.rook.io/v1/types.go +++ b/pkg/apis/ceph.rook.io/v1/types.go @@ -694,6 +694,12 @@ type CrashCollectorSpec struct { // CephBlockPool represents a Ceph Storage Pool // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Type",type=string,JSONPath=`.status.info.type` +// +kubebuilder:printcolumn:name="FailureDomain",type=string,JSONPath=`.status.info.failureDomain` +// +kubebuilder:printcolumn:name="Replication",type=integer,JSONPath=`.spec.replicated.size`,priority=1 +// +kubebuilder:printcolumn:name="EC-CodingChunks",type=integer,JSONPath=`.spec.erasureCoded.codingChunks`,priority=1 +// +kubebuilder:printcolumn:name="EC-DataChunks",type=integer,JSONPath=`.spec.erasureCoded.dataChunks`,priority=1 +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:subresource:status type CephBlockPool struct { metav1.TypeMeta `json:",inline"` @@ -1401,6 +1407,9 @@ type PeerStatSpec struct { // CephObjectStore represents a Ceph Object Store Gateway // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Endpoint",type=string,JSONPath=`.status.info.endpoint` +// +kubebuilder:printcolumn:name="SecureEndpoint",type=string,JSONPath=`.status.info.secureEndpoint` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:subresource:status type CephObjectStore struct { metav1.TypeMeta `json:",inline"` @@ -1664,6 +1673,7 @@ type ObjectStoreHostingSpec struct { // CephObjectStoreUser represents a Ceph Object Store Gateway User // +kubebuilder:resource:shortName=rcou;objectuser // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:subresource:status type CephObjectStoreUser struct { metav1.TypeMeta `json:",inline"` @@ -1841,6 +1851,7 @@ type PullSpec struct { // CephObjectZoneGroup represents a Ceph Object Store Gateway Zone Group // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:subresource:status type CephObjectZoneGroup struct { metav1.TypeMeta `json:",inline"` @@ -1871,6 +1882,7 @@ type ObjectZoneGroupSpec struct { // CephObjectZone represents a Ceph Object Store Gateway Zone // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:subresource:status type CephObjectZone struct { metav1.TypeMeta `json:",inline"` @@ -1933,6 +1945,7 @@ type ObjectZoneSpec struct { // CephBucketTopic represents a Ceph Object Topic for Bucket Notifications // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:subresource:status type CephBucketTopic struct { metav1.TypeMeta `json:",inline"` @@ -2569,6 +2582,7 @@ type DisruptionManagementSpec struct { // CephClient represents a Ceph Client // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:subresource:status type CephClient struct { metav1.TypeMeta `json:",inline"` @@ -2656,6 +2670,7 @@ type SanitizeDisksSpec struct { // CephRBDMirror represents a Ceph RBD Mirror // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:subresource:status type CephRBDMirror struct { metav1.TypeMeta `json:",inline"` @@ -2727,6 +2742,7 @@ type MirroringPeerSpec struct { // CephFilesystemMirror is the Ceph Filesystem Mirror object definition // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:subresource:status type CephFilesystemMirror struct { metav1.TypeMeta `json:",inline"` @@ -2961,6 +2977,7 @@ type StorageClassDeviceSet struct { // CephFilesystemSubVolumeGroup represents a Ceph Filesystem SubVolumeGroup // +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // +kubebuilder:subresource:status type CephFilesystemSubVolumeGroup struct { metav1.TypeMeta `json:",inline"` diff --git a/pkg/operator/ceph/pool/controller.go b/pkg/operator/ceph/pool/controller.go index 8d7981f09cd6..c2a6c963be90 100644 --- a/pkg/operator/ceph/pool/controller.go +++ b/pkg/operator/ceph/pool/controller.go @@ -175,7 +175,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile // The CR was just created, initializing status fields if cephBlockPool.Status == nil { - updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionProgressing, nil, k8sutil.ObservedGenerationNotAvailable) + updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionProgressing, k8sutil.ObservedGenerationNotAvailable) } // Make sure a CephCluster is present otherwise do nothing @@ -287,7 +287,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile logger.Info(opcontroller.OperatorNotInitializedMessage) return opcontroller.WaitForRequeueIfOperatorNotInitialized, *cephBlockPool, nil } - updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionFailure, nil, k8sutil.ObservedGenerationNotAvailable) + updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionFailure, k8sutil.ObservedGenerationNotAvailable) return reconcileResponse, *cephBlockPool, errors.Wrapf(err, "failed to create pool %q.", cephBlockPool.GetName()) } @@ -302,7 +302,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile // Always create a bootstrap peer token in case another cluster wants to add us as a peer reconcileResponse, err = opcontroller.CreateBootstrapPeerSecret(r.context, clusterInfo, cephBlockPool, k8sutil.NewOwnerInfo(cephBlockPool, r.scheme)) if err != nil { - updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionFailure, nil, k8sutil.ObservedGenerationNotAvailable) + updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionFailure, k8sutil.ObservedGenerationNotAvailable) return reconcileResponse, *cephBlockPool, errors.Wrapf(err, "failed to create rbd-mirror bootstrap peer for pool %q.", cephBlockPool.GetName()) } @@ -334,7 +334,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile // update ObservedGeneration in status at the end of reconcile // Set Ready status, we are done reconciling - updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionReady, opcontroller.GenerateStatusInfo(cephBlockPool), observedGeneration) + updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionReady, observedGeneration) // If not mirrored there is no Status Info field to fulfil } else { @@ -345,7 +345,7 @@ func (r *ReconcileCephBlockPool) reconcile(request reconcile.Request) (reconcile } // update ObservedGeneration in status at the end of reconcile // Set Ready status, we are done reconciling - updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionReady, nil, observedGeneration) + updateStatus(r.opManagerContext, r.client, request.NamespacedName, cephv1.ConditionReady, observedGeneration) // Stop monitoring the mirroring status of this pool if blockPoolContextsExists && r.blockPoolContexts[blockPoolChannelKey].started { diff --git a/pkg/operator/ceph/pool/status.go b/pkg/operator/ceph/pool/status.go index 85aaa2fbbd66..e9de744fd79c 100644 --- a/pkg/operator/ceph/pool/status.go +++ b/pkg/operator/ceph/pool/status.go @@ -22,6 +22,7 @@ import ( "time" cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" + opcontroller "github.com/rook/rook/pkg/operator/ceph/controller" "github.com/rook/rook/pkg/operator/ceph/reporting" "github.com/rook/rook/pkg/operator/k8sutil" kerrors "k8s.io/apimachinery/pkg/api/errors" @@ -30,7 +31,7 @@ import ( ) // updateStatus updates a pool CR with the given status -func updateStatus(ctx context.Context, client client.Client, poolName types.NamespacedName, status cephv1.ConditionType, info map[string]string, observedGeneration int64) { +func updateStatus(ctx context.Context, client client.Client, poolName types.NamespacedName, status cephv1.ConditionType, observedGeneration int64) { pool := &cephv1.CephBlockPool{} err := client.Get(ctx, poolName, pool) if err != nil { @@ -47,7 +48,7 @@ func updateStatus(ctx context.Context, client client.Client, poolName types.Name } pool.Status.Phase = status - pool.Status.Info = info + updateStatusInfo(pool) if observedGeneration != k8sutil.ObservedGenerationNotAvailable { pool.Status.ObservedGeneration = observedGeneration } @@ -130,3 +131,27 @@ func toCustomResourceStatus(currentStatus *cephv1.MirroringStatusSpec, mirroring return mirroringStatusSpec, mirroringInfoSpec, snapshotScheduleStatusSpec } + +func updateStatusInfo(cephBlockPool *cephv1.CephBlockPool) { + m := make(map[string]string) + if cephBlockPool.Status.Phase == cephv1.ConditionReady && cephBlockPool.Spec.Mirroring.Enabled { + mirroringInfo := opcontroller.GenerateStatusInfo(cephBlockPool) + for key, value := range mirroringInfo { + m[key] = value + } + } + + if cephBlockPool.Spec.IsReplicated() { + m["type"] = "Replicated" + } else { + m["type"] = "Erasure Coded" + } + + if cephBlockPool.Spec.FailureDomain != "" { + m["failureDomain"] = cephBlockPool.Spec.FailureDomain + } else { + m["failureDomain"] = cephv1.DefaultFailureDomain + } + + cephBlockPool.Status.Info = m +} diff --git a/pkg/operator/ceph/pool/status_test.go b/pkg/operator/ceph/pool/status_test.go index f9723a1a59d5..e34b58282aed 100644 --- a/pkg/operator/ceph/pool/status_test.go +++ b/pkg/operator/ceph/pool/status_test.go @@ -21,6 +21,7 @@ import ( "testing" cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" + opcontroller "github.com/rook/rook/pkg/operator/ceph/controller" "github.com/stretchr/testify/assert" ) @@ -58,3 +59,59 @@ func TestToCustomResourceStatus(t *testing.T) { assert.NotEmpty(t, newSnapshotScheduleStatus) } } + +func TestUpdateStatusInfo(t *testing.T) { + + cephBlockPoolReplicated := &cephv1.CephBlockPool{ + Spec: cephv1.NamedBlockPoolSpec{ + Name: "test-pool-replicated", + PoolSpec: cephv1.PoolSpec{ + Replicated: cephv1.ReplicatedSpec{ + Size: 3, + }, + }, + }, + Status: &cephv1.CephBlockPoolStatus{ + Phase: cephv1.ConditionProgressing, + }, + } + updateStatusInfo(cephBlockPoolReplicated) + statusInfo := cephBlockPoolReplicated.Status.Info + assert.Equal(t, "Replicated", statusInfo["type"]) + assert.Equal(t, cephv1.DefaultFailureDomain, statusInfo["failureDomain"]) + assert.Empty(t, statusInfo[opcontroller.RBDMirrorBootstrapPeerSecretName]) + + cephBlockPoolErasureCoded := &cephv1.CephBlockPool{ + Spec: cephv1.NamedBlockPoolSpec{ + Name: "test-pool-erasure-coded", + PoolSpec: cephv1.PoolSpec{ + FailureDomain: "osd", + ErasureCoded: cephv1.ErasureCodedSpec{ + CodingChunks: 6, + DataChunks: 2, + }, + }, + }, + Status: &cephv1.CephBlockPoolStatus{ + Phase: cephv1.ConditionProgressing, + }, + } + updateStatusInfo(cephBlockPoolErasureCoded) + statusInfo = cephBlockPoolErasureCoded.Status.Info + assert.Equal(t, "Erasure Coded", statusInfo["type"]) + assert.Equal(t, "osd", statusInfo["failureDomain"]) + assert.Empty(t, statusInfo[opcontroller.RBDMirrorBootstrapPeerSecretName]) + + cephBlockPoolErasureCoded.Spec.PoolSpec.Mirroring = cephv1.MirroringSpec{ + Enabled: true, + } + + updateStatusInfo(cephBlockPoolErasureCoded) + statusInfo = cephBlockPoolErasureCoded.Status.Info + assert.Empty(t, statusInfo[opcontroller.RBDMirrorBootstrapPeerSecretName]) + + cephBlockPoolErasureCoded.Status.Phase = cephv1.ConditionReady + updateStatusInfo(cephBlockPoolErasureCoded) + statusInfo = cephBlockPoolErasureCoded.Status.Info + assert.NotEmpty(t, statusInfo[opcontroller.RBDMirrorBootstrapPeerSecretName]) +}