in oracle/controllers/instancecontroller/instance_controller.go [509:664]
func (r *InstanceReconciler) reconcileDatabaseInstance(ctx context.Context, inst *v1alpha1.Instance, log logr.Logger, images map[string]string) (ctrl.Result, error) {
instanceReadyCond := k8s.FindCondition(inst.Status.Conditions, k8s.Ready)
dbInstanceCond := k8s.FindCondition(inst.Status.Conditions, k8s.DatabaseInstanceReady)
log.Info("reconciling database instance: ", "instanceReadyCond", instanceReadyCond, "dbInstanceCond", dbInstanceCond)
// reconcile database only when instance is ready, but requeue.
if !k8s.ConditionStatusEquals(instanceReadyCond, v1.ConditionTrue) {
return ctrl.Result{Requeue: true}, nil
}
isImageSeeded, err := r.isImageSeeded(ctx, inst, log)
if err != nil {
log.Error(err, "unable to determine image type")
return ctrl.Result{}, err
}
if dbInstanceCond == nil {
if inst.Spec.Restore != nil {
log.Info("Skip bootstrap CDB database, waiting to be restored")
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, k8s.RestorePending, "Awaiting restore CDB")
} else if !isImageSeeded {
log.Info("Unseeded image used, waiting to be created")
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, k8s.CreatePending, "Awaiting create CDB")
} else {
log.Info("Seeded image used, waiting to be bootstrapped")
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, k8s.BootstrapPending, "Awaiting bootstrap CDB")
}
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, inst)
}
// Check for timeout
if !k8s.ConditionStatusEquals(dbInstanceCond, v1.ConditionTrue) {
elapsed := k8s.ElapsedTimeFromLastTransitionTime(dbInstanceCond, time.Second)
createDatabaseInstanceTimeout := DatabaseInstanceReadyTimeoutSeeded
if !isImageSeeded {
createDatabaseInstanceTimeout = DatabaseInstanceReadyTimeoutUnseeded
}
if elapsed < createDatabaseInstanceTimeout {
log.Info(fmt.Sprintf("database instance creation in progress for %v", elapsed))
} else {
log.Info(fmt.Sprintf("database instance creation timed out. Elapsed Time: %v", elapsed))
if !strings.Contains(dbInstanceCond.Message, "Warning") { // so that we would create only one database instance timeout event
r.Recorder.Eventf(inst, corev1.EventTypeWarning, k8s.DatabaseInstanceTimeout, "DatabaseInstance has been in progress for over %v, please try delete and recreate.", createDatabaseInstanceTimeout)
}
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, dbInstanceCond.Reason, "Warning: db instance is taking too long to start up - please try delete and recreate")
return ctrl.Result{}, nil
}
}
switch dbInstanceCond.Reason {
case k8s.CreatePending:
// Launch the CreateCDB LRO
req := &controllers.CreateCDBRequest{
Sid: inst.Spec.CDBName,
DbUniqueName: inst.Spec.DBUniqueName,
DbDomain: controllers.GetDBDomain(inst),
CharacterSet: inst.Spec.CharacterSet,
MemoryPercent: int32(inst.Spec.MemoryPercent),
//DBCA expects the parameters in the following string array format
// ["key1=val1", "key2=val2","key3=val3"]
AdditionalParams: mapsToStringArray(inst.Spec.Parameters),
LroInput: &controllers.LROInput{OperationId: lroCreateCDBOperationID(*inst)},
}
_, err = controllers.CreateCDB(ctx, r, r.DatabaseClientFactory, inst.GetNamespace(), inst.GetName(), *req)
if err != nil {
if !controllers.IsAlreadyExistsError(err) {
log.Error(err, "CreateCDB failed")
return ctrl.Result{}, err
}
} else {
log.Info("CreateCDB started")
}
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, k8s.CreateInProgress, "Database creation in progress")
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, inst)
case k8s.CreateInProgress:
id := lroCreateCDBOperationID(*inst)
done, err := controllers.IsLROOperationDone(ctx, r.DatabaseClientFactory, r.Client, id, inst.GetNamespace(), inst.GetName())
if !done {
log.Info("CreateCDB still in progress, waiting")
return ctrl.Result{RequeueAfter: 15 * time.Second}, nil
}
controllers.DeleteLROOperation(ctx, r.DatabaseClientFactory, r.Client, id, inst.Namespace, inst.Name)
if err != nil {
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, k8s.CreateFailed, "CreateCDB LRO returned error")
log.Error(err, "CreateCDB LRO returned error")
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, inst)
}
log.Info("CreateCDB done successfully")
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, k8s.BootstrapPending, "")
// Reconcile again
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, inst)
case k8s.BootstrapPending:
// Launch the BootstrapDatabase LRO
bootstrapMode := controllers.BootstrapDatabaseRequest_ProvisionUnseeded
if isImageSeeded {
bootstrapMode = controllers.BootstrapDatabaseRequest_ProvisionSeeded
}
req := &controllers.BootstrapDatabaseRequest{
CdbName: inst.Spec.CDBName,
DbUniqueName: inst.Spec.DBUniqueName,
Dbdomain: controllers.GetDBDomain(inst),
Mode: bootstrapMode,
LroInput: &controllers.LROInput{OperationId: lroBootstrapCDBOperationID(*inst)},
}
lro, err := controllers.BootstrapDatabase(ctx, r, r.DatabaseClientFactory, inst.Namespace, inst.Name, *req)
if err != nil {
if !controllers.IsAlreadyExistsError(err) {
log.Error(err, "BootstrapDatabase failed")
return ctrl.Result{}, err
}
} else if lro.GetDone() {
// handle synchronous version of BootstrapDatabase
r.Log.Info("encountered synchronous version of BootstrapDatabase")
r.Log.Info("BootstrapDatabase DONE")
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, k8s.ReconcileServices, "Services starting")
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, inst)
}
log.Info("BootstrapDatabase started")
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, k8s.BootstrapInProgress, "Database bootstrap in progress")
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, inst)
case k8s.BootstrapInProgress:
id := lroBootstrapCDBOperationID(*inst)
done, err := controllers.IsLROOperationDone(ctx, r.DatabaseClientFactory, r.Client, id, inst.GetNamespace(), inst.GetName())
if !done {
log.Info("BootstrapDatabase still in progress, waiting")
return ctrl.Result{RequeueAfter: 15 * time.Second}, nil
}
controllers.DeleteLROOperation(ctx, r.DatabaseClientFactory, r.Client, id, inst.Namespace, inst.Name)
if err != nil {
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, k8s.CreateFailed, "BootstrapDatabase LRO returned error")
log.Error(err, "BootstrapDatabase LRO returned error")
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, inst)
}
log.Info("BootstrapDatabase done successfully")
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionFalse, k8s.ReconcileServices, "Services starting")
// Reconcile again
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, inst)
case k8s.ReconcileServices:
res, err := r.reconcileMonitoring(ctx, inst, log, images)
if err == nil && res.RequeueAfter == 0 {
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionTrue, k8s.CreateComplete, "")
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, inst)
}
return res, err
case k8s.RestorePending:
if k8s.ConditionReasonEquals(instanceReadyCond, k8s.RestoreComplete) {
k8s.InstanceUpsertCondition(&inst.Status, k8s.DatabaseInstanceReady, v1.ConditionTrue, k8s.CreateComplete, "")
return ctrl.Result{Requeue: true}, r.Status().Update(ctx, inst)
}
default:
r.Log.Info("reconcileDatabaseInstance: no action needed, proceed with main reconciliation")
}
return ctrl.Result{}, nil
}