Files
kamaji/internal/resources/sql_setup.go
2022-08-26 22:05:59 +02:00

247 lines
6.8 KiB
Go

// Copyright 2022 Clastix Labs
// SPDX-License-Identifier: Apache-2.0
package resources
import (
"context"
"fmt"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1"
"github.com/clastix/kamaji/internal/sql"
)
type sqlSetupResource struct {
schema string
user string
password string
}
type SQLSetup struct {
resource sqlSetupResource
Client client.Client
DBConnection sql.DBConnection
Name string
Driver string
}
func (r *SQLSetup) ShouldStatusBeUpdated(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) bool {
if tenantControlPlane.Status.Storage.Kine == nil {
return true
}
return tenantControlPlane.Status.Storage.Kine.Driver != r.Driver &&
tenantControlPlane.Status.Storage.Kine.Setup.Checksum != tenantControlPlane.Status.Storage.Kine.Config.Checksum
}
func (r *SQLSetup) ShouldCleanup(_ *kamajiv1alpha1.TenantControlPlane) bool {
return false
}
func (r *SQLSetup) CleanUp(context.Context, *kamajiv1alpha1.TenantControlPlane) (bool, error) {
return false, nil
}
func (r *SQLSetup) Define(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
secret := &corev1.Secret{}
namespacedName := types.NamespacedName{
Namespace: tenantControlPlane.GetNamespace(),
Name: tenantControlPlane.Status.Storage.Kine.Config.SecretName,
}
if err := r.Client.Get(ctx, namespacedName, secret); err != nil {
return err
}
r.resource = sqlSetupResource{
schema: string(secret.Data["DB_SCHEMA"]),
user: string(secret.Data["DB_USER"]),
password: string(secret.Data["DB_PASSWORD"]),
}
return nil
}
func (r *SQLSetup) GetClient() client.Client {
return r.Client
}
func (r *SQLSetup) CreateOrUpdate(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error) {
if tenantControlPlane.Status.Storage.Kine.Setup.Checksum != "" &&
tenantControlPlane.Status.Storage.Kine.Setup.Checksum != tenantControlPlane.Status.Storage.Kine.Config.Checksum {
if err := r.Delete(ctx, tenantControlPlane); err != nil {
return controllerutil.OperationResultNone, err
}
return controllerutil.OperationResultUpdated, nil
}
reconcilationResult := controllerutil.OperationResultNone
var operationResult controllerutil.OperationResult
var err error
operationResult, err = r.createDB(ctx, tenantControlPlane)
if err != nil {
return reconcilationResult, err
}
reconcilationResult = updateOperationResult(reconcilationResult, operationResult)
operationResult, err = r.createUser(ctx, tenantControlPlane)
if err != nil {
return reconcilationResult, err
}
reconcilationResult = updateOperationResult(reconcilationResult, operationResult)
operationResult, err = r.createGrantPrivileges(ctx, tenantControlPlane)
if err != nil {
return reconcilationResult, err
}
reconcilationResult = updateOperationResult(reconcilationResult, operationResult)
return reconcilationResult, nil
}
func (r *SQLSetup) GetName() string {
return r.Name
}
func (r *SQLSetup) Delete(ctx context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
if err := r.Define(ctx, tenantControlPlane); err != nil {
return err
}
if err := r.revokeGrantPrivileges(ctx, tenantControlPlane); err != nil {
return err
}
if err := r.deleteDB(ctx, tenantControlPlane); err != nil {
return err
}
if err := r.deleteUser(ctx, tenantControlPlane); err != nil {
return err
}
return nil
}
func (r *SQLSetup) UpdateTenantControlPlaneStatus(_ context.Context, tenantControlPlane *kamajiv1alpha1.TenantControlPlane) error {
if tenantControlPlane.Status.Storage.Kine == nil {
return fmt.Errorf("sql configuration is not ready")
}
tenantControlPlane.Status.Storage.Kine.Setup.Schema = r.resource.schema
tenantControlPlane.Status.Storage.Kine.Setup.User = r.resource.user
tenantControlPlane.Status.Storage.Kine.Setup.LastUpdate = metav1.Now()
tenantControlPlane.Status.Storage.Kine.Setup.Checksum = tenantControlPlane.Status.Storage.Kine.Config.Checksum
return nil
}
func (r *SQLSetup) createDB(ctx context.Context, _ *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error) {
exists, err := r.DBConnection.DBExists(ctx, r.resource.schema)
if err != nil {
return controllerutil.OperationResultNone, err
}
if exists {
return controllerutil.OperationResultNone, nil
}
if err := r.DBConnection.CreateDB(ctx, r.resource.schema); err != nil {
return controllerutil.OperationResultNone, err
}
return controllerutil.OperationResultCreated, nil
}
func (r *SQLSetup) deleteDB(ctx context.Context, _ *kamajiv1alpha1.TenantControlPlane) error {
exists, err := r.DBConnection.DBExists(ctx, r.resource.schema)
if err != nil {
return err
}
if !exists {
return nil
}
if err := r.DBConnection.DeleteDB(ctx, r.resource.schema); err != nil {
return err
}
return nil
}
func (r *SQLSetup) createUser(ctx context.Context, _ *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error) {
exists, err := r.DBConnection.UserExists(ctx, r.resource.user)
if err != nil {
return controllerutil.OperationResultNone, err
}
if exists {
return controllerutil.OperationResultNone, nil
}
if err := r.DBConnection.CreateUser(ctx, r.resource.user, r.resource.password); err != nil {
return controllerutil.OperationResultNone, err
}
return controllerutil.OperationResultCreated, nil
}
func (r *SQLSetup) deleteUser(ctx context.Context, _ *kamajiv1alpha1.TenantControlPlane) error {
exists, err := r.DBConnection.UserExists(ctx, r.resource.user)
if err != nil {
return err
}
if !exists {
return nil
}
if err := r.DBConnection.DeleteUser(ctx, r.resource.user); err != nil {
return err
}
return nil
}
func (r *SQLSetup) createGrantPrivileges(ctx context.Context, _ *kamajiv1alpha1.TenantControlPlane) (controllerutil.OperationResult, error) {
exists, err := r.DBConnection.GrantPrivilegesExists(ctx, r.resource.user, r.resource.schema)
if err != nil {
return controllerutil.OperationResultNone, err
}
if exists {
return controllerutil.OperationResultNone, nil
}
if err := r.DBConnection.GrantPrivileges(ctx, r.resource.user, r.resource.schema); err != nil {
return controllerutil.OperationResultNone, err
}
return controllerutil.OperationResultCreated, nil
}
func (r *SQLSetup) revokeGrantPrivileges(ctx context.Context, _ *kamajiv1alpha1.TenantControlPlane) error {
exists, err := r.DBConnection.GrantPrivilegesExists(ctx, r.resource.user, r.resource.schema)
if err != nil {
return err
}
if !exists {
return nil
}
if err := r.DBConnection.RevokePrivileges(ctx, r.resource.user, r.resource.schema); err != nil {
return err
}
return nil
}