Skip to content

Commit

Permalink
add finalizer to mysql_controller (#168)
Browse files Browse the repository at this point in the history
  • Loading branch information
nakamasato authored Mar 27, 2023
1 parent 42aa8fa commit 83a018d
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 9 deletions.
27 changes: 27 additions & 0 deletions controllers/mysql_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,20 @@ package controllers
import (
"context"
"fmt"
"time"

"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/log"

mysqlv1alpha1 "github.com/nakamasato/mysql-operator/api/v1alpha1"
)

const mysqlFinalizer = "mysql.nakamasato.com/finalizer"

// MySQLReconciler reconciles a MySQL object
type MySQLReconciler struct {
client.Client
Expand Down Expand Up @@ -64,6 +68,13 @@ func (r *MySQLReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
log.Error(err, "[FetchMySQL] Failed to get MySQL")
return ctrl.Result{}, err
}
// Add a finalizer if not exists
if controllerutil.AddFinalizer(mysql, mysqlFinalizer) {
if err := r.Update(ctx, mysql); err != nil {
log.Error(err, "Failed to update MySQL after adding finalizer")
return ctrl.Result{}, err
}
}

// Get referenced number
referencedNum, err := r.countReferencesByMySQLUser(ctx, mysql)
Expand All @@ -84,6 +95,18 @@ func (r *MySQLReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl
log.Info(fmt.Sprintf("[Status] updated with userCount=%d\n", referencedNum))
}

if !mysql.GetDeletionTimestamp().IsZero() && controllerutil.ContainsFinalizer(mysql, mysqlFinalizer) {
if r.finalizeMysql(ctx, mysql) {
if controllerutil.RemoveFinalizer(mysql, mysqlFinalizer) {
if err := r.Update(ctx, mysql); err != nil {
return ctrl.Result{}, err
}
}
} else {
log.Info("Could not complete finalizer. waiting another 5 seconds")
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
}
}
return ctrl.Result{}, nil
}

Expand All @@ -106,3 +129,7 @@ func (r *MySQLReconciler) countReferencesByMySQLUser(ctx context.Context, mysql
}
return len(mysqlUserList.Items), nil
}

func (r *MySQLReconciler) finalizeMysql(ctx context.Context, mysql *mysqlv1alpha1.MySQL) bool {
return mysql.Status.UserCount == 0
}
16 changes: 16 additions & 0 deletions controllers/mysql_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

mysqlv1alpha1 "github.com/nakamasato/mysql-operator/api/v1alpha1"
)
Expand Down Expand Up @@ -95,6 +96,21 @@ var _ = Describe("MySQL controller", func() {

checkMySQLUserCount(ctx, int32(0))
})

It("Should have finalizer", func() {
By("By creating a new MySQLUser")
mysqlUser = newMySQLUser(APIVersion, Namespace, MySQLUserName, MySQLName)
addOwnerReferenceToMySQL(mysqlUser, mysql)
Expect(k8sClient.Create(ctx, mysqlUser)).Should(Succeed())

Eventually(func() bool {
err := k8sClient.Get(ctx, client.ObjectKey{Namespace: Namespace, Name: MySQLName}, mysql)
if err != nil {
return false
}
return controllerutil.ContainsFinalizer(mysql, mysqlFinalizer)
}).Should(BeTrue())
})
})
})

Expand Down
15 changes: 6 additions & 9 deletions controllers/mysqluser_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,25 +143,22 @@ func (r *MySQLUserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
log.Error(serr, "Failed to update mysqluser status", "mysqlUser", mysqlUser.Name)
return ctrl.Result{RequeueAfter: time.Second}, nil
}
return ctrl.Result{RequeueAfter: time.Second}, nil // requeue after 5 second
return ctrl.Result{RequeueAfter: time.Second}, nil // requeue after 1 second
}
log.Info("[MySQLClient] Successfully connected")
defer mysqlClient.Close()

// Finalize if DeletionTimestamp exists
isMysqlUserMarkedToBeDeleted := mysqlUser.GetDeletionTimestamp() != nil
log.Info("isMysqlUserMarkedToBeDeleted", "isMysqlUserMarkedToBeDeleted", isMysqlUserMarkedToBeDeleted)
if isMysqlUserMarkedToBeDeleted {
if !mysqlUser.GetDeletionTimestamp().IsZero() {
log.Info("isMysqlUserMarkedToBeDeleted is true")
if controllerutil.ContainsFinalizer(mysqlUser, mysqlUserFinalizer) {
log.Info("ContainsFinalizer is true")
// Run finalization logic for mysqlUserFinalizer. If the
// finalization logic fails, don't remove the finalizer so
// that we can retry during the next reconciliation.
if err := r.finalizeMySQLUser(ctx, mysqlUser, mysql); err != nil {
log.Info("finalizeMySQLUser err")
// return ctrl.Result{}, err
return ctrl.Result{}, err // requeue
log.Error(err, "Failed to complete finalizeMySQLUser")
return ctrl.Result{}, err
}
log.Info("finalizeMySQLUser completed")
// Remove mysqlUserFinalizer. Once all finalizers have been
Expand All @@ -172,8 +169,8 @@ func (r *MySQLUserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
err := r.Update(ctx, mysqlUser)
log.Info("Update")
if err != nil {
log.Info("Update err")
return ctrl.Result{}, err // requeue
log.Error(err, "Failed to update mysqlUser")
return ctrl.Result{}, err
}
log.Info("Update completed")
}
Expand Down
27 changes: 27 additions & 0 deletions controllers/mysqluser_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
. "github.com/onsi/ginkgo/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -99,6 +100,32 @@ var _ = Describe("MySQLUser controller", func() {
return mysqlUser.Status.Reason
}).Should(Equal(mysqlUserReasonCompleted))
})

It("Should have finalizer", func() {
By("By creating a new MySQL")
mysql = &mysqlv1alpha1.MySQL{
TypeMeta: metav1.TypeMeta{APIVersion: APIVersion, Kind: "MySQL"},
ObjectMeta: metav1.ObjectMeta{Name: MySQLName, Namespace: Namespace},
Spec: mysqlv1alpha1.MySQLSpec{Host: "localhost", AdminUser: "root", AdminPassword: "password"},
}
Expect(k8sClient.Create(ctx, mysql)).Should(Succeed())
By("By creating a new MySQLUser")
mysqlUser = &mysqlv1alpha1.MySQLUser{
TypeMeta: metav1.TypeMeta{APIVersion: APIVersion, Kind: "MySQLUser"},
ObjectMeta: metav1.ObjectMeta{Namespace: Namespace, Name: MySQLUserName},
Spec: mysqlv1alpha1.MySQLUserSpec{MysqlName: MySQLName},
Status: mysqlv1alpha1.MySQLUserStatus{},
}
Expect(k8sClient.Create(ctx, mysqlUser)).Should(Succeed())

Eventually(func() bool {
err := k8sClient.Get(ctx, client.ObjectKey{Namespace: Namespace, Name: MySQLUserName}, mysqlUser)
if err != nil {
return false
}
return controllerutil.ContainsFinalizer(mysqlUser, mysqlUserFinalizer)
}).Should(BeTrue())
})
})

When("Deleting a MySQLUser", func() {
Expand Down

0 comments on commit 83a018d

Please sign in to comment.