in oracle/controllers/databasecontroller/database_controller.go [171:289]
func (r *DatabaseReconciler) ReconcileDatabaseCreation(ctx context.Context, req ctrl.Request, log logr.Logger) (ctrl.Result, error) {
log.Info("reconciling database")
var db v1alpha1.Database
if err := r.Get(ctx, req.NamespacedName, &db); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
if err := validateSpec(&db); err != nil {
return ctrl.Result{}, r.handlePreflightCheckError(ctx, &db, err)
}
// Find an Instance resource that the Database belongs to.
var inst v1alpha1.Instance
if err := r.Get(ctx, types.NamespacedName{Namespace: req.Namespace, Name: db.Spec.Instance}, &inst); err != nil {
return ctrl.Result{}, r.handlePreflightCheckError(ctx, &db, fmt.Errorf("failed to find instance %q for database %q", db.Spec.Instance, db.Name))
}
log.Info("using the following instance to create a new database(PDB)", "db.Spec.Instance", db.Spec.Instance, "inst", inst)
DBDomain := controllers.GetDBDomain(&inst)
// Find a pod running a database container.
pods, err := r.findPod(ctx, req.Namespace, db.Spec.Instance)
if err != nil {
return ctrl.Result{}, r.handlePreflightCheckError(ctx, &db, fmt.Errorf("failed to find a pod"))
}
log.V(2).Info("found a pod", "pods", pods)
if len(pods.Items) != 1 {
return ctrl.Result{}, r.handlePreflightCheckError(ctx, &db, fmt.Errorf("expected 1 pod, found %d", len(pods.Items)))
}
// Find a database container within that pod.
if _, err := findContainer(pods.Items[0], controllers.DatabaseContainerName); err != nil {
log.Error(err, "reconciling database - failed to find a database container")
return ctrl.Result{}, err
}
log.V(1).Info("a database container identified")
// CDBName is specified in Instance specs
cdbName := inst.Spec.CDBName
istatus, err := CheckStatusInstanceFunc(ctx, r, r.DatabaseClientFactory, db.Spec.Instance, cdbName, inst.Namespace, "", DBDomain, log)
if err != nil {
log.Error(err, "preflight check failed", "check the database instance status", "failed")
return ctrl.Result{}, err
}
if istatus != controllers.StatusReady {
return ctrl.Result{}, r.handlePreflightCheckError(ctx, &db, fmt.Errorf("database instance doesn't appear to be ready yet"))
}
log.Info("preflight check: database instance is ready")
// Confirm that an external LB is ready.
lbSvc := &corev1.Service{}
if err := r.Get(ctx, types.NamespacedName{Name: fmt.Sprintf(controllers.SvcName, db.Spec.Instance), Namespace: req.NamespacedName.Namespace}, lbSvc); err != nil {
return ctrl.Result{}, err
}
if len(lbSvc.Status.LoadBalancer.Ingress) == 0 && !skipLBCheckForTest {
return ctrl.Result{}, fmt.Errorf("preflight check: createDatabase: external LB is NOT ready")
}
log.Info("preflight check: createDatabase external LB service is ready", "svcName", lbSvc.Name)
// Add finalizer to clean up the underlying PDB in case of deletion.
if !controllerutil.ContainsFinalizer(&db, controllers.FinalizerName) {
log.Info("adding a finalizer to the Database object.")
controllerutil.AddFinalizer(&db, controllers.FinalizerName)
if err := r.Update(ctx, &db); err != nil {
return ctrl.Result{}, err
}
}
alreadyExists, err := NewDatabase(ctx, r, &db, DBDomain, cdbName, log)
if err != nil {
return ctrl.Result{}, err
}
r.Recorder.Eventf(&db, corev1.EventTypeNormal, k8s.CreatedDatabase, fmt.Sprintf("Created new database %q", db.Spec.Name))
db.Status.Phase = commonv1alpha1.DatabaseReady
db.Status.Conditions = k8s.Upsert(db.Status.Conditions, k8s.Ready, v1.ConditionTrue, k8s.CreateComplete, "")
if err := r.Status().Update(ctx, &db); err != nil {
return ctrl.Result{}, err
}
if alreadyExists {
if err := SyncUsers(ctx, r, &db, cdbName, log); err != nil {
log.Error(err, "failed to sync database")
return ctrl.Result{}, err
}
return ctrl.Result{}, nil
}
log.V(1).Info("[DEBUG] create users", "Database", db.Spec.Name, "Users/Privs", db.Spec.Users)
if err := NewUsers(ctx, r, &db, DBDomain, cdbName, log); err != nil {
return ctrl.Result{}, err
}
// check DB name against existing ones to decide whether this is a new DB
if !util.Contains(inst.Status.DatabaseNames, db.Spec.Name) {
log.Info("found a new DB", "dbName", db.Spec.Name)
inst.Status.DatabaseNames = append(inst.Status.DatabaseNames, db.Spec.Name)
} else {
log.V(1).Info("not a new DB, skipping the update", "dbName", db.Spec.Name)
}
log.Info("instance status", "conditions", inst.Status.Conditions, "endpoint", inst.Status.Endpoint,
"url", inst.Status.URL, "databases", inst.Status.DatabaseNames)
if err := r.Status().Update(ctx, &inst); err != nil {
log.Error(err, "failed to update an Instance status")
return ctrl.Result{}, err
}
log.Info("reconciling database: DONE")
return ctrl.Result{}, nil
}