diff --git a/controllers/credentials_secret.go b/controllers/credentials_secret.go index 4c663272..684d152d 100644 --- a/controllers/credentials_secret.go +++ b/controllers/credentials_secret.go @@ -1,9 +1,11 @@ package controllers import ( + "fmt" "github.com/digitalocean/godo" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "net/url" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -32,8 +34,8 @@ func credentialsSecretForDefaultDBUser(owner client.Object, db *godo.Database) * return secret } -func credentialsSecretForDBUser(owner client.Object, user *godo.DatabaseUser) *corev1.Secret { - return &corev1.Secret{ +func credentialsSecretForDBUser(db *godo.Database, owner client.Object, user *godo.DatabaseUser) (*corev1.Secret, error) { + secret := &corev1.Secret{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "Secret", @@ -45,7 +47,25 @@ func credentialsSecretForDBUser(owner client.Object, user *godo.DatabaseUser) *c StringData: map[string]string{ "username": user.Name, "password": user.Password, - // TODO(awg): Construct uri and private_uri from DB info. }, } + if db.Connection != nil { + dbUri, err := url.Parse(db.Connection.URI) + if err != nil { + return nil, fmt.Errorf("unable to parse connection uri: %s", err) + } + dbUri.User = url.UserPassword(user.Name, user.Password) + secret.StringData["uri"] = dbUri.String() + } + + if db.PrivateConnection != nil { + dbPrivateUri, err := url.Parse(db.PrivateConnection.URI) + if err != nil { + return nil, fmt.Errorf("unable to parse private connection uri: %s", err) + } + dbPrivateUri.User = url.UserPassword(user.Name, user.Password) + secret.StringData["private_uri"] = dbPrivateUri.String() + } + + return secret, nil } diff --git a/controllers/databaseuser_controller.go b/controllers/databaseuser_controller.go index dae3f34a..2c4adbf4 100644 --- a/controllers/databaseuser_controller.go +++ b/controllers/databaseuser_controller.go @@ -167,6 +167,11 @@ func (r *DatabaseUserReconciler) reconcileDBUser(ctx context.Context, clusterUUI "user_name", user.Spec.Username, ) + db, resp, err := r.GodoClient.Databases.Get(ctx, clusterUUID) + if err != nil { + return ctrl.Result{}, fmt.Errorf("checking for existing DB Cluster: %v", err) + } + // The validating webhook checks that the user doesn't already exist, so we // assume that if we find it to exist now we created it. If the user was // created between validation passing and getting here, we could assume @@ -193,7 +198,7 @@ func (r *DatabaseUserReconciler) reconcileDBUser(ctx context.Context, clusterUUI controllerutil.AddFinalizer(user, finalizerName) user.Status.Role = dbUser.Role - err = r.ensureOwnedObjects(ctx, user, dbUser) + err = r.ensureOwnedObjects(ctx, db, user, dbUser) if err != nil { ll.Error(err, "unable to ensure user-related objects") return ctrl.Result{}, fmt.Errorf("ensuring user-related objects: %v", err) @@ -202,7 +207,7 @@ func (r *DatabaseUserReconciler) reconcileDBUser(ctx context.Context, clusterUUI return ctrl.Result{RequeueAfter: 5 * time.Minute}, nil } -func (r *DatabaseUserReconciler) ensureOwnedObjects(ctx context.Context, user *v1alpha1.DatabaseUser, dbUser *godo.DatabaseUser) error { +func (r *DatabaseUserReconciler) ensureOwnedObjects(ctx context.Context, db *godo.Database, user *v1alpha1.DatabaseUser, dbUser *godo.DatabaseUser) error { // For some database engines the password is not returned when fetching a // user, only on initial creation. Avoid creating or updating the user // credentials secret if the password is empty, so we don't clear the @@ -211,7 +216,10 @@ func (r *DatabaseUserReconciler) ensureOwnedObjects(ctx context.Context, user *v return nil } - obj := credentialsSecretForDBUser(user, dbUser) + obj, err := credentialsSecretForDBUser(db, user, dbUser) + if err != nil { + return fmt.Errorf("creating secrett: %s", err) + } controllerutil.SetControllerReference(user, obj, r.Scheme) if err := r.Patch(ctx, obj, client.Apply, client.ForceOwnership, client.FieldOwner("do-operator")); err != nil { return fmt.Errorf("applying object %s: %s", client.ObjectKeyFromObject(obj), err) diff --git a/controllers/databaseuserreference_controller.go b/controllers/databaseuserreference_controller.go index 03224c7e..da05d679 100644 --- a/controllers/databaseuserreference_controller.go +++ b/controllers/databaseuserreference_controller.go @@ -135,6 +135,11 @@ func (r *DatabaseUserReferenceReconciler) reconcileDBUserReference(ctx context.C "user_name", userRef.Spec.Username, ) + db, _, err := r.GodoClient.Databases.Get(ctx, clusterUUID) + if err != nil { + return ctrl.Result{}, fmt.Errorf("looking up DB cluster: %v", err) + } + // The validating webhook checks that the user exists, so normally this // should work. However, the user could have been deleted in which case // we'll fail and back off in case it gets re-created. @@ -145,7 +150,7 @@ func (r *DatabaseUserReferenceReconciler) reconcileDBUserReference(ctx context.C userRef.Status.Role = dbUser.Role - err = r.ensureOwnedObjects(ctx, userRef, dbUser) + err = r.ensureOwnedObjects(ctx, db, userRef, dbUser) if err != nil { ll.Error(err, "unable to ensure user-related objects") return ctrl.Result{}, fmt.Errorf("ensuring user-related objects: %v", err) @@ -154,8 +159,11 @@ func (r *DatabaseUserReferenceReconciler) reconcileDBUserReference(ctx context.C return ctrl.Result{RequeueAfter: 5 * time.Minute}, nil } -func (r *DatabaseUserReferenceReconciler) ensureOwnedObjects(ctx context.Context, userRef *v1alpha1.DatabaseUserReference, dbUser *godo.DatabaseUser) error { - obj := credentialsSecretForDBUser(userRef, dbUser) +func (r *DatabaseUserReferenceReconciler) ensureOwnedObjects(ctx context.Context, db *godo.Database, userRef *v1alpha1.DatabaseUserReference, dbUser *godo.DatabaseUser) error { + obj, err := credentialsSecretForDBUser(db, userRef, dbUser) + if err != nil { + return fmt.Errorf("creating secrett: %s", err) + } controllerutil.SetControllerReference(userRef, obj, r.Scheme) if err := r.Patch(ctx, obj, client.Apply, client.ForceOwnership, client.FieldOwner("do-operator")); err != nil { return fmt.Errorf("applying object %s: %s", client.ObjectKeyFromObject(obj), err)