diff --git a/srcs/cmd/borg-backup/entrypoint/entrypoint.go b/srcs/cmd/borg-backup/entrypoint/entrypoint.go new file mode 100644 index 0000000..55a687a --- /dev/null +++ b/srcs/cmd/borg-backup/entrypoint/entrypoint.go @@ -0,0 +1,119 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "bufio" + + "git.keyzox.me/42_adjoly/inception/internal/cmd" + "git.keyzox.me/42_adjoly/inception/internal/env" + _log "git.keyzox.me/42_adjoly/inception/internal/log" + "git.keyzox.me/42_adjoly/inception/internal/pass" +) + +func overrideCronFile(filePath string, jobs []string) error { + file, err := os.Create(filePath) + if err != nil { + return err + } + defer file.Close() + + writer := bufio.NewWriter(file) + for _, job := range jobs { + _, err := writer.WriteString(job + "\n") + if err != nil { + return err + } + } + return writer.Flush() +} + +func isBorgInit(repo string) (bool, error) { + cmd := exec.Command("borg", "info", repo) + + err := cmd.Run() + if err != nil { + if exitError, ok := err.(*exec.ExitError); ok { + if exitError.ExitCode() == 2 { + return false, nil + } + } + return false, err + } + return true, err +} + +func main() { + args := os.Args + + src := env.EnvCheck("BORG_SRC", "/source") + if _, err := os.ReadDir(src); err != nil { + _log.Log("error", src+" does not exist can't perform backup") + } + + repo := env.EnvCheck("BORG_REPO", "/backup") + if _, err := os.ReadDir(src); err != nil { + _log.Log("error", repo+" does not exist can't perform backup") + } + is, err := isBorgInit(repo) + if err != nil { + log.Fatal(err) + } else if is == true { + _log.Log("note", "Repo already initialize, skipping...") + } else { + _log.Log("note", "Initializing repo...") + + passphrase := env.FileEnv("BORG_PASSPHRASE", "") + if passphrase == "" { + _log.Log("error", "No passphrase specified, exiting...") + } + + err = cmd.ExecCmd([]string{"borg", "init", "--encryption=" + passphrase, repo}) + if err != nil { + log.Fatal(err) + } + } + + interval := env.EnvCheck("CRON_INTERVAL", "0 0 * * *") + cronFilePath := "/etc/crontabs/root" + newJobs := []string{ + "# Borg Backup Cron Job", + interval + " root run-parts /docker-backup.d >> /var/log/cron.log 2>&1", + } + err = overrideCronFile(cronFilePath, newJobs) + if err != nil { + fmt.Printf("Error overriding cron file: %v\n", err) + } else { + fmt.Println("Cron file overridden successfully.") + } + + dir, err := os.ReadDir("/docker-entrypoint.d") + if err != nil { + log.Fatal(err) + } + _log.Log("note", "Running entrypoint scripts") + for _, v := range dir { + os.Chmod("/docker-entrypoint.d/"+v.Name(), 0755) + cmd := exec.Command("/docker-entrypoint.d/" + v.Name()) + cmd.Env = os.Environ() + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + if err := cmd.Run(); err != nil { + fmt.Printf("Error running script(%s): %v\n", v.Name(), err) + os.Exit(1) + } + } + + cmd := exec.Command(args[1], args[2:]...) + cmd.Env = os.Environ() + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + if err := cmd.Run(); err != nil { + fmt.Printf("Error running BORGBACKUP: %v\n", err) + os.Exit(1) + } +} diff --git a/srcs/cmd/vsftpd/entrypoint/entrypoint.go b/srcs/cmd/vsftpd/entrypoint/entrypoint.go deleted file mode 100644 index 8163458..0000000 --- a/srcs/cmd/vsftpd/entrypoint/entrypoint.go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -import ( - "bytes" - "os" - - "fmt" - "log" - "os/exec" - - "git.keyzox.me/42_adjoly/inception/internal/cmd" - "git.keyzox.me/42_adjoly/inception/internal/env" - _log "git.keyzox.me/42_adjoly/inception/internal/log" -) - -func configFtp() { - _log.Log("note", "Configuring VSFTPD...") - ftpUser := env.FileEnv("FTP_USER", "ftp") - ftpPass := env.FileEnv("FTP_PASS", "ftppass") - cmd.ExecCmd([]string{"adduser", ftpUser, "--disabled-password"}) - - var stdin bytes.Buffer - stdin.WriteString(fmt.Sprintf("%s:%s", ftpUser, ftpPass)) - - cmd := exec.Command("/usr/sbin/chpasswd") - cmd.Stdin = &stdin - err := cmd.Run() - if err != nil { - log.Fatal(err) - } - - _, err = os.Create("/etc/vsftpd.check") - if err != nil { - log.Fatal("could not create check file :O") - } - os.WriteFile("/etc/vsftpd/vsftpd.userlist", []byte(ftpUser), 0766) - - _log.Log("note", "VSFTPD configured ;D") -} - -func main() { - args := os.Args - - if args[1] == "vsftpd" { - _log.Log("note", "Entrypoint script for VSFTPD Server started") - - _, err := os.ReadFile("/etc/vsftpd.check") - if err != nil { - configFtp() - } else { - _log.Log("note", "VSFTPD already configured, skipping...") - } - - dir, err := os.ReadDir("/docker-entrypoint.d") - if err != nil { - log.Fatal(err) - } - _log.Log("note", "Running entrypoint scripts") - for _, v := range dir { - os.Chmod("/docker-entrypoint.d/"+v.Name(), 0755) - cmd := exec.Command("/docker-entrypoint.d/" + v.Name()) - cmd.Env = os.Environ() - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Stdin = os.Stdin - if err := cmd.Run(); err != nil { - fmt.Printf("Error running script(%s): %v\n", v.Name(), err) - os.Exit(1) - } - } - } - cmd := exec.Command(args[1], args[2:]...) - cmd.Env = os.Environ() - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Stdin = os.Stdin - if err := cmd.Run(); err != nil { - fmt.Printf("Error running VSFTPD: %v\n", err) - os.Exit(1) - } -} diff --git a/srcs/docker-compose.yml b/srcs/docker-compose.yml index 7731cee..ba0b0d9 100644 --- a/srcs/docker-compose.yml +++ b/srcs/docker-compose.yml @@ -83,24 +83,6 @@ services: - wp-db:/var/lib/mysql restart: unless-stopped - ftp: - build: - context: . - dockerfile: docker/bonus/vsftpd/Dockerfile - ports: - - 2100:2100 - - 30000-30100:30000-30100 - volumes: - - wp-site:/var/ftp - environment: - - FTP_USER=kanel - - FTP_PASS=legoat - depends_on: - nginx: - condition: service_started - wordpress-php: - condition: service_healthy - static-site: build: docker/bonus/static-site ports: @@ -111,4 +93,32 @@ services: - TZ=Europe/Paris - NGINX_SSL_KEY_FILE=/etc/nginx/ssl/kanel-wp.key - NGINX_SSL_CERT_FILE=/etc/nginx/ssl/kanel-wp.crt + restart: unless-stopped + backup: + build: + context: . + dockerfile: docker/bonus/borg-backup/Dockerfile + networks: + - inception + environment: + - TZ=Europe/Paris # handled by tzdata + - CRON_INTERVAL=0 0 * * * # handled by entrypoint + - BORG_PASSPHRASE=Hanky-Kangaroo-Thinning5-Statute-Mascot-Islamist + - BORG_REPO=/backup + - BORG_SRC=/source + - BORG_COMPRESS=zstd + - BORG_PRUNE_KEEP_DAILY=3 + - BORG_PRUNE_KEEP_WEEKLY=2 + - BORG_PRUNE_KEEP_MONTHLY=1 + #- BORG_EXCLUDE_PATTERNS=/var/www/cache # just an exemple to remove after + - BORG_LOG_LEVEL=info + - BORG_CHECK_LAST=3 + - BORG_CHECK_DATA=1 + depends_on: + nginx: + condition: service_healthy + volumes: + - wp-db:/source/db + - wp-site:/source/wordpress + restart: unless-stopped diff --git a/srcs/docker/bonus/borg-backup/Dockerfile b/srcs/docker/bonus/borg-backup/Dockerfile new file mode 100644 index 0000000..e55c149 --- /dev/null +++ b/srcs/docker/bonus/borg-backup/Dockerfile @@ -0,0 +1,33 @@ +FROM scratch AS builder +ADD alpine-minirootfs-3.21.2-x86_64.tar.gz / + +WORKDIR /build + +COPY go.sum /build/go.sum +COPY go.mod /build/go.mod +COPY cmd /build/cmd +COPY internal /build/internal + +RUN cd /build \ + && go build git.keyzox.me/42_adjoly/inception/cmd/borg-backup/entrypoint + +FROM scratch +ADD alpine-minirootfs-3.21.2-x86_64.tar.gz / + +RUN mkdir -p /backup \ + && mkdir -p /source \ + && mkdir /docker-entrypoint.d \ + && mkdir /docker-backup.d + +RUN apk add --no-cache borgbackup tzdata \ + && rm -rf /var/cache/apk/* + +COPY --from=builder /build/entrypoint /docker-entrypoint +COPY docker/bonus/borg-backup/default-bak.sh /docker-backup.d + +ENTRYPOINT [ "/docker-entrypoint" ] +WORKDIR / + +STOPSIGNAL SIGQUIT + +CMD [ "crond", "-l", "${CRON_LOGLEVEL:-8}", "-f" ] diff --git a/srcs/docker/bonus/borg-backup/default-bak.sh b/srcs/docker/bonus/borg-backup/default-bak.sh new file mode 100644 index 0000000..e302ba0 --- /dev/null +++ b/srcs/docker/bonus/borg-backup/default-bak.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +set -e + +# Define variables from environment +REPO=${BORG_REPO} +PASSPHRASE=${BORG_PASSPHRASE} +SOURCE=${BORG_SOURCE} +COMPRESSION=${BORG_COMPRESS:-zstd} +PRUNE_KEEP_DAILY=${BORG_PRUNE_KEEP_DAILY:-7} +PRUNE_KEEP_WEEKLY=${BORG_PRUNE_KEEP_WEEKLY:-4} +PRUNE_KEEP_MONTHLY=${BORG_PRUNE_KEEP_MONTHLY:-6} +EXCLUDE_PATTERNS=${BORG_EXCLUDE_PATTERNS:-} +CHECK_LAST=${BORG_CHECK_LAST} + +BAK_ARGS=--compression $COMPRESSION + +if [[ -z "$PASSPHRASE" ]]; then + exit 1 +fi + +if [[ -n "$EXCLUDE_PATTERNS" ]]; then + BAK_ARGS+=--exclude $EXCLUDE_PATTERNS +fi + +# Borg backup command +borg create --stats $BAK_ARGS \ + $REPO::$(hostname)-$(date +%Y-%m-%d) $SOURCE + +# Borg prune command + +echo "Creating backup..." +borg prune --list $REPO --keep-daily=$PRUNE_KEEP_DAILY --keep-weekly=$PRUNE_KEEP_WEEKLY --keep-monthly=$PRUNE_KEEP_MONTHLY + +# Borg check command +CHECK_ARGS="" + +if [[ -n "$CHECK_LAST" ]]; then + CHECK_ARGS+=--last $CHECK_LAST +fi +if [[ -n "$CHECK_DATA" ]]; then + CHECK_ARGS+=--verify-data +fi + +borg check $CHECK_ARGS $REPO diff --git a/srcs/docker/bonus/vsftpd/Dockerfile b/srcs/docker/bonus/vsftpd/Dockerfile deleted file mode 100644 index bfcbb20..0000000 --- a/srcs/docker/bonus/vsftpd/Dockerfile +++ /dev/null @@ -1,39 +0,0 @@ -FROM scratch as builder -ADD docker/alpine/alpine-minirootfs-3.21.2-x86_64.tar.gz / - -RUN apk add --no-cache go - -WORKDIR /build - -COPY go.mod /build/go.mod -COPY cmd /build/cmd -COPY internal /build/internal - -RUN cd /build \ - && go build git.keyzox.me/42_adjoly/inception/cmd/vsftpd/entrypoint - -FROM scratch -ADD docker/alpine/alpine-minirootfs-3.21.2-x86_64.tar.gz / - -LABEL maintainer="KeyZox" -LABEL version="0.1" - -COPY --from=builder /build/entrypoint /docker-entrypoint -COPY docker/bonus/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf - -RUN apk add vsftpd \ - && mkdir -p /var/ftp \ - && mkdir -p /docker-entrypoint.d - -VOLUME /var/ftp - - -ENTRYPOINT [ "/docker-entrypoint" ] -WORKDIR /etc/vsftpd - -EXPOSE 21 -EXPOSE 30000-30100 - -STOPSIGNAL SIGQUIT - -CMD [ "vsftpd", "/etc/vsftpd/vsftpd.conf" ] diff --git a/srcs/docker/bonus/vsftpd/vsftpd.conf b/srcs/docker/bonus/vsftpd/vsftpd.conf deleted file mode 100644 index ec0cf12..0000000 --- a/srcs/docker/bonus/vsftpd/vsftpd.conf +++ /dev/null @@ -1,25 +0,0 @@ -anonymous_enable=NO -local_enable=YES -write_enable=YES -dirmessage_enable=YES -xferlog_enable=YES - -ftpd_banner=Welcome to your WordPress FTP server. - -chroot_local_user=YES -allow_writeable_chroot=YES -user_sub_token=$USER -local_root=/var/ftp - -listen=YES -listen_port=2100 -listen_address=0.0.0.0 -seccomp_sandbox=NO - -pasv_enable=YES -pasv_min_port=30000 -pasv_max_port=30100 - -userlist_enable=YES -userlist_file=/etc/vsftpd/vsftpd.userlist -userlist_deny=NO diff --git a/srcs/docker/mariadb/Dockerfile b/srcs/docker/mariadb/Dockerfile index 832ebe0..9782175 100644 --- a/srcs/docker/mariadb/Dockerfile +++ b/srcs/docker/mariadb/Dockerfile @@ -25,16 +25,9 @@ RUN addgroup mysql \ COPY --from=builder /build/entrypoint /docker-entrypoint COPY --from=builder /build/healthcheck /docker-healthcheck -RUN mkdir /build - -COPY go.mod /build/go.mod -COPY cmd /build/cmd -COPY internal /build/internal - -RUN apk add --no-cache go mariadb tzdata mariadb-client \ +RUN apk add --no-cache mariadb tzdata mariadb-client \ && chmod +x /docker-healthcheck \ && chmod +x /docker-entrypoint \ - && apk del go \ && mkdir -p /etc/mysql/conf.d /etc/mysql/mariadb.conf.d/ /run/mariadb /run/mysqld \ && chmod ugo+rwx,o+t /run/mariadb \ && chown -R mysql:mysql /var/lib/mysql /run/mariadb /run/mysqld \ diff --git a/srcs/internal/cmd/cmd.go b/srcs/internal/cmd/cmd.go index eff3c20..4f7cb84 100644 --- a/srcs/internal/cmd/cmd.go +++ b/srcs/internal/cmd/cmd.go @@ -7,13 +7,11 @@ import ( _log "git.keyzox.me/42_adjoly/inception/internal/log" ) -func ExecCmd(cmdStr []string) { +func ExecCmd(cmdStr []string) error { cmd := exec.Command(cmdStr[0], cmdStr...) cmd.Env = os.Environ() cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin - if err := cmd.Run(); err != nil { - _log.Log("error", "Could not execute : " + cmdStr[0]) - } + return cmd.Run() }