fix: Fixes migration Dockerfile.
This commit is contained in:
parent
0bc41c430a
commit
c2eb2d15aa
4 changed files with 36 additions and 81 deletions
|
@ -11,6 +11,8 @@ COPY backend-legacy/tsconfig.json /app/legacy/
|
||||||
COPY backend-legacy/package.json /app/legacy/
|
COPY backend-legacy/package.json /app/legacy/
|
||||||
COPY backend-legacy/package-lock.json /app/legacy/
|
COPY backend-legacy/package-lock.json /app/legacy/
|
||||||
WORKDIR /app/legacy
|
WORKDIR /app/legacy
|
||||||
|
RUN apt update
|
||||||
|
RUN apt install postgresql -y
|
||||||
RUN npm install --save-dev
|
RUN npm install --save-dev
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
RUN rm out/**/*.ts out/**/*.map
|
RUN rm out/**/*.ts out/**/*.map
|
||||||
|
|
|
@ -2,19 +2,15 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.terah.dev/imterah/hermes/api/dbcore"
|
"git.terah.dev/imterah/hermes/api/dbcore"
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/jackc/pgx/v5"
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
@ -93,10 +89,15 @@ func backupRestoreEntrypoint(cCtx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
reader, err := gzip.NewReader(backupFile)
|
reader, err := gzip.NewReader(backupFile)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to initialize Gzip (compression) reader: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
backupDataBytes, err := io.ReadAll(reader)
|
backupDataBytes, err := io.ReadAll(reader)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return fmt.Errorf("failed to read backup contents: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Decompressed backup. Cleaning up...")
|
log.Info("Decompressed backup. Cleaning up...")
|
||||||
|
@ -127,73 +128,7 @@ func backupRestoreEntrypoint(cCtx *cli.Context) error {
|
||||||
return fmt.Errorf("failed to validate backup: %s", err.Error())
|
return fmt.Errorf("failed to validate backup: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Warn("!! WARNING !!")
|
log.Info("Initializing database and opening it...")
|
||||||
log.Warn("This will attempt to permanently wipe the old database. The backup will not be deleted, however, caution is still advised.")
|
|
||||||
log.Warn("Continuing in 5 seconds...")
|
|
||||||
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
log.Info("Wiping database...")
|
|
||||||
|
|
||||||
databaseBackend := os.Getenv("HERMES_DATABASE_BACKEND")
|
|
||||||
|
|
||||||
switch databaseBackend {
|
|
||||||
case "sqlite":
|
|
||||||
filePath := os.Getenv("HERMES_SQLITE_FILEPATH")
|
|
||||||
|
|
||||||
if filePath == "" {
|
|
||||||
return fmt.Errorf("sqlite database file not specified (missing HERMES_SQLITE_FILEPATH)")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := os.Remove(filePath)
|
|
||||||
|
|
||||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
||||||
return fmt.Errorf("failed to delete sqlite database: %s", err.Error())
|
|
||||||
}
|
|
||||||
case "postgresql":
|
|
||||||
// FIXME(imterah): Maybe make this not required?
|
|
||||||
postgresDB := os.Getenv("HERMES_MIGRATE_POSTGRES_DATABASE")
|
|
||||||
|
|
||||||
if postgresDB == "" {
|
|
||||||
return fmt.Errorf("postgres migration DB is not specified (we don't parse the DSN to save space) (missing HERMES_MIGRATE_POSTGRES_DATABASE)")
|
|
||||||
}
|
|
||||||
|
|
||||||
postgresDSN := os.Getenv("HERMES_POSTGRES_DSN")
|
|
||||||
|
|
||||||
if postgresDSN == "" {
|
|
||||||
return fmt.Errorf("postgres DSN not specified (missing HERMES_POSTGRES_DSN)")
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Connecting to database...")
|
|
||||||
|
|
||||||
db, err := pgx.Connect(context.Background(), postgresDSN)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to connect to database: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Dropping database...")
|
|
||||||
|
|
||||||
_, err = db.Query(context.Background(), fmt.Sprintf("DROP DATABASE %s", pgx.Identifier{postgresDB}.Sanitize()))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to drop database: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Closing database connection...")
|
|
||||||
|
|
||||||
err = db.Close(context.Background())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to close database connection: %s", err.Error())
|
|
||||||
}
|
|
||||||
case "":
|
|
||||||
return fmt.Errorf("no database backend specified in environment variables (missing HERMES_DATABASE_BACKEND)")
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown database backend specified: %s", os.Getenv(databaseBackend))
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Reinitializing database and opening it...")
|
|
||||||
|
|
||||||
err = dbcore.InitializeDatabase(&gorm.Config{})
|
err = dbcore.InitializeDatabase(&gorm.Config{})
|
||||||
|
|
||||||
|
@ -254,7 +189,7 @@ func backupRestoreEntrypoint(cCtx *cli.Context) error {
|
||||||
var bestEffortOwnerUID uint
|
var bestEffortOwnerUID uint
|
||||||
|
|
||||||
for _, user := range backupData.Users {
|
for _, user := range backupData.Users {
|
||||||
log.Debugf("Migrating user with email '%s' and ID of '%d'", user.Email, user.ID)
|
log.Infof("Migrating user with email '%s' and ID of '%d'", user.Email, user.ID)
|
||||||
tokens := make([]dbcore.Token, 0)
|
tokens := make([]dbcore.Token, 0)
|
||||||
permissions := make([]dbcore.Permission, 0)
|
permissions := make([]dbcore.Permission, 0)
|
||||||
|
|
||||||
|
@ -307,7 +242,7 @@ func backupRestoreEntrypoint(cCtx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, backend := range backupData.Backends {
|
for _, backend := range backupData.Backends {
|
||||||
log.Debugf("Migrating backend ID '%d' with name '%s'", backend.ID, backend.Name)
|
log.Infof("Migrating backend ID '%d' with name '%s'", backend.ID, backend.Name)
|
||||||
|
|
||||||
backendDatabase := &dbcore.Backend{
|
backendDatabase := &dbcore.Backend{
|
||||||
UserID: bestEffortOwnerUID,
|
UserID: bestEffortOwnerUID,
|
||||||
|
@ -321,14 +256,14 @@ func backupRestoreEntrypoint(cCtx *cli.Context) error {
|
||||||
log.Errorf("Failed to create backend: %s", err.Error())
|
log.Errorf("Failed to create backend: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Migrating proxies for backend ID '%d'", backend.ID)
|
log.Infof("Migrating proxies for backend ID '%d'", backend.ID)
|
||||||
|
|
||||||
for _, proxy := range backupData.Proxies {
|
for _, proxy := range backupData.Proxies {
|
||||||
if proxy.BackendID != backend.ID {
|
if proxy.BackendID != backend.ID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Migrating proxy ID '%d' with name '%s'", proxy.ID, proxy.Name)
|
log.Infof("Migrating proxy ID '%d' with name '%s'", proxy.ID, proxy.Name)
|
||||||
|
|
||||||
proxyDatabase := &dbcore.Proxy{
|
proxyDatabase := &dbcore.Proxy{
|
||||||
BackendID: backendDatabase.ID,
|
BackendID: backendDatabase.ID,
|
||||||
|
|
|
@ -17,10 +17,11 @@ Below are new environment variables that may need to be set up:
|
||||||
## Migration steps
|
## Migration steps
|
||||||
1. Remove all old environment variables.
|
1. Remove all old environment variables.
|
||||||
2. Add these variables:
|
2. Add these variables:
|
||||||
- `HERMES_MIGRATE_POSTGRES_DATABASE` -> `$POSTGRES_DB`
|
- `HERMES_MIGRATE_POSTGRES_DATABASE` -> `${POSTGRES_DB}`
|
||||||
- `HERMES_DATABASE_BACKEND` -> `postgresql`
|
- `HERMES_DATABASE_BACKEND` -> `postgresql`
|
||||||
- `HERMES_POSTGRES_DSN` -> `postgres://$POSTGRES_USERNAME:$POSTGRES_PASSWORD@nextnet-postgres:5432/$POSTGRES_DB`
|
- `HERMES_POSTGRES_DSN` -> `postgres://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@nextnet-postgres:5432/${POSTGRES_DB}`
|
||||||
- `DATABASE_URL` -> `postgresql://$POSTGRES_USERNAME:$POSTGRES_PASSWORD@nextnet-postgres:5432/$POSTGRES_DB?schema=nextnet`
|
- `DATABASE_URL` -> `postgresql://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@nextnet-postgres:5432/${POSTGRES_DB}?schema=nextnet`
|
||||||
|
- `HERMES_JWT_SECRET` -> Random data (recommended to use `head -c 500 /dev/random | sha512sum | cut -d " " -f 1` to seed the data)
|
||||||
3. Switch the API docker image from `ghcr.io/imterah/nextnet:latest` to `ghcr.io/imterah/hermes-backend-migration:latest`
|
3. Switch the API docker image from `ghcr.io/imterah/nextnet:latest` to `ghcr.io/imterah/hermes-backend-migration:latest`
|
||||||
4. Change the exposed ports from `3000:3000` to `3000:8000`.
|
4. Change the exposed ports from `3000:3000` to `3000:8000`.
|
||||||
5. Start the Docker compose stack.
|
5. Start the Docker compose stack.
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
echo "Welcome to the Hermes migration wizard."
|
echo "Welcome to the Hermes migration assistant."
|
||||||
|
|
||||||
if [ ! -f "/tmp/db.json.gz" ]; then
|
if [ ! -f "/tmp/db.json.gz" ]; then
|
||||||
echo "Exporting database contents..."
|
echo "Exporting database contents..."
|
||||||
cd /app/legacy
|
cd /app/legacy
|
||||||
node out/tools/exportDBContents.js /tmp/db.json.gz
|
node out/tools/exportDBContents.js /tmp/db.json.gz
|
||||||
|
BACKUP_EXIT_CODE=$?
|
||||||
|
|
||||||
|
if [ $BACKUP_EXIT_CODE -ne 0 ]; then
|
||||||
|
echo "Failed to export database contents!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "!! IMPORTANT !!"
|
echo "!! IMPORTANT !!"
|
||||||
echo "Database backup contents below:"
|
echo "Database backup contents below:"
|
||||||
echo "==== BEGIN BACKUP ===="
|
echo "==== BEGIN BACKUP ===="
|
||||||
|
@ -13,11 +20,21 @@ if [ ! -f "/tmp/db.json.gz" ]; then
|
||||||
echo "When copying, do NOT copy the BEGIN and END sections."
|
echo "When copying, do NOT copy the BEGIN and END sections."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "Wiping old database..."
|
||||||
|
cat >> /tmp/wipe.sql << EOF
|
||||||
|
CREATE DATABASE temp;
|
||||||
|
\c temp
|
||||||
|
DROP DATABASE $HERMES_MIGRATE_POSTGRES_DATABASE;
|
||||||
|
CREATE DATABASE $HERMES_MIGRATE_POSTGRES_DATABASE;
|
||||||
|
\c nextnet
|
||||||
|
DROP DATABASE temp;
|
||||||
|
EOF
|
||||||
|
psql "$HERMES_POSTGRES_DATABASE" < /tmp/wipe.sql
|
||||||
|
rm -rf /tmp/wipe.sql
|
||||||
echo "Restoring backup..."
|
echo "Restoring backup..."
|
||||||
|
|
||||||
cd /app/modern
|
cd /app/modern
|
||||||
./hermes -b ./backends.json import --bp /tmp/db.json.gz
|
./hermes -b ./backends.json import --bp /tmp/db.json.gz
|
||||||
rm -rf /tmp/db.json.gz
|
|
||||||
|
|
||||||
echo "Restored backup. If this restore fails after the database has wiped, get a shell into the container,"
|
echo "Restored backup. If this restore fails after the database has wiped, get a shell into the container,"
|
||||||
echo "copy the backup contents into the container (base64 decoded) at '/tmp/db.json.gz',"
|
echo "copy the backup contents into the container (base64 decoded) at '/tmp/db.json.gz',"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue