mirror of
https://github.com/mariadb-operator/mariadb-operator.git
synced 2025-07-25 01:28:31 +00:00
1072 lines
35 KiB
Go
1072 lines
35 KiB
Go
package controller
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"crypto/sha256"
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"text/template"
|
|
"time"
|
|
|
|
"github.com/hashicorp/go-multierror"
|
|
mariadbv1alpha1 "github.com/mariadb-operator/mariadb-operator/api/v1alpha1"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/builder"
|
|
labels "github.com/mariadb-operator/mariadb-operator/pkg/builder/labels"
|
|
condition "github.com/mariadb-operator/mariadb-operator/pkg/condition"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/auth"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/configmap"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/deployment"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/endpoints"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/galera"
|
|
galeraresources "github.com/mariadb-operator/mariadb-operator/pkg/controller/galera/resources"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/maxscale"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/rbac"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/replication"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/secret"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/service"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/servicemonitor"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/controller/statefulset"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/discovery"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/environment"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/health"
|
|
kadapter "github.com/mariadb-operator/mariadb-operator/pkg/kubernetes/adapter"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/metadata"
|
|
mdbpod "github.com/mariadb-operator/mariadb-operator/pkg/pod"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/predicate"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/refresolver"
|
|
sts "github.com/mariadb-operator/mariadb-operator/pkg/statefulset"
|
|
"github.com/mariadb-operator/mariadb-operator/pkg/watch"
|
|
appsv1 "k8s.io/api/apps/v1"
|
|
corev1 "k8s.io/api/core/v1"
|
|
policyv1 "k8s.io/api/policy/v1"
|
|
rbacv1 "k8s.io/api/rbac/v1"
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
klabels "k8s.io/apimachinery/pkg/labels"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
"k8s.io/apimachinery/pkg/util/intstr"
|
|
"k8s.io/client-go/tools/record"
|
|
"k8s.io/utils/ptr"
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
|
ctrlbuilder "sigs.k8s.io/controller-runtime/pkg/builder"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
"sigs.k8s.io/controller-runtime/pkg/controller"
|
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
)
|
|
|
|
// MariaDBReconciler reconciles a MariaDB object
|
|
type MariaDBReconciler struct {
|
|
client.Client
|
|
Scheme *runtime.Scheme
|
|
Recorder record.EventRecorder
|
|
|
|
Builder *builder.Builder
|
|
RefResolver *refresolver.RefResolver
|
|
ConditionReady *condition.Ready
|
|
Environment *environment.OperatorEnv
|
|
Discovery *discovery.Discovery
|
|
|
|
ConfigMapReconciler *configmap.ConfigMapReconciler
|
|
SecretReconciler *secret.SecretReconciler
|
|
StatefulSetReconciler *statefulset.StatefulSetReconciler
|
|
ServiceReconciler *service.ServiceReconciler
|
|
EndpointsReconciler *endpoints.EndpointsReconciler
|
|
RBACReconciler *rbac.RBACReconciler
|
|
AuthReconciler *auth.AuthReconciler
|
|
DeploymentReconciler *deployment.DeploymentReconciler
|
|
ServiceMonitorReconciler *servicemonitor.ServiceMonitorReconciler
|
|
MaxScaleReconciler *maxscale.MaxScaleReconciler
|
|
|
|
ReplicationReconciler *replication.ReplicationReconciler
|
|
GaleraReconciler *galera.GaleraReconciler
|
|
}
|
|
|
|
type reconcilePhaseMariaDB struct {
|
|
Name string
|
|
Reconcile func(context.Context, *mariadbv1alpha1.MariaDB) (ctrl.Result, error)
|
|
}
|
|
|
|
type patcherMariaDB func(*mariadbv1alpha1.MariaDBStatus) error
|
|
|
|
//+kubebuilder:rbac:groups=k8s.mariadb.com,resources=mariadbs,verbs=get;list;watch;create;update;patch;delete
|
|
//+kubebuilder:rbac:groups=k8s.mariadb.com,resources=mariadbs/status,verbs=get;update;patch
|
|
//+kubebuilder:rbac:groups=k8s.mariadb.com,resources=mariadbs/finalizers,verbs=update
|
|
//+kubebuilder:rbac:groups=k8s.mariadb.com,resources=maxscale;restores;connections;users;grants,verbs=list;watch;create;patch
|
|
//+kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;patch;delete
|
|
//+kubebuilder:rbac:groups="",resources=services,verbs=list;watch;create;patch
|
|
//+kubebuilder:rbac:groups="",resources=secrets,verbs=list;watch;create;patch
|
|
//+kubebuilder:rbac:groups="",resources=endpoints,verbs=create;patch;get;list;watch
|
|
//+kubebuilder:rbac:groups="",resources=endpoints/restricted,verbs=create;patch;get;list;watch
|
|
//+kubebuilder:rbac:groups="",resources=pods,verbs=get;patch;delete
|
|
//+kubebuilder:rbac:groups="",resources=pods/log,verbs=get
|
|
//+kubebuilder:rbac:groups="",resources=persistentvolumeclaims,verbs=list
|
|
//+kubebuilder:rbac:groups="",resources=events,verbs=list;watch;create;patch
|
|
//+kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=list;watch;create;patch
|
|
//+kubebuilder:rbac:groups=apps,resources=statefulsets,verbs=list;watch;create;patch;delete
|
|
//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=list;watch;create;patch
|
|
//+kubebuilder:rbac:groups=batch,resources=jobs,verbs=list;watch;create;patch;delete
|
|
//+kubebuilder:rbac:groups=policy,resources=poddisruptionbudgets,verbs=list;watch;create;patch
|
|
//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles;rolebindings;clusterrolebindings,verbs=list;watch;create;patch
|
|
//+kubebuilder:rbac:groups=authorization.k8s.io,resources=subjectaccessreviews,verbs=create
|
|
//+kubebuilder:rbac:groups=authentication.k8s.io,resources=tokenreviews,verbs=create
|
|
//+kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors,verbs=list;watch;create;patch
|
|
|
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
|
// move the current state of the cluster closer to the desired state.
|
|
func (r *MariaDBReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
|
var mariadb mariadbv1alpha1.MariaDB
|
|
if err := r.Get(ctx, req.NamespacedName, &mariadb); err != nil {
|
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
|
}
|
|
phases := []reconcilePhaseMariaDB{
|
|
{
|
|
Name: "Spec",
|
|
Reconcile: r.setSpecDefaults,
|
|
},
|
|
{
|
|
Name: "Status",
|
|
Reconcile: r.reconcileStatus,
|
|
},
|
|
{
|
|
Name: "Suspend",
|
|
Reconcile: r.reconcileSuspend,
|
|
},
|
|
{
|
|
Name: "Secret",
|
|
Reconcile: r.reconcileSecret,
|
|
},
|
|
{
|
|
Name: "ConfigMap",
|
|
Reconcile: r.reconcileConfigMap,
|
|
},
|
|
{
|
|
Name: "RBAC",
|
|
Reconcile: r.reconcileRBAC,
|
|
},
|
|
{
|
|
Name: "Init",
|
|
Reconcile: r.reconcileInit,
|
|
},
|
|
{
|
|
Name: "Storage",
|
|
Reconcile: r.reconcileStorage,
|
|
},
|
|
{
|
|
Name: "StatefulSet",
|
|
Reconcile: r.reconcileStatefulSet,
|
|
},
|
|
{
|
|
Name: "PodDisruptionBudget",
|
|
Reconcile: r.reconcilePodDisruptionBudget,
|
|
},
|
|
{
|
|
Name: "Service",
|
|
Reconcile: r.reconcileService,
|
|
},
|
|
{
|
|
Name: "Replication",
|
|
Reconcile: r.ReplicationReconciler.Reconcile,
|
|
},
|
|
{
|
|
Name: "Labels",
|
|
Reconcile: r.reconcilePodLabels,
|
|
},
|
|
{
|
|
Name: "Galera",
|
|
Reconcile: r.GaleraReconciler.Reconcile,
|
|
},
|
|
{
|
|
Name: "Update",
|
|
Reconcile: r.reconcileUpdates,
|
|
},
|
|
{
|
|
Name: "Restore",
|
|
Reconcile: r.reconcileRestore,
|
|
},
|
|
{
|
|
Name: "MaxScale",
|
|
Reconcile: r.MaxScaleReconciler.Reconcile,
|
|
},
|
|
{
|
|
Name: "SQL",
|
|
Reconcile: r.reconcileSQL,
|
|
},
|
|
{
|
|
Name: "Metrics",
|
|
Reconcile: r.reconcileMetrics,
|
|
},
|
|
{
|
|
Name: "Connection",
|
|
Reconcile: r.reconcileConnection,
|
|
},
|
|
}
|
|
|
|
for _, p := range phases {
|
|
result, err := p.Reconcile(ctx, &mariadb)
|
|
if err != nil {
|
|
if apierrors.IsNotFound(err) {
|
|
continue
|
|
}
|
|
|
|
var errBundle *multierror.Error
|
|
errBundle = multierror.Append(errBundle, err)
|
|
|
|
msg := fmt.Sprintf("Error reconciling %s: %v", p.Name, err)
|
|
patchErr := r.patchStatus(ctx, &mariadb, func(s *mariadbv1alpha1.MariaDBStatus) error {
|
|
patcher := r.ConditionReady.PatcherFailed(msg)
|
|
patcher(s)
|
|
return nil
|
|
})
|
|
if !apierrors.IsNotFound(patchErr) {
|
|
errBundle = multierror.Append(errBundle, patchErr)
|
|
}
|
|
|
|
if err := errBundle.ErrorOrNil(); err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error reconciling %s: %v", p.Name, err)
|
|
}
|
|
}
|
|
if !result.IsZero() {
|
|
return result, err
|
|
}
|
|
}
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileSecret(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
var secretKeyRefs []mariadbv1alpha1.GeneratedSecretKeyRef
|
|
|
|
if !mariadb.IsRootPasswordEmpty() {
|
|
secretKeyRefs = append(secretKeyRefs, mariadb.Spec.RootPasswordSecretKeyRef)
|
|
}
|
|
if mariadb.Spec.PasswordSecretKeyRef != nil {
|
|
secretKeyRefs = append(secretKeyRefs, *mariadb.Spec.PasswordSecretKeyRef)
|
|
}
|
|
galera := ptr.Deref(mariadb.Spec.Galera, mariadbv1alpha1.Galera{})
|
|
basicAuth := ptr.Deref(galera.Agent.BasicAuth, mariadbv1alpha1.BasicAuth{})
|
|
if galera.Enabled && basicAuth.Enabled && !reflect.ValueOf(galera.Agent.BasicAuth.PasswordSecretKeyRef).IsZero() {
|
|
secretKeyRefs = append(secretKeyRefs, galera.Agent.BasicAuth.PasswordSecretKeyRef)
|
|
}
|
|
|
|
for _, secretKeyRef := range secretKeyRefs {
|
|
req := secret.PasswordRequest{
|
|
Owner: mariadb,
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
Key: types.NamespacedName{
|
|
Name: secretKeyRef.Name,
|
|
Namespace: mariadb.Namespace,
|
|
},
|
|
SecretKey: secretKeyRef.Key,
|
|
Generate: secretKeyRef.Generate,
|
|
}
|
|
_, err := r.SecretReconciler.ReconcilePassword(ctx, req)
|
|
if err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
}
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileConfigMap(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
defaultConfigMapKeyRef := mariadb.DefaultConfigMapKeyRef()
|
|
config, err := defaultConfig(mariadb)
|
|
if err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error getting default config: %v", err)
|
|
}
|
|
|
|
req := configmap.ReconcileRequest{
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
Owner: mariadb,
|
|
Key: types.NamespacedName{
|
|
Name: defaultConfigMapKeyRef.Name,
|
|
Namespace: mariadb.Namespace,
|
|
},
|
|
Data: map[string]string{
|
|
defaultConfigMapKeyRef.Key: config,
|
|
},
|
|
}
|
|
if err := r.ConfigMapReconciler.Reconcile(ctx, &req); err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
|
|
if mariadb.Spec.MyCnf != nil && mariadb.Spec.MyCnfConfigMapKeyRef != nil {
|
|
configMapKeyRef := *mariadb.Spec.MyCnfConfigMapKeyRef
|
|
req := configmap.ReconcileRequest{
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
Owner: mariadb,
|
|
Key: types.NamespacedName{
|
|
Name: configMapKeyRef.Name,
|
|
Namespace: mariadb.Namespace,
|
|
},
|
|
Data: map[string]string{
|
|
configMapKeyRef.Key: *mariadb.Spec.MyCnf,
|
|
},
|
|
}
|
|
if err := r.ConfigMapReconciler.Reconcile(ctx, &req); err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
}
|
|
|
|
if mariadb.Replication().Enabled && ptr.Deref(mariadb.Replication().ProbesEnabled, false) {
|
|
configMapKeyRef := mariadb.ReplConfigMapKeyRef()
|
|
if err := r.ReplicationReconciler.ReconcileProbeConfigMap(ctx, configMapKeyRef, mariadb); err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
}
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileRBAC(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
return ctrl.Result{}, r.RBACReconciler.ReconcileMariadbRBAC(ctx, mariadb)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileInit(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
if mariadb.IsGaleraEnabled() {
|
|
if result, err := r.GaleraReconciler.ReconcileInit(ctx, mariadb); !result.IsZero() || err != nil {
|
|
return result, err
|
|
}
|
|
}
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileStatefulSet(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
key := client.ObjectKeyFromObject(mariadb)
|
|
podAnnotations, err := r.getPodAnnotations(ctx, mariadb)
|
|
if err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error getting Pod annotations: %v", err)
|
|
}
|
|
|
|
desiredSts, err := r.Builder.BuildMariadbStatefulSet(mariadb, key, podAnnotations)
|
|
if err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error building StatefulSet: %v", err)
|
|
}
|
|
shouldUpdate := mariadb.Spec.UpdateStrategy.Type != mariadbv1alpha1.NeverUpdateType
|
|
|
|
return ctrl.Result{}, r.StatefulSetReconciler.ReconcileWithUpdates(ctx, desiredSts, shouldUpdate)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcilePodLabels(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
if mariadb.Status.CurrentPrimaryPodIndex == nil {
|
|
return ctrl.Result{RequeueAfter: 5 * time.Second}, nil
|
|
}
|
|
|
|
podList := corev1.PodList{}
|
|
listOpts := &client.ListOptions{
|
|
LabelSelector: klabels.SelectorFromSet(
|
|
labels.NewLabelsBuilder().
|
|
WithMariaDBSelectorLabels(mariadb).
|
|
Build(),
|
|
),
|
|
Namespace: mariadb.GetNamespace(),
|
|
}
|
|
if err := r.List(ctx, &podList, listOpts); err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error listing Pods: %v", err)
|
|
}
|
|
|
|
for _, pod := range podList.Items {
|
|
var role = "replica"
|
|
|
|
if pod.Status.PodIP == "" || pod.Spec.NodeName == "" {
|
|
continue
|
|
}
|
|
podIndex, err := sts.PodIndex(pod.Name)
|
|
if err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error getting Pod '%s' index: %v", pod.Name, err)
|
|
}
|
|
|
|
if *podIndex == *mariadb.Status.CurrentPrimaryPodIndex {
|
|
role = "primary"
|
|
}
|
|
|
|
p := client.MergeFrom(pod.DeepCopy())
|
|
pod.Labels = labels.NewLabelsBuilder().WithLabels(pod.Labels).WithPodRole(role).Build()
|
|
|
|
if mdbpod.PodReady(&pod) {
|
|
if err := r.Patch(ctx, &pod, p); err != nil {
|
|
if apierrors.IsConflict(err) {
|
|
return ctrl.Result{Requeue: true}, nil
|
|
}
|
|
if apierrors.IsNotFound(err) {
|
|
return ctrl.Result{Requeue: true}, nil
|
|
}
|
|
return ctrl.Result{}, err
|
|
}
|
|
}
|
|
}
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
func (r *MariaDBReconciler) getPodAnnotations(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (map[string]string, error) {
|
|
podAnnotations := make(map[string]string)
|
|
|
|
if mariadb.Spec.MyCnfConfigMapKeyRef != nil {
|
|
config, err := r.RefResolver.ConfigMapKeyRef(ctx, mariadb.Spec.MyCnfConfigMapKeyRef, mariadb.Namespace)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error getting my.cnf from ConfigMap: %v", err)
|
|
}
|
|
podAnnotations[metadata.ConfigAnnotation] = fmt.Sprintf("%x", sha256.Sum256([]byte(config)))
|
|
}
|
|
|
|
return podAnnotations, nil
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcilePodDisruptionBudget(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
if mariadb.IsHAEnabled() && mariadb.Spec.PodDisruptionBudget == nil {
|
|
return ctrl.Result{}, r.reconcileHighAvailabilityPDB(ctx, mariadb)
|
|
}
|
|
return ctrl.Result{}, r.reconcileDefaultPDB(ctx, mariadb)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileService(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
if err := r.reconcileInternalService(ctx, mariadb); err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error reconciling internal Service: %v", err)
|
|
}
|
|
if err := r.reconcileDefaultService(ctx, mariadb); err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error reconciling default Service: %v", err)
|
|
}
|
|
if mariadb.IsHAEnabled() {
|
|
if result, err := r.reconcilePrimaryService(ctx, mariadb); !result.IsZero() || err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
if result, err := r.reconcileSecondaryService(ctx, mariadb); !result.IsZero() || err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
}
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
func shouldReconcileRestore(mdb *mariadbv1alpha1.MariaDB) bool {
|
|
if mdb.IsUpdating() || mdb.IsResizingStorage() || mdb.IsSwitchingPrimary() || mdb.HasGaleraNotReadyCondition() {
|
|
return false
|
|
}
|
|
if mdb.HasRestoredBackup() || mdb.Spec.BootstrapFrom == nil {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileRestore(ctx context.Context, mdb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
if !shouldReconcileRestore(mdb) {
|
|
return ctrl.Result{}, nil
|
|
}
|
|
if mdb.IsRestoringBackup() {
|
|
var existingRestore mariadbv1alpha1.Restore
|
|
if err := r.Get(ctx, mdb.RestoreKey(), &existingRestore); err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
return ctrl.Result{}, r.patchStatus(ctx, mdb, func(status *mariadbv1alpha1.MariaDBStatus) error {
|
|
if existingRestore.IsComplete() {
|
|
if err := r.Delete(ctx, &existingRestore); err != nil {
|
|
return err
|
|
}
|
|
condition.SetRestoredBackup(status)
|
|
} else {
|
|
condition.SetRestoringBackup(status)
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
healthy, err := health.IsStatefulSetHealthy(
|
|
ctx,
|
|
r.Client,
|
|
client.ObjectKeyFromObject(mdb),
|
|
health.WithDesiredReplicas(mdb.Spec.Replicas),
|
|
health.WithPort(mdb.Spec.Port),
|
|
health.WithEndpointPolicy(health.EndpointPolicyAll),
|
|
)
|
|
if err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error checking MariaDB health: %v", err)
|
|
}
|
|
if !healthy {
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
var existingRestore mariadbv1alpha1.Restore
|
|
if err := r.Get(ctx, mdb.RestoreKey(), &existingRestore); err == nil {
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
if err := r.patchStatus(ctx, mdb, func(status *mariadbv1alpha1.MariaDBStatus) error {
|
|
condition.SetRestoringBackup(status)
|
|
return nil
|
|
}); err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error patching status: %v", err)
|
|
}
|
|
|
|
restore, err := r.Builder.BuildRestore(mdb, mdb.RestoreKey())
|
|
if err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error building restore: %v", err)
|
|
}
|
|
return ctrl.Result{}, r.Create(ctx, restore)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileDefaultPDB(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) error {
|
|
if mariadb.Spec.PodDisruptionBudget == nil {
|
|
return nil
|
|
}
|
|
|
|
key := client.ObjectKeyFromObject(mariadb)
|
|
var existingPDB policyv1.PodDisruptionBudget
|
|
if err := r.Get(ctx, key, &existingPDB); err == nil {
|
|
return nil
|
|
}
|
|
|
|
selectorLabels :=
|
|
labels.NewLabelsBuilder().
|
|
WithMariaDBSelectorLabels(mariadb).
|
|
Build()
|
|
opts := builder.PodDisruptionBudgetOpts{
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
Key: key,
|
|
MinAvailable: mariadb.Spec.PodDisruptionBudget.MinAvailable,
|
|
MaxUnavailable: mariadb.Spec.PodDisruptionBudget.MaxUnavailable,
|
|
SelectorLabels: selectorLabels,
|
|
}
|
|
pdb, err := r.Builder.BuildPodDisruptionBudget(opts, mariadb)
|
|
if err != nil {
|
|
return fmt.Errorf("error building PodDisruptionBudget: %v", err)
|
|
}
|
|
return r.Create(ctx, pdb)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileHighAvailabilityPDB(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) error {
|
|
key := client.ObjectKeyFromObject(mariadb)
|
|
var existingPDB policyv1.PodDisruptionBudget
|
|
if err := r.Get(ctx, key, &existingPDB); err == nil {
|
|
return nil
|
|
}
|
|
|
|
selectorLabels :=
|
|
labels.NewLabelsBuilder().
|
|
WithMariaDBSelectorLabels(mariadb).
|
|
Build()
|
|
minAvailable := intstr.FromString("50%")
|
|
opts := builder.PodDisruptionBudgetOpts{
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
Key: key,
|
|
MinAvailable: &minAvailable,
|
|
SelectorLabels: selectorLabels,
|
|
}
|
|
pdb, err := r.Builder.BuildPodDisruptionBudget(opts, mariadb)
|
|
if err != nil {
|
|
return fmt.Errorf("error building PodDisruptionBudget: %v", err)
|
|
}
|
|
return r.Create(ctx, pdb)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileDefaultService(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) error {
|
|
key := client.ObjectKeyFromObject(mariadb)
|
|
ports := []corev1.ServicePort{
|
|
{
|
|
Name: builder.MariadbPortName,
|
|
Port: mariadb.Spec.Port,
|
|
},
|
|
}
|
|
if mariadb.Spec.ServicePorts != nil {
|
|
ports = append(ports, kadapter.ToKubernetesSlice(mariadb.Spec.ServicePorts)...)
|
|
}
|
|
selectorLabels :=
|
|
labels.NewLabelsBuilder().
|
|
WithMariaDBSelectorLabels(mariadb).
|
|
Build()
|
|
opts := builder.ServiceOpts{
|
|
Ports: ports,
|
|
SelectorLabels: selectorLabels,
|
|
ExtraMeta: mariadb.Spec.InheritMetadata,
|
|
}
|
|
if mariadb.Spec.Service != nil {
|
|
opts.ServiceTemplate = *mariadb.Spec.Service
|
|
}
|
|
|
|
desiredSvc, err := r.Builder.BuildService(key, mariadb, opts)
|
|
if err != nil {
|
|
return fmt.Errorf("error building Service: %v", err)
|
|
}
|
|
return r.ServiceReconciler.Reconcile(ctx, desiredSvc)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileInternalService(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) error {
|
|
key := mariadb.InternalServiceKey()
|
|
ports := []corev1.ServicePort{
|
|
{
|
|
Name: builder.MariadbPortName,
|
|
Port: mariadb.Spec.Port,
|
|
},
|
|
}
|
|
if mariadb.Spec.ServicePorts != nil {
|
|
ports = append(ports, kadapter.ToKubernetesSlice(mariadb.Spec.ServicePorts)...)
|
|
}
|
|
if mariadb.IsGaleraEnabled() {
|
|
ports = append(ports, []corev1.ServicePort{
|
|
{
|
|
Name: galeraresources.GaleraClusterPortName,
|
|
Port: galeraresources.GaleraClusterPort,
|
|
},
|
|
{
|
|
Name: galeraresources.GaleraISTPortName,
|
|
Port: galeraresources.GaleraISTPort,
|
|
},
|
|
{
|
|
Name: galeraresources.GaleraSSTPortName,
|
|
Port: galeraresources.GaleraSSTPort,
|
|
},
|
|
{
|
|
Name: galeraresources.AgentPortName,
|
|
Port: ptr.Deref(mariadb.Spec.Galera, mariadbv1alpha1.Galera{}).Agent.Port,
|
|
},
|
|
}...)
|
|
}
|
|
selectorLabels :=
|
|
labels.NewLabelsBuilder().
|
|
WithMariaDBSelectorLabels(mariadb).
|
|
Build()
|
|
|
|
opts := builder.ServiceOpts{
|
|
Ports: ports,
|
|
Headless: true,
|
|
SelectorLabels: selectorLabels,
|
|
ExtraMeta: mariadb.Spec.InheritMetadata,
|
|
}
|
|
desiredSvc, err := r.Builder.BuildService(key, mariadb, opts)
|
|
if err != nil {
|
|
return fmt.Errorf("error building internal Service: %v", err)
|
|
}
|
|
return r.ServiceReconciler.Reconcile(ctx, desiredSvc)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcilePrimaryService(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
if mariadb.Status.CurrentPrimaryPodIndex == nil {
|
|
log.FromContext(ctx).V(1).Info("'status.currentPrimaryPodIndex' must be set")
|
|
return ctrl.Result{RequeueAfter: 1 * time.Second}, nil
|
|
}
|
|
key := mariadb.PrimaryServiceKey()
|
|
ports := []corev1.ServicePort{
|
|
{
|
|
Name: builder.MariadbPortName,
|
|
Port: mariadb.Spec.Port,
|
|
},
|
|
}
|
|
if mariadb.Spec.ServicePorts != nil {
|
|
ports = append(ports, kadapter.ToKubernetesSlice(mariadb.Spec.ServicePorts)...)
|
|
}
|
|
serviceLabels :=
|
|
labels.NewLabelsBuilder().
|
|
WithMariaDBSelectorLabels(mariadb).
|
|
WithStatefulSetPod(mariadb, *mariadb.Status.CurrentPrimaryPodIndex).
|
|
Build()
|
|
opts := builder.ServiceOpts{
|
|
Ports: ports,
|
|
SelectorLabels: serviceLabels,
|
|
ExtraMeta: mariadb.Spec.InheritMetadata,
|
|
}
|
|
if mariadb.Spec.PrimaryService != nil {
|
|
opts.ServiceTemplate = *mariadb.Spec.PrimaryService
|
|
}
|
|
|
|
desiredSvc, err := r.Builder.BuildService(key, mariadb, opts)
|
|
if err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error building Service: %v", err)
|
|
}
|
|
return ctrl.Result{}, r.ServiceReconciler.Reconcile(ctx, desiredSvc)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileSecondaryService(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
key := mariadb.SecondaryServiceKey()
|
|
ports := []corev1.ServicePort{
|
|
{
|
|
Name: builder.MariadbPortName,
|
|
Port: mariadb.Spec.Port,
|
|
},
|
|
}
|
|
if mariadb.Spec.ServicePorts != nil {
|
|
ports = append(ports, kadapter.ToKubernetesSlice(mariadb.Spec.ServicePorts)...)
|
|
}
|
|
selectorLabels :=
|
|
labels.NewLabelsBuilder().
|
|
WithMariaDBSelectorLabels(mariadb).
|
|
Build()
|
|
opts := builder.ServiceOpts{
|
|
ExcludeSelectorLabels: true,
|
|
Ports: ports,
|
|
SelectorLabels: selectorLabels,
|
|
ExtraMeta: mariadb.Spec.InheritMetadata,
|
|
}
|
|
if mariadb.Spec.SecondaryService != nil {
|
|
opts.ServiceTemplate = *mariadb.Spec.SecondaryService
|
|
}
|
|
|
|
desiredSvc, err := r.Builder.BuildService(key, mariadb, opts)
|
|
if err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error building Service: %v", err)
|
|
}
|
|
if err := r.ServiceReconciler.Reconcile(ctx, desiredSvc); err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
return r.EndpointsReconciler.Reconcile(ctx, mariadb.SecondaryServiceKey(), mariadb)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileSQL(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
if !mariadb.IsReady() {
|
|
log.FromContext(ctx).V(1).Info("MariaDB not ready. Requeuing SQL resources")
|
|
return ctrl.Result{RequeueAfter: 1 * time.Second}, nil
|
|
}
|
|
if err := r.reconcileDatabase(ctx, mariadb); err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error reconciling database: %v", err)
|
|
}
|
|
if result, err := r.reconcileUsers(ctx, mariadb); !result.IsZero() || err != nil {
|
|
return result, err
|
|
}
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileDatabase(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) error {
|
|
if mariadb.Spec.Database == nil {
|
|
return nil
|
|
}
|
|
var database mariadbv1alpha1.Database
|
|
err := r.Get(ctx, mariadb.MariadbDatabaseKey(), &database)
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
if !apierrors.IsNotFound(err) {
|
|
return fmt.Errorf("error getting database: %v", err)
|
|
}
|
|
|
|
opts := builder.DatabaseOpts{
|
|
Name: *mariadb.Spec.Database,
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
MariaDBRef: mariadbv1alpha1.MariaDBRef{
|
|
ObjectReference: mariadbv1alpha1.ObjectReference{
|
|
Name: mariadb.Name,
|
|
Namespace: mariadb.Namespace,
|
|
},
|
|
},
|
|
}
|
|
db, err := r.Builder.BuildDatabase(mariadb.MariadbDatabaseKey(), mariadb, opts)
|
|
if err != nil {
|
|
return fmt.Errorf("error building database: %v", err)
|
|
}
|
|
return r.Create(ctx, db)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileUsers(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
sysUserKey := mariadb.MariadbSysUserKey()
|
|
sysGrantKey := mariadb.MariadbSysGrantKey()
|
|
userOpts := builder.UserOpts{
|
|
MariaDBRef: mariadbv1alpha1.MariaDBRef{
|
|
ObjectReference: mariadbv1alpha1.ObjectReference{
|
|
Name: mariadb.Name,
|
|
Namespace: mariadb.Namespace,
|
|
},
|
|
},
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
MaxUserConnections: 20,
|
|
Name: "mariadb.sys",
|
|
Host: "localhost",
|
|
PasswordSecretKeyRef: nil,
|
|
CleanupPolicy: ptr.To(mariadbv1alpha1.CleanupPolicySkip),
|
|
}
|
|
grantOpts := auth.GrantOpts{
|
|
Key: sysGrantKey,
|
|
GrantOpts: builder.GrantOpts{
|
|
MariaDBRef: mariadbv1alpha1.MariaDBRef{
|
|
ObjectReference: mariadbv1alpha1.ObjectReference{
|
|
Name: mariadb.Name,
|
|
Namespace: mariadb.Namespace,
|
|
},
|
|
},
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
Privileges: []string{
|
|
"SELECT",
|
|
"UPDATE",
|
|
"DELETE",
|
|
},
|
|
Database: "mysql",
|
|
Table: "global_priv",
|
|
Username: "mariadb.sys",
|
|
Host: "localhost",
|
|
CleanupPolicy: ptr.To(mariadbv1alpha1.CleanupPolicySkip),
|
|
},
|
|
}
|
|
|
|
if result, err := r.AuthReconciler.ReconcileUserGrant(ctx, sysUserKey, mariadb, userOpts, grantOpts); !result.IsZero() || err != nil {
|
|
if err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error reconciling mariadb.sys user auth: %v", err)
|
|
}
|
|
return result, err
|
|
}
|
|
|
|
var sysGrant mariadbv1alpha1.Grant
|
|
if err := r.Get(ctx, sysGrantKey, &sysGrant); err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error getting mariadb.sys Grant: %v", err)
|
|
}
|
|
if !sysGrant.IsReady() {
|
|
log.FromContext(ctx).V(1).Info("mariadb.sys Grant not ready. Requeuing...")
|
|
return ctrl.Result{RequeueAfter: 1 * time.Second}, nil
|
|
}
|
|
|
|
if mariadb.IsInitialUserEnabled() {
|
|
userKey := mariadb.MariadbUserKey()
|
|
user := builder.UserOpts{
|
|
MariaDBRef: mariadbv1alpha1.MariaDBRef{
|
|
ObjectReference: mariadbv1alpha1.ObjectReference{
|
|
Name: mariadb.Name,
|
|
Namespace: mariadb.Namespace,
|
|
},
|
|
},
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
MaxUserConnections: 20,
|
|
Name: *mariadb.Spec.Username,
|
|
Host: "%",
|
|
}
|
|
if mariadb.Spec.PasswordPlugin != nil {
|
|
user.PasswordPlugin = mariadb.Spec.PasswordPlugin
|
|
} else if mariadb.Spec.PasswordHashSecretKeyRef != nil {
|
|
user.PasswordHashSecretKeyRef = mariadb.Spec.PasswordHashSecretKeyRef
|
|
} else if mariadb.Spec.PasswordSecretKeyRef != nil {
|
|
user.PasswordSecretKeyRef = &mariadb.Spec.PasswordSecretKeyRef.SecretKeySelector
|
|
}
|
|
grant := auth.GrantOpts{
|
|
Key: mariadb.MariadbGrantKey(),
|
|
GrantOpts: builder.GrantOpts{
|
|
MariaDBRef: mariadbv1alpha1.MariaDBRef{
|
|
ObjectReference: mariadbv1alpha1.ObjectReference{
|
|
Name: mariadb.Name,
|
|
Namespace: mariadb.Namespace,
|
|
},
|
|
},
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
Privileges: []string{
|
|
"ALL PRIVILEGES",
|
|
},
|
|
Database: *mariadb.Spec.Database,
|
|
Table: "*",
|
|
Username: *mariadb.Spec.Username,
|
|
Host: "%",
|
|
},
|
|
}
|
|
|
|
if result, err := r.AuthReconciler.ReconcileUserGrant(ctx, userKey, mariadb, user, grant); !result.IsZero() || err != nil {
|
|
if err != nil {
|
|
return ctrl.Result{}, fmt.Errorf("error reconciling user auth: %v", err)
|
|
}
|
|
return result, err
|
|
}
|
|
}
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
func (r *MariaDBReconciler) setSpecDefaults(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
return ctrl.Result{}, r.patch(ctx, mariadb, func(mdb *mariadbv1alpha1.MariaDB) error {
|
|
return mdb.SetDefaults(r.Environment)
|
|
})
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileSuspend(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
if mariadb.IsSuspended() {
|
|
log.FromContext(ctx).V(1).Info("MariaDB is suspended. Skipping...")
|
|
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
|
|
}
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileConnection(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) (ctrl.Result, error) {
|
|
if !mariadb.IsInitialUserEnabled() {
|
|
return ctrl.Result{}, nil
|
|
}
|
|
if !mariadb.IsReady() {
|
|
return ctrl.Result{RequeueAfter: 1 * time.Second}, nil
|
|
}
|
|
if mariadb.IsHAEnabled() {
|
|
if mariadb.Spec.PrimaryConnection != nil {
|
|
key := mariadb.PrimaryConnectioneKey()
|
|
connTpl := mariadb.Spec.PrimaryConnection
|
|
connTpl.ServiceName = ptr.To(mariadb.PrimaryServiceKey().Name)
|
|
|
|
if err := r.reconcileConnectionTemplate(ctx, key, connTpl, mariadb); err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
}
|
|
if mariadb.Spec.SecondaryConnection != nil {
|
|
key := mariadb.SecondaryConnectioneKey()
|
|
connTpl := mariadb.Spec.SecondaryConnection
|
|
connTpl.ServiceName = ptr.To(mariadb.SecondaryServiceKey().Name)
|
|
|
|
if err := r.reconcileConnectionTemplate(ctx, key, connTpl, mariadb); err != nil {
|
|
return ctrl.Result{}, err
|
|
}
|
|
}
|
|
}
|
|
return ctrl.Result{}, r.reconcileDefaultConnection(ctx, mariadb)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileConnectionTemplate(ctx context.Context, key types.NamespacedName,
|
|
connTpl *mariadbv1alpha1.ConnectionTemplate, mariadb *mariadbv1alpha1.MariaDB) error {
|
|
var existingConn mariadbv1alpha1.Connection
|
|
if err := r.Get(ctx, key, &existingConn); err == nil {
|
|
return nil
|
|
}
|
|
|
|
if mariadb.Spec.Username == nil || mariadb.Spec.PasswordSecretKeyRef == nil {
|
|
log.FromContext(ctx).Error(
|
|
errors.New("unable to reconcile Connection"),
|
|
"spec.user and spec.passwordSecretKeyRef must have been initialized",
|
|
"user", mariadb.Spec.Username,
|
|
"passwordKeyRef", mariadb.Spec.PasswordSecretKeyRef,
|
|
)
|
|
return nil
|
|
}
|
|
connOpts := builder.ConnectionOpts{
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
MariaDB: mariadb,
|
|
Key: key,
|
|
Username: *mariadb.Spec.Username,
|
|
PasswordSecretKeyRef: mariadb.Spec.PasswordSecretKeyRef.SecretKeySelector,
|
|
Database: mariadb.Spec.Database,
|
|
Template: connTpl,
|
|
}
|
|
conn, err := r.Builder.BuildConnection(connOpts, mariadb)
|
|
if err != nil {
|
|
return fmt.Errorf("error building Connection: %v", err)
|
|
}
|
|
return r.Create(ctx, conn)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) reconcileDefaultConnection(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB) error {
|
|
if mariadb.Spec.Connection == nil {
|
|
return nil
|
|
}
|
|
key := client.ObjectKeyFromObject(mariadb)
|
|
var existingConn mariadbv1alpha1.Connection
|
|
if err := r.Get(ctx, key, &existingConn); err == nil {
|
|
return nil
|
|
}
|
|
|
|
if mariadb.Spec.Username == nil || mariadb.Spec.PasswordSecretKeyRef == nil {
|
|
log.FromContext(ctx).Error(
|
|
errors.New("unable to reconcile default Connection"),
|
|
"spec.user and spec.passwordSecretKeyRef must have been initialized",
|
|
"user", mariadb.Spec.Username,
|
|
"passwordKeyRef", mariadb.Spec.PasswordSecretKeyRef,
|
|
)
|
|
return nil
|
|
}
|
|
connOpts := builder.ConnectionOpts{
|
|
Metadata: mariadb.Spec.InheritMetadata,
|
|
MariaDB: mariadb,
|
|
Key: key,
|
|
Username: *mariadb.Spec.Username,
|
|
PasswordSecretKeyRef: mariadb.Spec.PasswordSecretKeyRef.SecretKeySelector,
|
|
Database: mariadb.Spec.Database,
|
|
Template: mariadb.Spec.Connection,
|
|
}
|
|
conn, err := r.Builder.BuildConnection(connOpts, mariadb)
|
|
if err != nil {
|
|
return fmt.Errorf("error building Connection: %v", err)
|
|
}
|
|
return r.Create(ctx, conn)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) patchStatus(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB,
|
|
patcher patcherMariaDB) error {
|
|
patch := client.MergeFrom(mariadb.DeepCopy())
|
|
if err := patcher(&mariadb.Status); err != nil {
|
|
return err
|
|
}
|
|
return r.Status().Patch(ctx, mariadb, patch)
|
|
}
|
|
|
|
func (r *MariaDBReconciler) patch(ctx context.Context, mariadb *mariadbv1alpha1.MariaDB,
|
|
patcher func(*mariadbv1alpha1.MariaDB) error) error {
|
|
patch := client.MergeFrom(mariadb.DeepCopy())
|
|
if err := patcher(mariadb); err != nil {
|
|
return err
|
|
}
|
|
return r.Patch(ctx, mariadb, patch)
|
|
}
|
|
|
|
// SetupWithManager sets up the controller with the Manager.
|
|
func (r *MariaDBReconciler) SetupWithManager(ctx context.Context, mgr ctrl.Manager, env *environment.OperatorEnv,
|
|
opts controller.Options) error {
|
|
builder := ctrl.NewControllerManagedBy(mgr).
|
|
For(&mariadbv1alpha1.MariaDB{}).
|
|
Owns(&mariadbv1alpha1.MaxScale{}).
|
|
Owns(&mariadbv1alpha1.Connection{}).
|
|
Owns(&mariadbv1alpha1.Restore{}).
|
|
Owns(&mariadbv1alpha1.User{}).
|
|
Owns(&mariadbv1alpha1.Grant{}).
|
|
Owns(&corev1.ConfigMap{}).
|
|
Owns(&corev1.Service{}).
|
|
Owns(&corev1.Secret{}).
|
|
Owns(&corev1.Event{}).
|
|
Owns(&corev1.ServiceAccount{}).
|
|
Owns(&appsv1.StatefulSet{}).
|
|
Owns(&appsv1.Deployment{}).
|
|
Owns(&policyv1.PodDisruptionBudget{}).
|
|
Owns(&rbacv1.Role{}).
|
|
Owns(&rbacv1.RoleBinding{}).
|
|
WithOptions(opts)
|
|
|
|
currentNamespaceOnly, err := env.CurrentNamespaceOnly()
|
|
if err != nil {
|
|
return fmt.Errorf("error checking operator watch scope: %v", err)
|
|
}
|
|
if !currentNamespaceOnly {
|
|
builder = builder.Owns(&rbacv1.ClusterRoleBinding{})
|
|
}
|
|
|
|
watcherIndexer := watch.NewWatcherIndexer(mgr, builder, r.Client)
|
|
if err := watcherIndexer.Watch(
|
|
ctx,
|
|
&corev1.ConfigMap{},
|
|
&mariadbv1alpha1.MariaDB{},
|
|
&mariadbv1alpha1.MariaDBList{},
|
|
mariadbv1alpha1.MariadbMyCnfConfigMapFieldPath,
|
|
ctrlbuilder.WithPredicates(
|
|
predicate.PredicateWithLabel(metadata.WatchLabel),
|
|
),
|
|
); err != nil {
|
|
return fmt.Errorf("error watching '%s': %v", mariadbv1alpha1.MariadbMyCnfConfigMapFieldPath, err)
|
|
}
|
|
if err := watcherIndexer.Watch(
|
|
ctx,
|
|
&corev1.Secret{},
|
|
&mariadbv1alpha1.MariaDB{},
|
|
&mariadbv1alpha1.MariaDBList{},
|
|
mariadbv1alpha1.MariadbMetricsPasswordSecretFieldPath,
|
|
ctrlbuilder.WithPredicates(
|
|
predicate.PredicateWithLabel(metadata.WatchLabel),
|
|
),
|
|
); err != nil {
|
|
return fmt.Errorf("error watching '%s': %v", mariadbv1alpha1.MariadbMetricsPasswordSecretFieldPath, err)
|
|
}
|
|
|
|
return builder.Complete(r)
|
|
}
|
|
|
|
func defaultConfig(mariadb *mariadbv1alpha1.MariaDB) (string, error) {
|
|
tpl := createTpl("0-default.cnf", `[mariadb]
|
|
skip-name-resolve
|
|
{{- with .TimeZone }}
|
|
default_time_zone = {{ . }}
|
|
{{- end }}
|
|
`)
|
|
|
|
buf := new(bytes.Buffer)
|
|
err := tpl.Execute(buf, struct {
|
|
TimeZone *string
|
|
}{
|
|
TimeZone: mariadb.Spec.TimeZone,
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
func createTpl(name, t string) *template.Template {
|
|
return template.Must(template.New(name).Parse(t))
|
|
}
|