Skip to content

Commit

Permalink
Add pre- and post-exec commands. (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerrit91 committed Aug 25, 2023
1 parent 8488c2e commit 42b1b36
Show file tree
Hide file tree
Showing 24 changed files with 184 additions and 364 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ jobs:
[ "${GITHUB_EVENT_NAME}" == 'release' ] && echo "tag=${GITHUB_REF##*/}" >> $GITHUB_ENV || true
[ "${GITHUB_EVENT_NAME}" == 'push' ] && echo "tag=latest" >> $GITHUB_ENV || true
- name: Build
run:
make all

- name: Build and push image
uses: docker/build-push-action@v4
with:
Expand Down
27 changes: 5 additions & 22 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,29 +1,12 @@
FROM golang:1.21 as builder
WORKDIR /work
COPY .git .git
COPY api api
COPY cmd cmd
COPY go.mod .
COPY go.sum .
COPY Makefile .
RUN make

# TODO: remove tini in a future release, not required anymore since pre- and post-exec-cmd flags
FROM krallin/ubuntu-tini as ubuntu-tini

# rethinkdb backup/restore requires the python client library
# let's make small binaries of these commands in order not to blow up the image size
FROM rethinkdb:2.4.1 as rethinkdb-python-client-builder
WORKDIR /work
RUN apt update && apt install -y python3-pip
RUN pip3 install pyinstaller==4.3.0 rethinkdb
COPY build/rethinkdb-dump.spec rethinkdb-dump.spec
COPY build/rethinkdb-restore.spec rethinkdb-restore.spec
RUN pyinstaller rethinkdb-dump.spec \
&& pyinstaller rethinkdb-restore.spec
FROM ghcr.io/metal-stack/rethinkdb-backup-tools-build:v2.4.1 as rethinkdb-backup-tools

FROM alpine:3.18
# TODO: remove tini in a future release, not required anymore since pre- and post-exec-cmd flags
RUN apk add --no-cache tini ca-certificates
COPY --from=builder /work/bin/backup-restore-sidecar /backup-restore-sidecar
COPY bin/backup-restore-sidecar /backup-restore-sidecar
COPY --from=ubuntu-tini /usr/local/bin/tini-static /ubuntu/tini
COPY --from=rethinkdb-python-client-builder /work/dist/rethinkdb-dump /work/dist/rethinkdb-restore /rethinkdb/
COPY --from=rethinkdb-backup-tools /rethinkdb-dump /rethinkdb-restore /rethinkdb/
CMD ["/backup-restore-sidecar"]
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ BACKUP_PROVIDER := $(or ${BACKUP_PROVIDER},local)

SHA := $(shell git rev-parse --short=8 HEAD)
GITVERSION := $(shell git describe --long --all)
BUILDDATE := $(shell GO111MODULE=off go run ${COMMONDIR}/time.go)
BUILDDATE := $(shell date --rfc-3339=seconds)
VERSION := $(or ${VERSION},$(shell git describe --tags --exact-match 2> /dev/null || git symbolic-ref -q --short HEAD || git rev-parse --short HEAD))

GO111MODULE := on
Expand All @@ -25,7 +25,7 @@ proto:
make -C proto protoc

.PHONY: dockerimage
dockerimage:
dockerimage: all
docker build -t ghcr.io/metal-stack/backup-restore-sidecar:${DOCKER_TAG} .

.PHONY: dockerpush
Expand Down
28 changes: 0 additions & 28 deletions build/rethinkdb-dump.spec

This file was deleted.

28 changes: 0 additions & 28 deletions build/rethinkdb-restore.spec

This file was deleted.

5 changes: 3 additions & 2 deletions cmd/internal/backup/backup.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package backup

import (
"context"
"os"
"path"

Expand All @@ -14,7 +15,7 @@ import (
)

// Start starts the backup component, which is periodically taking backups of the database
func Start(log *zap.SugaredLogger, backupSchedule string, db database.DatabaseProber, bp backuproviders.BackupProvider, metrics *metrics.Metrics, comp *compress.Compressor, stop <-chan struct{}) error {
func Start(ctx context.Context, log *zap.SugaredLogger, backupSchedule string, db database.DatabaseProber, bp backuproviders.BackupProvider, metrics *metrics.Metrics, comp *compress.Compressor) error {
log.Info("database is now available, starting periodic backups")

c := cron.New()
Expand Down Expand Up @@ -70,7 +71,7 @@ func Start(log *zap.SugaredLogger, backupSchedule string, db database.DatabasePr

c.Start()
log.Infow("scheduling next backup", "at", c.Entry(id).Next.String())
<-stop
<-ctx.Done()
c.Stop()
return nil
}
22 changes: 16 additions & 6 deletions cmd/internal/database/rethinkdb/rethinkdb.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package rethinkdb

import (
"context"
"fmt"
"net"
"os"
Expand Down Expand Up @@ -40,11 +41,13 @@ type RethinkDB struct {
passwordFile string
log *zap.SugaredLogger
executor *utils.CmdExecutor
ctx context.Context
}

// New instantiates a new rethinkdb database
func New(log *zap.SugaredLogger, datadir string, url string, passwordFile string) *RethinkDB {
func New(ctx context.Context, log *zap.SugaredLogger, datadir string, url string, passwordFile string) *RethinkDB {
return &RethinkDB{
ctx: ctx,
log: log,
datadir: datadir,
url: url,
Expand Down Expand Up @@ -125,13 +128,18 @@ func (db *RethinkDB) Recover() error {
}()

db.log.Infow("waiting for rethinkdb database to come up")
restoreDB := New(db.log, db.datadir, "localhost:1", "")
stop := make(chan struct{})

restoreDB := New(db.ctx, db.log, db.datadir, "localhost:1", "")

done := make(chan bool)
defer close(done)

probeCtx, probeCancel := context.WithTimeout(context.Background(), restoreDatabaseStartupTimeout)
defer probeCancel()

var err error
go func() {
err = probe.Start(restoreDB.log, restoreDB, stop)
err = probe.Start(probeCtx, restoreDB.log, restoreDB)
done <- true
}()
select {
Expand All @@ -140,15 +148,17 @@ func (db *RethinkDB) Recover() error {
return fmt.Errorf("error while probing: %w", err)
}
db.log.Infow("rethinkdb in sidecar is now available, now triggering restore commands...")
case <-time.After(restoreDatabaseStartupTimeout):
close(stop)
case <-probeCtx.Done():
return errors.New("rethinkdb database did not come up in time")
}

args := []string{}
if db.url != "" {
args = append(args, "--connect="+restoreDB.url)
}
if db.passwordFile != "" {
args = append(args, "--password-file="+db.passwordFile)
}
args = append(args, rethinkDBRestoreFilePath)

out, err := db.executor.ExecuteCommandWithOutput(rethinkDBRestoreCmd, nil, args...)
Expand Down
27 changes: 18 additions & 9 deletions cmd/internal/initializer/initializer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package initializer

import (
"context"
"fmt"
"net"
"os"
Expand Down Expand Up @@ -30,24 +31,26 @@ type Initializer struct {
db database.Database
bp providers.BackupProvider
comp *compress.Compressor
dbDataDir string
}

func New(log *zap.SugaredLogger, addr string, db database.Database, bp providers.BackupProvider, comp *compress.Compressor) *Initializer {
func New(log *zap.SugaredLogger, addr string, db database.Database, bp providers.BackupProvider, comp *compress.Compressor, dbDataDir string) *Initializer {
return &Initializer{
currentStatus: &v1.StatusResponse{
Status: v1.StatusResponse_CHECKING,
Message: "starting initializer server",
},
log: log,
addr: addr,
db: db,
bp: bp,
comp: comp,
log: log,
addr: addr,
db: db,
bp: bp,
comp: comp,
dbDataDir: dbDataDir,
}
}

// Start starts the initializer, which includes a server component and the initializer itself, which is potentially restoring a backup
func (i *Initializer) Start(stop <-chan struct{}) {
func (i *Initializer) Start(ctx context.Context) {
opts := []grpc.ServerOption{
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
grpc_ctxtags.StreamServerInterceptor(),
Expand Down Expand Up @@ -75,7 +78,7 @@ func (i *Initializer) Start(stop <-chan struct{}) {
}

go func() {
<-stop
<-ctx.Done()
i.log.Info("received stop signal, shutting down")
grpcServer.Stop()
}()
Expand Down Expand Up @@ -106,9 +109,15 @@ func (i *Initializer) Start(stop <-chan struct{}) {
func (i *Initializer) initialize() error {
i.log.Info("start running initializer")

i.log.Info("ensuring database data directory")
err := os.MkdirAll(i.dbDataDir, 0755)
if err != nil {
return fmt.Errorf("unable to ensure database data directory: %w", err)
}

i.log.Info("ensuring backup bucket")
i.currentStatus.Message = "ensuring backup bucket"
err := i.bp.EnsureBackupBucket()
err = i.bp.EnsureBackupBucket()
if err != nil {
return fmt.Errorf("unable to ensure backup bucket: %w", err)
}
Expand Down
5 changes: 3 additions & 2 deletions cmd/internal/probe/probe.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package probe

import (
"context"
"errors"
"time"

Expand All @@ -13,12 +14,12 @@ var (
)

// Start starts the database prober
func Start(log *zap.SugaredLogger, db database.DatabaseProber, stop <-chan struct{}) error {
func Start(ctx context.Context, log *zap.SugaredLogger, db database.DatabaseProber) error {
log.Info("start probing database")

for {
select {
case <-stop:
case <-ctx.Done():
return errors.New("received stop signal, stop probing")
case <-time.After(probeInterval):
err := db.Probe()
Expand Down
43 changes: 0 additions & 43 deletions cmd/internal/signals/signal.go

This file was deleted.

26 changes: 0 additions & 26 deletions cmd/internal/signals/signal_posix.go

This file was deleted.

Loading

0 comments on commit 42b1b36

Please sign in to comment.