Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/bases/mariadb.openstack.org_mariadbaccounts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ spec:
spec:
description: MariaDBAccountSpec defines the desired state of MariaDBAccount
properties:
accountType:
default: User
enum:
- User
- System
type: string
requireTLS:
default: false
description: Account must use TLS to connect to the database
Expand Down
19 changes: 19 additions & 0 deletions api/v1beta1/mariadbaccount_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,19 @@ type MariaDBAccountSpec struct {
// Account must use TLS to connect to the database
// +kubebuilder:default=false
RequireTLS bool `json:"requireTLS"`

// +kubebuilder:validation:Enum=User;System
// +kubebuilder:default=User
AccountType AccountType `json:"accountType,omitempty"`
}

type AccountType string

const (
User AccountType = "User"
System AccountType = "System"
)

// MariaDBAccountStatus defines the observed state of MariaDBAccount
type MariaDBAccountStatus struct {
// Deployment Conditions
Expand Down Expand Up @@ -85,3 +96,11 @@ type MariaDBAccountList struct {
func init() {
SchemeBuilder.Register(&MariaDBAccount{}, &MariaDBAccountList{})
}

func (mariadbAccount MariaDBAccount) IsSystemAccount() bool {
return mariadbAccount.Spec.AccountType == System
}

func (mariadbAccount MariaDBAccount) IsUserAccount() bool {
return mariadbAccount.Spec.AccountType == "" || mariadbAccount.Spec.AccountType == User
}
6 changes: 6 additions & 0 deletions config/crd/bases/mariadb.openstack.org_mariadbaccounts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ spec:
spec:
description: MariaDBAccountSpec defines the desired state of MariaDBAccount
properties:
accountType:
default: User
enum:
- User
- System
type: string
requireTLS:
default: false
description: Account must use TLS to connect to the database
Expand Down
3 changes: 1 addition & 2 deletions controllers/galera_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1058,9 +1058,8 @@ func (r *GaleraReconciler) SetupWithManager(mgr ctrl.Manager) error {
Complete(r)
}

// GetDatabaseObject - returns either a Galera or MariaDB object (and an associated client.Object interface).
// GetDatabaseObject - returns a Galera object.
// used by both MariaDBDatabaseReconciler and MariaDBAccountReconciler
// this will later return only Galera objects, so as a lookup it's part of the galera controller
func GetDatabaseObject(ctx context.Context, clientObj client.Client, name string, namespace string) (*mariadbv1.Galera, error) {
dbGalera := &mariadbv1.Galera{
ObjectMeta: metav1.ObjectMeta{
Expand Down
150 changes: 102 additions & 48 deletions controllers/mariadbaccount_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
util "github.com/openstack-k8s-operators/lib-common/modules/common/util"
databasev1beta1 "github.com/openstack-k8s-operators/mariadb-operator/api/v1beta1"
mariadb "github.com/openstack-k8s-operators/mariadb-operator/pkg/mariadb"
batchv1 "k8s.io/api/batch/v1"
k8s_errors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -113,12 +114,18 @@ func (r *MariaDBAccountReconciler) Reconcile(ctx context.Context, req ctrl.Reque
}()

// initialize conditions used later as Status=Unknown
cl := condition.CreateList(
condition.UnknownCondition(condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage),
condition.UnknownCondition(databasev1beta1.MariaDBServerReadyCondition, condition.InitReason, databasev1beta1.MariaDBServerReadyInitMessage),
condition.UnknownCondition(databasev1beta1.MariaDBDatabaseReadyCondition, condition.InitReason, databasev1beta1.MariaDBDatabaseReadyInitMessage),
condition.UnknownCondition(databasev1beta1.MariaDBAccountReadyCondition, condition.InitReason, databasev1beta1.MariaDBAccountReadyInitMessage),
)
cl := condition.Conditions{
*condition.UnknownCondition(condition.ReadyCondition, condition.InitReason, condition.ReadyInitMessage),
*condition.UnknownCondition(databasev1beta1.MariaDBServerReadyCondition, condition.InitReason, databasev1beta1.MariaDBServerReadyInitMessage),
}
if instance.IsUserAccount() {
// user accounts also need the database ready condition
// the element is being inserted into the list in a specific location
// to preseve expectations of tests suites that are hardcoded to
// expect a specific ordering of Conditions in YAML displays
cl = append(cl, *condition.UnknownCondition(databasev1beta1.MariaDBDatabaseReadyCondition, condition.InitReason, databasev1beta1.MariaDBDatabaseReadyInitMessage))
}
cl = append(cl, *condition.UnknownCondition(databasev1beta1.MariaDBAccountReadyCondition, condition.InitReason, databasev1beta1.MariaDBAccountReadyInitMessage))
instance.Status.Conditions.Init(&cl)

if instance.DeletionTimestamp.IsZero() || isNewInstance { //revive:disable:indent-error-flow
Expand All @@ -134,23 +141,30 @@ func (r *MariaDBAccountReconciler) reconcileCreate(
ctx context.Context, log logr.Logger,
helper *helper.Helper, instance *databasev1beta1.MariaDBAccount) (result ctrl.Result, _err error) {

// get a handle to the current, active MariaDBDatabase.
// if not ready yet, requeue.
mariadbDatabase, result, err := r.getMariaDBDatabaseForCreate(ctx, log, instance)
if mariadbDatabase == nil {
return result, err
var mariadbDatabase *databasev1beta1.MariaDBDatabase
var err error

if instance.IsUserAccount() {
// for User account, get a handle to the current, active MariaDBDatabase.
// if not ready yet, requeue.
mariadbDatabase, result, err = r.getMariaDBDatabaseForCreate(ctx, log, instance)
if mariadbDatabase == nil {
return result, err
}
}

if controllerutil.AddFinalizer(instance, helper.GetFinalizer()) {
// we need to persist this right away
return ctrl.Result{}, nil
}

// MariaDBdatabase exists and we are a create case. ensure finalizers set up
if controllerutil.AddFinalizer(mariadbDatabase, fmt.Sprintf("%s-%s", helper.GetFinalizer(), instance.Name)) {
err = r.Update(ctx, mariadbDatabase)
if err != nil {
return ctrl.Result{}, err
if instance.IsUserAccount() {
// MariaDBdatabase exists and we are a create case. ensure finalizers set up
if controllerutil.AddFinalizer(mariadbDatabase, fmt.Sprintf("%s-%s", helper.GetFinalizer(), instance.Name)) {
err = r.Update(ctx, mariadbDatabase)
if err != nil {
return ctrl.Result{}, err
}
}
}

Expand All @@ -174,13 +188,25 @@ func (r *MariaDBAccountReconciler) reconcileCreate(
return result, err
}

log.Info(fmt.Sprintf("Running account create '%s' MariaDBDatabase '%s'",
instance.Name, mariadbDatabase.Spec.Name))
jobDef, err := mariadb.CreateDbAccountJob(
dbGalera, instance, mariadbDatabase.Spec.Name, dbHostname,
dbContainerImage, serviceAccountName, dbGalera.Spec.NodeSelector)
if err != nil {
return ctrl.Result{}, err
var jobDef *batchv1.Job

if instance.IsUserAccount() {
log.Info(fmt.Sprintf("Running account create '%s' MariaDBDatabase '%s'",
instance.Name, mariadbDatabase.Spec.Name))
jobDef, err = mariadb.CreateDbAccountJob(
dbGalera, instance, mariadbDatabase.Spec.Name, dbHostname,
dbContainerImage, serviceAccountName, dbGalera.Spec.NodeSelector)
if err != nil {
return ctrl.Result{}, err
}
} else {
log.Info(fmt.Sprintf("Running system account create '%s'", instance.Name))
jobDef, err = mariadb.CreateDbAccountJob(
dbGalera, instance, "", dbHostname,
dbContainerImage, serviceAccountName, dbGalera.Spec.NodeSelector)
if err != nil {
return ctrl.Result{}, err
}
}

accountCreateHash := instance.Status.Hash[databasev1beta1.AccountCreateHash]
Expand Down Expand Up @@ -228,9 +254,14 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
ctx context.Context, log logr.Logger,
helper *helper.Helper, instance *databasev1beta1.MariaDBAccount) (result ctrl.Result, _err error) {

mariadbDatabase, result, err := r.getMariaDBDatabaseForDelete(ctx, log, helper, instance)
if mariadbDatabase == nil {
return result, err
var mariadbDatabase *databasev1beta1.MariaDBDatabase
var err error

if instance.IsUserAccount() {
mariadbDatabase, result, err = r.getMariaDBDatabaseForDelete(ctx, log, helper, instance)
if mariadbDatabase == nil {
return result, err
}
}

// dont do actual DROP USER until finalizers from downstream controllers
Expand Down Expand Up @@ -259,10 +290,12 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
databasev1beta1.MariaDBAccountReadyForDeleteMessage,
)

instance.Status.Conditions.MarkTrue(
databasev1beta1.MariaDBDatabaseReadyCondition,
databasev1beta1.MariaDBDatabaseReadyMessage,
)
if instance.IsUserAccount() {
instance.Status.Conditions.MarkTrue(
databasev1beta1.MariaDBDatabaseReadyCondition,
databasev1beta1.MariaDBDatabaseReadyMessage,
)
}

// now proceed to do actual work. acquire the Galera instance
// which will lead us to the hostname and container image to target
Expand All @@ -278,20 +311,21 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
// scheme allows multiple MariaDBAccounts to claim the same MariaDBDatabase
// as a dependency) and allows a delete of the MariaDBDatabase to proceed
// assuming no other finalizers
if controllerutil.RemoveFinalizer(mariadbDatabase, fmt.Sprintf("%s-%s", helper.GetFinalizer(), instance.Name)) {
err = r.Update(ctx, mariadbDatabase)
if instance.IsUserAccount() {
if controllerutil.RemoveFinalizer(mariadbDatabase, fmt.Sprintf("%s-%s", helper.GetFinalizer(), instance.Name)) {
err = r.Update(ctx, mariadbDatabase)

if err != nil && !k8s_errors.IsNotFound(err) {
return ctrl.Result{}, err
if err != nil && !k8s_errors.IsNotFound(err) {
return ctrl.Result{}, err
}
}

}

// remove finalizer "openstack.org/mariadbaccount" from both the
// MariaDBAccount as well as the Secret which is referenced from the
// MariaDBAccount, allowing both to be deleted assuming no other
// finalizers
err = r.removeAccountAndSecretFinalizer(ctx, helper, instance)
err := r.removeAccountAndSecretFinalizer(ctx, helper, instance)
return ctrl.Result{}, err
} else if dbGalera == nil {
return result, err
Expand All @@ -300,13 +334,24 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
dbContainerImage := dbGalera.Spec.ContainerImage
serviceAccountName := dbGalera.RbacResourceName()

log.Info(fmt.Sprintf("Running account delete '%s' MariaDBDatabase '%s'", instance.Name, mariadbDatabase.Spec.Name))
var jobDef *batchv1.Job

jobDef, err := mariadb.DeleteDbAccountJob(dbGalera, instance, mariadbDatabase.Spec.Name, dbHostname, dbContainerImage, serviceAccountName, dbGalera.Spec.NodeSelector)
if err != nil {
return ctrl.Result{}, err
}
if instance.IsUserAccount() {

log.Info(fmt.Sprintf("Running account delete '%s' MariaDBDatabase '%s'", instance.Name, mariadbDatabase.Spec.Name))

jobDef, err = mariadb.DeleteDbAccountJob(dbGalera, instance, mariadbDatabase.Spec.Name, dbHostname, dbContainerImage, serviceAccountName, dbGalera.Spec.NodeSelector)
if err != nil {
return ctrl.Result{}, err
}
} else {
log.Info(fmt.Sprintf("Running system account delete '%s'", instance.Name))

jobDef, err = mariadb.DeleteDbAccountJob(dbGalera, instance, "", dbHostname, dbContainerImage, serviceAccountName, dbGalera.Spec.NodeSelector)
if err != nil {
return ctrl.Result{}, err
}
}
accountDeleteHash := instance.Status.Hash[databasev1beta1.AccountDeleteHash]
accountDeleteJob := job.NewJob(
jobDef,
Expand Down Expand Up @@ -335,18 +380,19 @@ func (r *MariaDBAccountReconciler) reconcileDelete(
// scheme allows multiple MariaDBAccounts to claim the same MariaDBDatabase
// as a dependency) and allows a delete of the MariaDBDatabase to proceed
// assuming no other finalizers
if controllerutil.RemoveFinalizer(mariadbDatabase, fmt.Sprintf("%s-%s", helper.GetFinalizer(), instance.Name)) {
err = r.Update(ctx, mariadbDatabase)
if err != nil {
return ctrl.Result{}, err
if instance.IsUserAccount() {
if controllerutil.RemoveFinalizer(mariadbDatabase, fmt.Sprintf("%s-%s", helper.GetFinalizer(), instance.Name)) {
err = r.Update(ctx, mariadbDatabase)
if err != nil {
return ctrl.Result{}, err
}
}
}

// remove finalizer "openstack.org/mariadbaccount" from
// both the MariaDBAccount as well as the Secret which is referenced
// from the MariaDBAccount, allowing both to be deleted
err = r.removeAccountAndSecretFinalizer(ctx, helper, instance)

return ctrl.Result{}, err
}

Expand Down Expand Up @@ -526,9 +572,17 @@ func (r *MariaDBAccountReconciler) getGaleraForCreateOrDelete(
helper *helper.Helper, instance *databasev1beta1.MariaDBAccount,
mariadbDatabase *databasev1beta1.MariaDBDatabase) (*databasev1beta1.Galera, string, ctrl.Result, error) {

dbName := mariadbDatabase.Labels["dbName"]
var dbGalera *databasev1beta1.Galera
var err error
var dbName string

dbGalera, err := GetDatabaseObject(ctx, r.Client, dbName, instance.Namespace)
if instance.IsUserAccount() {
dbName = mariadbDatabase.Labels["dbName"]
} else {
// note mariadbDatabase is passed as nil in this case
dbName = instance.Labels["dbName"]
}
dbGalera, err = GetDatabaseObject(ctx, r.Client, dbName, instance.Namespace)

if err != nil {
log.Error(err, "Error retrieving Galera instance")
Expand Down
7 changes: 5 additions & 2 deletions templates/account.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ MYSQL_REMOTE_HOST={{.DatabaseHostname}} source /var/lib/operator-scripts/mysql_r

export DatabasePassword=${DatabasePassword:?"Please specify a DatabasePassword variable."}

mysql -h {{.DatabaseHostname}} -u {{.DatabaseAdminUsername}} -P 3306 -e "GRANT ALL PRIVILEGES ON {{.DatabaseName}}.* TO '{{.UserName}}'@'localhost' IDENTIFIED BY '$DatabasePassword'{{.RequireTLS}};GRANT ALL PRIVILEGES ON {{.DatabaseName}}.* TO '{{.UserName}}'@'%' IDENTIFIED BY '$DatabasePassword'{{.RequireTLS}};"

if [ -n "{{.DatabaseName}}" ]; then
mysql -h {{.DatabaseHostname}} -u {{.DatabaseAdminUsername}} -P 3306 -e "GRANT ALL PRIVILEGES ON {{.DatabaseName}}.* TO '{{.UserName}}'@'localhost' IDENTIFIED BY '$DatabasePassword'{{.RequireTLS}};GRANT ALL PRIVILEGES ON {{.DatabaseName}}.* TO '{{.UserName}}'@'%' IDENTIFIED BY '$DatabasePassword'{{.RequireTLS}};"
else
mysql -h {{.DatabaseHostname}} -u {{.DatabaseAdminUsername}} -P 3306 -e "GRANT ALL PRIVILEGES ON *.* TO '{{.UserName}}'@'localhost' IDENTIFIED BY '$DatabasePassword'{{.RequireTLS}};GRANT ALL PRIVILEGES ON *.* TO '{{.UserName}}'@'%' IDENTIFIED BY '$DatabasePassword'{{.RequireTLS}};"
fi

# search for the account. not using SHOW CREATE USER to avoid displaying
# password hash
Expand Down
42 changes: 42 additions & 0 deletions tests/chainsaw/common/system-account-assert.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
apiVersion: mariadb.openstack.org/v1beta1
kind: MariaDBAccount
metadata:
labels:
dbName: openstack
name: chainsawdb-some-system-db-account
status:
conditions:
- message: Setup complete
reason: Ready
status: "True"
type: Ready
- message: MariaDBAccount creation complete
reason: Ready
status: "True"
type: MariaDBAccountReady
- message: MariaDB / Galera server ready
reason: Ready
status: "True"
type: MariaDBServerReady
---
apiVersion: v1
data:
DatabasePassword: ZGJzZWNyZXQx
kind: Secret
metadata:
name: some-system-db-secret
# ensure finalizer was added
finalizers:
- openstack.org/mariadbaccount
type: Opaque
---
apiVersion: batch/v1
kind: Job
metadata:
name: systemuser-account-create
spec:
template:
spec: {}
status:
succeeded: 1
7 changes: 7 additions & 0 deletions tests/chainsaw/common/system-account-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
data:
DatabasePassword: ZGJzZWNyZXQx
kind: Secret
metadata:
name: some-system-db-secret
type: Opaque
10 changes: 10 additions & 0 deletions tests/chainsaw/common/system-account.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: mariadb.openstack.org/v1beta1
kind: MariaDBAccount
metadata:
labels:
dbName: openstack
name: chainsawdb-some-system-db-account
spec:
userName: systemuser
secret: some-system-db-secret
accountType: System
Loading