mirror of
https://github.com/mariadb-operator/mariadb-operator.git
synced 2025-08-02 23:55:01 +00:00
Removed recovery operations from agent
This commit is contained in:
@ -37,7 +37,6 @@ var (
|
|||||||
kubernetesAuth bool
|
kubernetesAuth bool
|
||||||
kubernetesTrustedName string
|
kubernetesTrustedName string
|
||||||
kubernetesTrustedNamespace string
|
kubernetesTrustedNamespace string
|
||||||
recoveryTimeout time.Duration
|
|
||||||
gracefulShutdownTimeout time.Duration
|
gracefulShutdownTimeout time.Duration
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -56,8 +55,6 @@ func init() {
|
|||||||
RootCmd.Flags().StringVar(&kubernetesTrustedName, "kubernetes-trusted-name", "", "Trusted Kubernetes ServiceAccount name to be verified")
|
RootCmd.Flags().StringVar(&kubernetesTrustedName, "kubernetes-trusted-name", "", "Trusted Kubernetes ServiceAccount name to be verified")
|
||||||
RootCmd.Flags().StringVar(&kubernetesTrustedNamespace, "kubernetes-trusted-namespace", "", "Trusted Kubernetes ServiceAccount "+
|
RootCmd.Flags().StringVar(&kubernetesTrustedNamespace, "kubernetes-trusted-namespace", "", "Trusted Kubernetes ServiceAccount "+
|
||||||
"namespace to be verified")
|
"namespace to be verified")
|
||||||
RootCmd.Flags().DurationVar(&recoveryTimeout, "recovery-timeout", 1*time.Minute, "Timeout to obtain sequence number "+
|
|
||||||
"during the Galera cluster recovery process")
|
|
||||||
RootCmd.Flags().DurationVar(&gracefulShutdownTimeout, "graceful-shutdown-timeout", 5*time.Second, "Timeout to gracefully terminate "+
|
RootCmd.Flags().DurationVar(&gracefulShutdownTimeout, "graceful-shutdown-timeout", 5*time.Second, "Timeout to gracefully terminate "+
|
||||||
"in-flight requests")
|
"in-flight requests")
|
||||||
}
|
}
|
||||||
@ -102,7 +99,6 @@ var RootCmd = &cobra.Command{
|
|||||||
fileManager,
|
fileManager,
|
||||||
state,
|
state,
|
||||||
&handlerLogger,
|
&handlerLogger,
|
||||||
handler.WithRecoveryTimeout(recoveryTimeout),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
routerOpts := []router.Option{
|
routerOpts := []router.Option{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
##@ Build
|
##@ Build
|
||||||
|
|
||||||
DOCKER_ARGS ?=
|
DOCKER_ARGS ?= --load
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: ## Build binary.
|
build: ## Build binary.
|
||||||
|
@ -171,7 +171,6 @@ func (b *Builder) maxscaleCommand(mxs *mariadbv1alpha1.MaxScale) (*command.Comma
|
|||||||
|
|
||||||
func (b *Builder) galeraAgentContainer(mariadb *mariadbv1alpha1.MariaDB) (*corev1.Container, error) {
|
func (b *Builder) galeraAgentContainer(mariadb *mariadbv1alpha1.MariaDB) (*corev1.Container, error) {
|
||||||
galera := ptr.Deref(mariadb.Spec.Galera, mariadbv1alpha1.Galera{})
|
galera := ptr.Deref(mariadb.Spec.Galera, mariadbv1alpha1.Galera{})
|
||||||
recovery := ptr.Deref(galera.Recovery, mariadbv1alpha1.GaleraRecovery{})
|
|
||||||
agent := galera.Agent
|
agent := galera.Agent
|
||||||
|
|
||||||
container, err := b.buildContainer(agent.Image, agent.ImagePullPolicy, &agent.ContainerTemplate)
|
container, err := b.buildContainer(agent.Image, agent.ImagePullPolicy, &agent.ContainerTemplate)
|
||||||
@ -197,9 +196,6 @@ func (b *Builder) galeraAgentContainer(mariadb *mariadbv1alpha1.MariaDB) (*corev
|
|||||||
if agent.GracefulShutdownTimeout != nil {
|
if agent.GracefulShutdownTimeout != nil {
|
||||||
args = append(args, fmt.Sprintf("--graceful-shutdown-timeout=%s", agent.GracefulShutdownTimeout.Duration))
|
args = append(args, fmt.Sprintf("--graceful-shutdown-timeout=%s", agent.GracefulShutdownTimeout.Duration))
|
||||||
}
|
}
|
||||||
if recovery.Enabled && recovery.PodRecoveryTimeout != nil {
|
|
||||||
args = append(args, fmt.Sprintf("--recovery-timeout=%s", recovery.PodRecoveryTimeout.Duration))
|
|
||||||
}
|
|
||||||
if ptr.Deref(agent.KubernetesAuth, mariadbv1alpha1.KubernetesAuth{}).Enabled {
|
if ptr.Deref(agent.KubernetesAuth, mariadbv1alpha1.KubernetesAuth{}).Enabled {
|
||||||
args = append(args, []string{
|
args = append(args, []string{
|
||||||
"--kubernetes-auth",
|
"--kubernetes-auth",
|
||||||
|
@ -12,7 +12,6 @@ import (
|
|||||||
type Client struct {
|
type Client struct {
|
||||||
Bootstrap *Bootstrap
|
Bootstrap *Bootstrap
|
||||||
State *State
|
State *State
|
||||||
Recovery *Recovery
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(baseUrl string, opts ...mdbhttp.Option) (*Client, error) {
|
func NewClient(baseUrl string, opts ...mdbhttp.Option) (*Client, error) {
|
||||||
@ -24,7 +23,6 @@ func NewClient(baseUrl string, opts ...mdbhttp.Option) (*Client, error) {
|
|||||||
return &Client{
|
return &Client{
|
||||||
Bootstrap: NewBootstrap(httpClient),
|
Bootstrap: NewBootstrap(httpClient),
|
||||||
State: NewState(httpClient),
|
State: NewState(httpClient),
|
||||||
Recovery: NewRecovery(httpClient),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/mariadb-operator/mariadb-operator/pkg/galera/recovery"
|
|
||||||
mdbhttp "github.com/mariadb-operator/mariadb-operator/pkg/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Recovery struct {
|
|
||||||
client *mdbhttp.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRecovery(client *mdbhttp.Client) *Recovery {
|
|
||||||
return &Recovery{
|
|
||||||
client: client,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Recovery) Enable(ctx context.Context) error {
|
|
||||||
res, err := r.client.Put(ctx, "/api/recovery", nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return handleResponse(res, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Recovery) Start(ctx context.Context) (*recovery.Bootstrap, error) {
|
|
||||||
res, err := r.client.Post(ctx, "/api/recovery", nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var bootstrap recovery.Bootstrap
|
|
||||||
if err := handleResponse(res, &bootstrap); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &bootstrap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Recovery) Disable(ctx context.Context) error {
|
|
||||||
res, err := r.client.Delete(ctx, "/api/recovery", nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return handleResponse(res, nil)
|
|
||||||
}
|
|
@ -59,11 +59,6 @@ func (b *Bootstrap) Enable(w http.ResponseWriter, r *http.Request) {
|
|||||||
defer b.locker.Unlock()
|
defer b.locker.Unlock()
|
||||||
b.logger.V(1).Info("enabling bootstrap")
|
b.logger.V(1).Info("enabling bootstrap")
|
||||||
|
|
||||||
if err := b.fileManager.DeleteConfigFile(recovery.RecoveryFileName); err != nil && !os.IsNotExist(err) {
|
|
||||||
b.responseWriter.WriteErrorf(w, "error deleting existing recovery config: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := b.setSafeToBootstrap(&bootstrap); err != nil {
|
if err := b.setSafeToBootstrap(&bootstrap); err != nil {
|
||||||
b.responseWriter.WriteErrorf(w, "error setting safe to bootstrap: %v", err)
|
b.responseWriter.WriteErrorf(w, "error setting safe to bootstrap: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -14,16 +14,14 @@ import (
|
|||||||
type Handler struct {
|
type Handler struct {
|
||||||
Bootstrap *Bootstrap
|
Bootstrap *Bootstrap
|
||||||
State *State
|
State *State
|
||||||
Recovery *Recovery
|
|
||||||
Probe *Probe
|
Probe *Probe
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(mariadbKey types.NamespacedName, client ctrlclient.Client, fileManager *filemanager.FileManager,
|
func NewHandler(mariadbKey types.NamespacedName, client ctrlclient.Client, fileManager *filemanager.FileManager,
|
||||||
initState *state.State, logger *logr.Logger, recoveryOpts ...RecoveryOption) *Handler {
|
initState *state.State, logger *logr.Logger) *Handler {
|
||||||
mux := &sync.RWMutex{}
|
mux := &sync.RWMutex{}
|
||||||
bootstrapLogger := logger.WithName("bootstrap")
|
bootstrapLogger := logger.WithName("bootstrap")
|
||||||
stateLogger := logger.WithName("state")
|
stateLogger := logger.WithName("state")
|
||||||
recoveryLogger := logger.WithName("recovery")
|
|
||||||
probeLogger := logger.WithName("probe")
|
probeLogger := logger.WithName("probe")
|
||||||
|
|
||||||
bootstrap := NewBootstrap(
|
bootstrap := NewBootstrap(
|
||||||
@ -39,13 +37,6 @@ func NewHandler(mariadbKey types.NamespacedName, client ctrlclient.Client, fileM
|
|||||||
mux.RLocker(),
|
mux.RLocker(),
|
||||||
&stateLogger,
|
&stateLogger,
|
||||||
)
|
)
|
||||||
recovery := NewRecover(
|
|
||||||
fileManager,
|
|
||||||
mdbhttp.NewResponseWriter(&recoveryLogger),
|
|
||||||
mux,
|
|
||||||
&recoveryLogger,
|
|
||||||
recoveryOpts...,
|
|
||||||
)
|
|
||||||
probe := NewProbe(
|
probe := NewProbe(
|
||||||
mariadbKey,
|
mariadbKey,
|
||||||
client,
|
client,
|
||||||
@ -56,7 +47,6 @@ func NewHandler(mariadbKey types.NamespacedName, client ctrlclient.Client, fileM
|
|||||||
return &Handler{
|
return &Handler{
|
||||||
Bootstrap: bootstrap,
|
Bootstrap: bootstrap,
|
||||||
State: state,
|
State: state,
|
||||||
Recovery: recovery,
|
|
||||||
Probe: probe,
|
Probe: probe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
"github.com/mariadb-operator/mariadb-operator/pkg/galera/errors"
|
|
||||||
"github.com/mariadb-operator/mariadb-operator/pkg/galera/filemanager"
|
|
||||||
"github.com/mariadb-operator/mariadb-operator/pkg/galera/recovery"
|
|
||||||
mdbhttp "github.com/mariadb-operator/mariadb-operator/pkg/http"
|
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Recovery struct {
|
|
||||||
fileManager *filemanager.FileManager
|
|
||||||
responseWriter *mdbhttp.ResponseWriter
|
|
||||||
locker sync.Locker
|
|
||||||
logger *logr.Logger
|
|
||||||
timeout time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type RecoveryOption func(*Recovery)
|
|
||||||
|
|
||||||
func WithRecoveryTimeout(timeout time.Duration) RecoveryOption {
|
|
||||||
return func(r *Recovery) {
|
|
||||||
r.timeout = timeout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRecover(fileManager *filemanager.FileManager, responseWriter *mdbhttp.ResponseWriter, locker sync.Locker,
|
|
||||||
logger *logr.Logger, opts ...RecoveryOption) *Recovery {
|
|
||||||
recovery := &Recovery{
|
|
||||||
fileManager: fileManager,
|
|
||||||
responseWriter: responseWriter,
|
|
||||||
locker: locker,
|
|
||||||
logger: logger,
|
|
||||||
timeout: 1 * time.Minute,
|
|
||||||
}
|
|
||||||
for _, setOpts := range opts {
|
|
||||||
setOpts(recovery)
|
|
||||||
}
|
|
||||||
return recovery
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Recovery) Enable(w http.ResponseWriter, req *http.Request) {
|
|
||||||
r.locker.Lock()
|
|
||||||
defer r.locker.Unlock()
|
|
||||||
r.logger.V(1).Info("enabling recovery")
|
|
||||||
|
|
||||||
if err := r.fileManager.DeleteConfigFile(recovery.BootstrapFileName); err != nil && !os.IsNotExist(err) {
|
|
||||||
r.responseWriter.WriteErrorf(w, "error deleting existing bootstrap config: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := r.fileManager.DeleteStateFile(recovery.RecoveryLogFileName); err != nil && !os.IsNotExist(err) {
|
|
||||||
r.responseWriter.WriteErrorf(w, "error deleting existing recovery log: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := r.fileManager.WriteConfigFile(recovery.RecoveryFileName, []byte(recovery.RecoveryFile)); err != nil {
|
|
||||||
r.responseWriter.WriteErrorf(w, "error writing recovery config: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Recovery) Start(w http.ResponseWriter, req *http.Request) {
|
|
||||||
r.locker.Lock()
|
|
||||||
defer r.locker.Unlock()
|
|
||||||
r.logger.V(1).Info("starting recovery")
|
|
||||||
|
|
||||||
exists, err := r.fileManager.ConfigFileExists(recovery.RecoveryFileName)
|
|
||||||
if err != nil {
|
|
||||||
r.responseWriter.WriteErrorf(w, "error checking recovery config: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !exists {
|
|
||||||
r.responseWriter.Write(w, errors.NewAPIError("recovery config not found"), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
recoveryCtx, cancel := context.WithTimeout(req.Context(), r.timeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
bootstrap, err := r.pollUntilRecovered(recoveryCtx)
|
|
||||||
if err != nil {
|
|
||||||
r.responseWriter.WriteErrorf(w, "error recovering galera: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r.responseWriter.WriteOK(w, bootstrap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Recovery) Disable(w http.ResponseWriter, req *http.Request) {
|
|
||||||
r.locker.Lock()
|
|
||||||
defer r.locker.Unlock()
|
|
||||||
r.logger.V(1).Info("disabling recovery")
|
|
||||||
|
|
||||||
if err := r.fileManager.DeleteConfigFile(recovery.RecoveryFileName); err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
r.responseWriter.Write(w, errors.NewAPIError("recovery config not found"), http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r.responseWriter.WriteErrorf(w, "error deleting recovery config: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Recovery) pollUntilRecovered(ctx context.Context) (*recovery.Bootstrap, error) {
|
|
||||||
var bootstrap *recovery.Bootstrap
|
|
||||||
err := wait.PollUntilContextCancel(ctx, 1*time.Second, true, func(context.Context) (bool, error) {
|
|
||||||
b, err := r.recover()
|
|
||||||
if err != nil {
|
|
||||||
r.logger.Error(err, "error recovering galera from recovery log")
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
bootstrap = b
|
|
||||||
return true, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return bootstrap, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Recovery) recover() (*recovery.Bootstrap, error) {
|
|
||||||
bytes, err := r.fileManager.ReadStateFile(recovery.RecoveryLogFileName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error reading Galera state file: %v", err)
|
|
||||||
}
|
|
||||||
var bootstrap recovery.Bootstrap
|
|
||||||
if err := bootstrap.Unmarshal(bytes); err != nil {
|
|
||||||
return nil, fmt.Errorf("error unmarshaling bootstrap: %v", err)
|
|
||||||
}
|
|
||||||
return &bootstrap, nil
|
|
||||||
}
|
|
@ -87,11 +87,6 @@ func apiRouter(h *handler.Handler, k8sClient ctrlclient.Client, logger logr.Logg
|
|||||||
r.Route("/state", func(r chi.Router) {
|
r.Route("/state", func(r chi.Router) {
|
||||||
r.Get("/galera", h.State.GetGaleraState)
|
r.Get("/galera", h.State.GetGaleraState)
|
||||||
})
|
})
|
||||||
r.Route("/recovery", func(r chi.Router) {
|
|
||||||
r.Put("/", h.Recovery.Enable)
|
|
||||||
r.Post("/", h.Recovery.Start)
|
|
||||||
r.Delete("/", h.Recovery.Disable)
|
|
||||||
})
|
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,6 @@ const (
|
|||||||
BootstrapFileName = "1-bootstrap.cnf"
|
BootstrapFileName = "1-bootstrap.cnf"
|
||||||
BootstrapFile = `[galera]
|
BootstrapFile = `[galera]
|
||||||
wsrep_new_cluster="ON"`
|
wsrep_new_cluster="ON"`
|
||||||
RecoveryFileName = "2-recovery.cnf"
|
|
||||||
RecoveryLogFileName = "mariadb.err"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
RecoveryFile = fmt.Sprintf(`[galera]
|
|
||||||
log_error=%s
|
|
||||||
wsrep_recover="ON"`, RecoveryLogFileName)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type GaleraRecoverer interface {
|
type GaleraRecoverer interface {
|
||||||
|
Reference in New Issue
Block a user