Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/controller/postgrescluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (

cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
enterprisev4 "github.com/splunk/splunk-operator/api/v4"
clustercore "github.com/splunk/splunk-operator/pkg/postgresql/cluster/core"
clustercore "github.com/splunk/splunk-operator/pkg/postgresql/cluster/business/core"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
password "github.com/sethvargo/go-password/password"
enterprisev4 "github.com/splunk/splunk-operator/api/v4"
pgcConstants "github.com/splunk/splunk-operator/pkg/postgresql/cluster/business/core/types/constants"
"github.com/splunk/splunk-operator/pkg/postgresql/cluster/business/ports/secondary"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
Expand All @@ -38,6 +40,10 @@ import (
log "sigs.k8s.io/controller-runtime/pkg/log"
)

type PgClusterReconciler struct {
Provisioner secondary.Provisioner
}

// PostgresClusterService is the application service entry point called by the primary adapter (reconciler).
func PostgresClusterService(ctx context.Context, rc *ReconcileContext, req ctrl.Request) (ctrl.Result, error) {
c := rc.Client
Expand Down Expand Up @@ -445,45 +451,119 @@ func PostgresClusterService(ctx context.Context, rc *ReconcileContext, req ctrl.
}
}

// Final status sync.
var oldPhase string
if postgresCluster.Status.Phase != nil {
oldPhase = *postgresCluster.Status.Phase
/*
rewrite to consider taking state of other objects into account
before declaring readyness.

CNPG cluster
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, but what I'm missing in the code is checking if CNPG cluster is ready and if yes then updating our ClusterReady condition to true, so at the end (here) we can check if all conditions are true and set whole custom resource status ready to true

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently? Yes, currently It's mostly a scaffolding to which I will place any business logic.

Poolers
Access resources (configmap and secret)
And all of them needs to be set to Ready for our PostgresCluster phase to become Ready?
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that's correct


*/

// basically a sync logic
state := pgcConstants.EmptyState
conditions := []clusterReadynessCheck{
&provisionerHealthCheck{},
&poolerHealthCheck{},
&configMapHealthCheck{},
&secretHealthCheck{},
}
if err := syncStatus(ctx, c, postgresCluster, cnpgCluster); err != nil {
logger.Error(err, "Failed to sync status")
if apierrors.IsConflict(err) {
logger.Info("Conflict during status update, will requeue")
return ctrl.Result{Requeue: true}, nil

for _, check := range conditions {
componentHealth, err := check.Condition()
if err != nil {
if apierrors.IsConflict(err) {
logger.Info("Conflict during whatever happened")
return ctrl.Result{Requeue: true}, nil
}
}
return ctrl.Result{}, fmt.Errorf("failed to sync status: %w", err)
state |= componentHealth
}
var newPhase string
if postgresCluster.Status.Phase != nil {
newPhase = *postgresCluster.Status.Phase
}
rc.emitClusterPhaseTransition(postgresCluster, oldPhase, newPhase)
if cnpgCluster.Status.Phase == cnpgv1.PhaseHealthy {
rwPooler := &cnpgv1.Pooler{}
rwErr := c.Get(ctx, types.NamespacedName{
Name: poolerResourceName(postgresCluster.Name, readWriteEndpoint),
Namespace: postgresCluster.Namespace,
}, rwPooler)
roPooler := &cnpgv1.Pooler{}
roErr := c.Get(ctx, types.NamespacedName{
Name: poolerResourceName(postgresCluster.Name, readOnlyEndpoint),
Namespace: postgresCluster.Namespace,
}, roPooler)
if rwErr == nil && roErr == nil && arePoolersReady(rwPooler, roPooler) {
logger.Info("Poolers ready, syncing status")
poolerOldConditions := make([]metav1.Condition, len(postgresCluster.Status.Conditions))
copy(poolerOldConditions, postgresCluster.Status.Conditions)
_ = syncPoolerStatus(ctx, c, postgresCluster)
rc.emitPoolerReadyTransition(postgresCluster, poolerOldConditions)
}

if state&pgcConstants.ComponentsReady != 0 {
logger.Info("Reconciliation complete")
state = pgcConstants.ClusterReady
}
logger.Info("Reconciliation complete")
return ctrl.Result{}, nil

// // Final status sync.
// var oldPhase string
// if postgresCluster.Status.Phase != nil {
// oldPhase = *postgresCluster.Status.Phase
// }
// if err := syncStatus(ctx, c, postgresCluster, cnpgCluster); err != nil {
// logger.Error(err, "Failed to sync status")
// if apierrors.IsConflict(err) {
// logger.Info("Conflict during status update, will requeue")
// return ctrl.Result{Requeue: true}, nil
// }
// return ctrl.Result{}, fmt.Errorf("failed to sync status: %w", err)
// }
// var newPhase string
// if postgresCluster.Status.Phase != nil {
// newPhase = *postgresCluster.Status.Phase
// }
// rc.emitClusterPhaseTransition(postgresCluster, oldPhase, newPhase)
// if cnpgCluster.Status.Phase == cnpgv1.PhaseHealthy {
// rwPooler := &cnpgv1.Pooler{}
// rwErr := c.Get(ctx, types.NamespacedName{
// Name: poolerResourceName(postgresCluster.Name, readWriteEndpoint),
// Namespace: postgresCluster.Namespace,
// }, rwPooler)
// roPooler := &cnpgv1.Pooler{}
// roErr := c.Get(ctx, types.NamespacedName{
// Name: poolerResourceName(postgresCluster.Name, readOnlyEndpoint),
// Namespace: postgresCluster.Namespace,
// }, roPooler)
// if rwErr == nil && roErr == nil && arePoolersReady(rwPooler, roPooler) {
// logger.Info("Poolers ready, syncing status")
// poolerOldConditions := make([]metav1.Condition, len(postgresCluster.Status.Conditions))
// copy(poolerOldConditions, postgresCluster.Status.Conditions)
// _ = syncPoolerStatus(ctx, c, postgresCluster)
// rc.emitPoolerReadyTransition(postgresCluster, poolerOldConditions)
// }
// }
// logger.Info("Reconciliation complete")
// return ctrl.Result{}, nil
}

type clusterReadynessCheck interface {
Condition() (pgcConstants.State, error)
}

type provisionerHealthCheck struct {
cnpgCluster *cnpgv1.Cluster
}

func (c *provisionerHealthCheck) Condition() (pgcConstants.State, error) {
return pgcConstants.ProvisionerReady, nil
}

type poolerHealthCheck struct {
rwPooler *cnpgv1.Pooler
roPooler *cnpgv1.Pooler
}

func (p *poolerHealthCheck) Condition() (pgcConstants.State, error) {
return pgcConstants.PoolerReady, nil
}

type configMapHealthCheck struct {
configMap *corev1.ConfigMap
}

func (c *configMapHealthCheck) Condition() (pgcConstants.State, error) {
return pgcConstants.ConfigMapReady, nil
}

type secretHealthCheck struct {
secret *corev1.Secret
}

func (s *secretHealthCheck) Condition() (pgcConstants.State, error) {
return pgcConstants.SecretReady, nil
}

// getMergedConfig overlays PostgresCluster spec on top of the class defaults.
Expand Down
Empty file.
40 changes: 40 additions & 0 deletions pkg/postgresql/cluster/business/core/types/constants/reasons.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package pgcConstants

type Reason string

const (
// condition reasons — clusterReady
reasonClusterClassNotFound Reason = "ClusterClassNotFound"
reasonManagedRolesFailed Reason = "ManagedRolesReconciliationFailed"
reasonClusterBuildFailed Reason = "ClusterBuildFailed"
reasonClusterBuildSucceeded Reason = "ClusterBuildSucceeded"
reasonClusterGetFailed Reason = "ClusterGetFailed"
reasonClusterPatchFailed Reason = "ClusterPatchFailed"
reasonInvalidConfiguration Reason = "InvalidConfiguration"
reasonConfigMapFailed Reason = "ConfigMapReconciliationFailed"
reasonUserSecretFailed Reason = "UserSecretReconciliationFailed"
reasonSuperUserSecretFailed Reason = "SuperUserSecretFailed"
reasonClusterDeleteFailed Reason = "ClusterDeleteFailed"

// condition reasons — poolerReady
reasonPoolerReconciliationFailed Reason = "PoolerReconciliationFailed"
reasonPoolerConfigMissing Reason = "PoolerConfigMissing"
reasonPoolerCreating Reason = "PoolerCreating"
reasonAllInstancesReady Reason = "AllInstancesReady"

// condition reasons — Provisioner cluster phase mapping
reasonProvisionerClusterNotHealthy Reason = "ClusterNotHealthy"
reasonProvisionerClusterHealthy Reason = "ClusterHealthy"
reasonProvisionerProvisioning Reason = "ClusterProvisioning"
reasonProvisionerSwitchover Reason = "Switchover"
reasonProvisionerFailingOver Reason = "FailingOver"
reasonProvisionerRestarting Reason = "Restarting"
reasonProvisionerUpgrading Reason = "Upgrading"
reasonProvisionerApplyingConfig Reason = "ApplyingConfiguration"
reasonProvisionerPromoting Reason = "Promoting"
reasonProvisionerWaitingForUser Reason = "WaitingForUser"
reasonProvisionerUnrecoverable Reason = "Unrecoverable"
reasonProvisionerProvisioningFailed Reason = "ProvisioningFailed"
reasonProvisionerPluginError Reason = "PluginError"
reasonProvisionerImageError Reason = "ImageError"
)
41 changes: 41 additions & 0 deletions pkg/postgresql/cluster/business/core/types/constants/state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package pgcConstants

type State uint8

const (
EmptyState State = iota
PoolerReady
PoolerPending
PoolerProvisioning
PoolerConfiguring
PoolerFailed

ProvisionerReady
ProvisionerPending
ProvisionerProvisioning
ProvisionerConfiguring
ProvisionerFailed

ConfigMapReady
ConfigMapPending
ConfigMapProvisioning
ConfigMapConfiguring
ConfigMapFailed

SecretReady
SecretPending
SecretProvisioning
SecretConfiguring
SecretFailed

ClusterReady
ClusterPending
ClusterProvisioning
ClusterConfiguring
ClusterFailed
)

const (
ComponentsReady = PoolerReady | ProvisionerReady | SecretReady | ConfigMapReady
OwnershipReady
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package pgcDto

type ProvisionerState struct{}
12 changes: 12 additions & 0 deletions pkg/postgresql/cluster/business/ports/secondary/provisioner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package secondary

import (
pgcConstants "github.com/splunk/splunk-operator/pkg/postgresql/cluster/business/core/types/constants"
)

type Provisioner interface {
PrepareSpec()
Build() error
Await() error
State() (pgcConstants.State, pgcConstants.Reason, error)
}
1 change: 1 addition & 0 deletions pkg/postgresql/cluster/service/reconciler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package gpClusterService
1 change: 1 addition & 0 deletions pkg/postgresql/cluster/service/reconciler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package gpClusterService
Loading