mirror of
https://github.com/databasus/databasus.git
synced 2026-04-06 00:32:03 +02:00
FEAUTRE (logging): Move logger to DI in services and models instead of globlal variables
This commit is contained in:
@@ -14,13 +14,13 @@ require (
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/minio/minio-go/v7 v7.0.92
|
||||
github.com/shirou/gopsutil/v4 v4.25.5
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/swaggo/files v1.0.1
|
||||
github.com/swaggo/gin-swagger v1.6.0
|
||||
github.com/swaggo/swag v1.16.4
|
||||
github.com/testcontainers/testcontainers-go v0.37.0
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/sys v0.33.0
|
||||
gorm.io/driver/postgres v1.5.11
|
||||
gorm.io/gorm v1.26.1
|
||||
)
|
||||
@@ -101,8 +101,6 @@ require (
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/shirou/gopsutil/v4 v4.25.5 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/tinylib/msgp v1.3.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.15 // indirect
|
||||
@@ -120,6 +118,7 @@ require (
|
||||
golang.org/x/arch v0.17.0 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
|
||||
@@ -213,8 +213,6 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc=
|
||||
github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
|
||||
@@ -111,7 +111,7 @@ func loadEnvVariables() {
|
||||
log.Info("ENV_MODE loaded", "mode", env.EnvMode)
|
||||
|
||||
env.PostgresesInstallDir = filepath.Join(backendRoot, "tools", "postgresql")
|
||||
tools.VerifyPostgresesInstallation(env.EnvMode, env.PostgresesInstallDir)
|
||||
tools.VerifyPostgresesInstallation(log, env.EnvMode, env.PostgresesInstallDir)
|
||||
|
||||
// Store the data and temp folders one level below the root
|
||||
// (projectRoot/postgresus-data -> /postgresus-data)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package backups
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"postgresus-backend/internal/config"
|
||||
"postgresus-backend/internal/features/databases"
|
||||
"postgresus-backend/internal/features/storages"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -15,15 +15,14 @@ type BackupBackgroundService struct {
|
||||
storageService *storages.StorageService
|
||||
|
||||
lastBackupTime time.Time
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
var log = logger.GetLogger()
|
||||
|
||||
func (s *BackupBackgroundService) Run() {
|
||||
s.lastBackupTime = time.Now().UTC()
|
||||
|
||||
if err := s.failBackupsInProgress(); err != nil {
|
||||
log.Error("Failed to fail backups in progress", "error", err)
|
||||
s.logger.Error("Failed to fail backups in progress", "error", err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -37,11 +36,11 @@ func (s *BackupBackgroundService) Run() {
|
||||
}
|
||||
|
||||
if err := s.cleanOldBackups(); err != nil {
|
||||
log.Error("Failed to clean old backups", "error", err)
|
||||
s.logger.Error("Failed to clean old backups", "error", err)
|
||||
}
|
||||
|
||||
if err := s.runPendingBackups(); err != nil {
|
||||
log.Error("Failed to run pending backups", "error", err)
|
||||
s.logger.Error("Failed to run pending backups", "error", err)
|
||||
}
|
||||
|
||||
s.lastBackupTime = time.Now().UTC()
|
||||
@@ -102,7 +101,7 @@ func (s *BackupBackgroundService) cleanOldBackups() error {
|
||||
dateBeforeBackupsShouldBeDeleted,
|
||||
)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
s.logger.Error(
|
||||
"Failed to find old backups for database",
|
||||
"databaseId",
|
||||
database.ID,
|
||||
@@ -115,7 +114,7 @@ func (s *BackupBackgroundService) cleanOldBackups() error {
|
||||
for _, backup := range oldBackups {
|
||||
storage, err := s.storageService.GetStorageByID(backup.StorageID)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
s.logger.Error(
|
||||
"Failed to get storage by ID",
|
||||
"storageId",
|
||||
backup.StorageID,
|
||||
@@ -125,14 +124,18 @@ func (s *BackupBackgroundService) cleanOldBackups() error {
|
||||
continue
|
||||
}
|
||||
|
||||
storage.DeleteFile(backup.ID)
|
||||
|
||||
if err := s.backupRepository.DeleteByID(backup.ID); err != nil {
|
||||
log.Error("Failed to delete old backup", "backupId", backup.ID, "error", err)
|
||||
err = storage.DeleteFile(backup.ID)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to delete backup file", "backupId", backup.ID, "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Info("Deleted old backup", "backupId", backup.ID, "databaseId", database.ID)
|
||||
if err := s.backupRepository.DeleteByID(backup.ID); err != nil {
|
||||
s.logger.Error("Failed to delete old backup", "backupId", backup.ID, "error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
s.logger.Info("Deleted old backup", "backupId", backup.ID, "databaseId", database.ID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +155,7 @@ func (s *BackupBackgroundService) runPendingBackups() error {
|
||||
|
||||
lastBackup, err := s.backupRepository.FindLastByDatabaseID(database.ID)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
s.logger.Error(
|
||||
"Failed to get last backup for database",
|
||||
"databaseId",
|
||||
database.ID,
|
||||
@@ -168,7 +171,7 @@ func (s *BackupBackgroundService) runPendingBackups() error {
|
||||
}
|
||||
|
||||
if database.BackupInterval.ShouldTriggerBackup(time.Now().UTC(), lastBackupTime) {
|
||||
log.Info(
|
||||
s.logger.Info(
|
||||
"Triggering scheduled backup",
|
||||
"databaseId",
|
||||
database.ID,
|
||||
@@ -177,7 +180,7 @@ func (s *BackupBackgroundService) runPendingBackups() error {
|
||||
)
|
||||
|
||||
go s.backupService.MakeBackup(database.ID)
|
||||
log.Info("Successfully triggered scheduled backup", "databaseId", database.ID)
|
||||
s.logger.Info("Successfully triggered scheduled backup", "databaseId", database.ID)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,25 +2,22 @@ package backups
|
||||
|
||||
import (
|
||||
"postgresus-backend/internal/features/backups/usecases"
|
||||
usecases_postgresql "postgresus-backend/internal/features/backups/usecases/postgresql"
|
||||
"postgresus-backend/internal/features/databases"
|
||||
"postgresus-backend/internal/features/notifiers"
|
||||
"postgresus-backend/internal/features/storages"
|
||||
"postgresus-backend/internal/features/users"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
"time"
|
||||
)
|
||||
|
||||
var createPostgresqlBackupUsecase = &usecases_postgresql.CreatePostgresqlBackupUsecase{}
|
||||
var createBackupUseCase = &usecases.CreateBackupUsecase{
|
||||
CreatePostgresqlBackupUsecase: createPostgresqlBackupUsecase,
|
||||
}
|
||||
var backupRepository = &BackupRepository{}
|
||||
var backupService = &BackupService{
|
||||
databases.GetDatabaseService(),
|
||||
storages.GetStorageService(),
|
||||
backupRepository,
|
||||
notifiers.GetNotifierService(),
|
||||
createBackupUseCase,
|
||||
usecases.GetCreateBackupUsecase(),
|
||||
logger.GetLogger(),
|
||||
}
|
||||
|
||||
var backupBackgroundService = &BackupBackgroundService{
|
||||
@@ -29,6 +26,7 @@ var backupBackgroundService = &BackupBackgroundService{
|
||||
databases.GetDatabaseService(),
|
||||
storages.GetStorageService(),
|
||||
time.Now().UTC(),
|
||||
logger.GetLogger(),
|
||||
}
|
||||
|
||||
var backupController = &BackupController{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package backups
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"postgresus-backend/internal/features/databases"
|
||||
"postgresus-backend/internal/features/storages"
|
||||
"time"
|
||||
@@ -27,14 +28,14 @@ type Backup struct {
|
||||
CreatedAt time.Time `json:"createdAt" gorm:"column:created_at"`
|
||||
}
|
||||
|
||||
func (b *Backup) DeleteBackupFromStorage() {
|
||||
func (b *Backup) DeleteBackupFromStorage(logger *slog.Logger) {
|
||||
if b.Status != BackupStatusCompleted {
|
||||
return
|
||||
}
|
||||
|
||||
err := b.Storage.DeleteFile(b.ID)
|
||||
if err != nil {
|
||||
log.Error("Failed to delete backup from storage", "error", err)
|
||||
logger.Error("Failed to delete backup from storage", "error", err)
|
||||
// we ignore the error, because the access to the storage
|
||||
// may be lost, file already deleted, etc.
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package backups
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"postgresus-backend/internal/features/backups/usecases"
|
||||
"postgresus-backend/internal/features/databases"
|
||||
"postgresus-backend/internal/features/notifiers"
|
||||
@@ -21,6 +22,8 @@ type BackupService struct {
|
||||
notifierService *notifiers.NotifierService
|
||||
|
||||
createBackupUseCase *usecases.CreateBackupUsecase
|
||||
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (s *BackupService) OnBeforeDbStorageChange(
|
||||
@@ -53,7 +56,7 @@ func (s *BackupService) OnBeforeDbStorageChange(
|
||||
if err := backup.Storage.DeleteFile(backup.ID); err != nil {
|
||||
// most likely we cannot do nothing with this,
|
||||
// so we just remove the backup model
|
||||
log.Error("Failed to delete backup file", "error", err)
|
||||
s.logger.Error("Failed to delete backup file", "error", err)
|
||||
}
|
||||
|
||||
if err := s.backupRepository.DeleteByID(backup.ID); err != nil {
|
||||
@@ -125,7 +128,7 @@ func (s *BackupService) DeleteBackup(
|
||||
return errors.New("backup is in progress")
|
||||
}
|
||||
|
||||
backup.DeleteBackupFromStorage()
|
||||
backup.DeleteBackupFromStorage(s.logger)
|
||||
|
||||
backup.Status = BackupStatusDeleted
|
||||
return s.backupRepository.Save(backup)
|
||||
@@ -134,24 +137,24 @@ func (s *BackupService) DeleteBackup(
|
||||
func (s *BackupService) MakeBackup(databaseID uuid.UUID) {
|
||||
database, err := s.databaseService.GetDatabaseByID(databaseID)
|
||||
if err != nil {
|
||||
log.Error("Failed to get database by ID", "error", err)
|
||||
s.logger.Error("Failed to get database by ID", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
lastBackup, err := s.backupRepository.FindLastByDatabaseID(databaseID)
|
||||
if err != nil {
|
||||
log.Error("Failed to find last backup by database ID", "error", err)
|
||||
s.logger.Error("Failed to find last backup by database ID", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
if lastBackup != nil && lastBackup.Status == BackupStatusInProgress {
|
||||
log.Error("Backup is in progress")
|
||||
s.logger.Error("Backup is in progress")
|
||||
return
|
||||
}
|
||||
|
||||
storage, err := s.storageService.GetStorageByID(database.StorageID)
|
||||
if err != nil {
|
||||
log.Error("Failed to get storage by ID", "error", err)
|
||||
s.logger.Error("Failed to get storage by ID", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -170,7 +173,7 @@ func (s *BackupService) MakeBackup(databaseID uuid.UUID) {
|
||||
}
|
||||
|
||||
if err := s.backupRepository.Save(backup); err != nil {
|
||||
log.Error("Failed to save backup", "error", err)
|
||||
s.logger.Error("Failed to save backup", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -183,7 +186,7 @@ func (s *BackupService) MakeBackup(databaseID uuid.UUID) {
|
||||
backup.BackupDurationMs = time.Since(start).Milliseconds()
|
||||
|
||||
if err := s.backupRepository.Save(backup); err != nil {
|
||||
log.Error("Failed to update backup progress", "error", err)
|
||||
s.logger.Error("Failed to update backup progress", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +204,7 @@ func (s *BackupService) MakeBackup(databaseID uuid.UUID) {
|
||||
backup.BackupSizeMb = 0
|
||||
|
||||
if updateErr := s.databaseService.SetBackupError(databaseID, errMsg); updateErr != nil {
|
||||
log.Error(
|
||||
s.logger.Error(
|
||||
"Failed to update database last backup time",
|
||||
"databaseId",
|
||||
databaseID,
|
||||
@@ -211,7 +214,7 @@ func (s *BackupService) MakeBackup(databaseID uuid.UUID) {
|
||||
}
|
||||
|
||||
if err := s.backupRepository.Save(backup); err != nil {
|
||||
log.Error("Failed to save backup", "error", err)
|
||||
s.logger.Error("Failed to save backup", "error", err)
|
||||
}
|
||||
|
||||
s.SendBackupNotification(
|
||||
@@ -228,14 +231,14 @@ func (s *BackupService) MakeBackup(databaseID uuid.UUID) {
|
||||
backup.BackupDurationMs = time.Since(start).Milliseconds()
|
||||
|
||||
if err := s.backupRepository.Save(backup); err != nil {
|
||||
log.Error("Failed to save backup", "error", err)
|
||||
s.logger.Error("Failed to save backup", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Update database last backup time
|
||||
now := time.Now().UTC()
|
||||
if updateErr := s.databaseService.SetLastBackupTime(databaseID, now); updateErr != nil {
|
||||
log.Error(
|
||||
s.logger.Error(
|
||||
"Failed to update database last backup time",
|
||||
"databaseId",
|
||||
databaseID,
|
||||
|
||||
13
backend/internal/features/backups/usecases/di.go
Normal file
13
backend/internal/features/backups/usecases/di.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package usecases
|
||||
|
||||
import (
|
||||
usecases_postgresql "postgresus-backend/internal/features/backups/usecases/postgresql"
|
||||
)
|
||||
|
||||
var createBackupUsecase = &CreateBackupUsecase{
|
||||
usecases_postgresql.GetCreatePostgresqlBackupUsecase(),
|
||||
}
|
||||
|
||||
func GetCreateBackupUsecase() *CreateBackupUsecase {
|
||||
return createBackupUsecase
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -16,15 +17,14 @@ import (
|
||||
"postgresus-backend/internal/features/databases"
|
||||
pgtypes "postgresus-backend/internal/features/databases/databases/postgresql"
|
||||
"postgresus-backend/internal/features/storages"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
"postgresus-backend/internal/util/tools"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var log = logger.GetLogger()
|
||||
|
||||
type CreatePostgresqlBackupUsecase struct{}
|
||||
type CreatePostgresqlBackupUsecase struct {
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
// Execute creates a backup of the database
|
||||
func (uc *CreatePostgresqlBackupUsecase) Execute(
|
||||
@@ -35,7 +35,7 @@ func (uc *CreatePostgresqlBackupUsecase) Execute(
|
||||
completedMBs float64,
|
||||
),
|
||||
) error {
|
||||
log.Info(
|
||||
uc.logger.Info(
|
||||
"Creating PostgreSQL backup via pg_dump custom format",
|
||||
"databaseId",
|
||||
db.ID,
|
||||
@@ -85,7 +85,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage(
|
||||
db *databases.Database,
|
||||
backupProgressListener func(completedMBs float64),
|
||||
) error {
|
||||
log.Info("Streaming PostgreSQL backup to storage", "pgBin", pgBin, "args", args)
|
||||
uc.logger.Info("Streaming PostgreSQL backup to storage", "pgBin", pgBin, "args", args)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Minute)
|
||||
defer cancel()
|
||||
@@ -126,7 +126,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage(
|
||||
|
||||
// Verify .pgpass file was created correctly
|
||||
if info, err := os.Stat(pgpassFile); err == nil {
|
||||
log.Info("Temporary .pgpass file created successfully",
|
||||
uc.logger.Info("Temporary .pgpass file created successfully",
|
||||
"pgpassFile", pgpassFile,
|
||||
"size", info.Size(),
|
||||
"mode", info.Mode(),
|
||||
@@ -136,17 +136,17 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage(
|
||||
}
|
||||
|
||||
cmd := exec.CommandContext(ctx, pgBin, args...)
|
||||
log.Info("Executing PostgreSQL backup command", "command", cmd.String())
|
||||
uc.logger.Info("Executing PostgreSQL backup command", "command", cmd.String())
|
||||
|
||||
// Start with system environment variables to preserve Windows PATH, SystemRoot, etc.
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
// Use the .pgpass file for authentication
|
||||
cmd.Env = append(cmd.Env, "PGPASSFILE="+pgpassFile)
|
||||
log.Info("Using temporary .pgpass file for authentication", "pgpassFile", pgpassFile)
|
||||
uc.logger.Info("Using temporary .pgpass file for authentication", "pgpassFile", pgpassFile)
|
||||
|
||||
// Debug password setup (without exposing the actual password)
|
||||
log.Info("Setting up PostgreSQL environment",
|
||||
uc.logger.Info("Setting up PostgreSQL environment",
|
||||
"passwordLength", len(password),
|
||||
"passwordEmpty", password == "",
|
||||
"pgBin", pgBin,
|
||||
@@ -170,11 +170,11 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage(
|
||||
// Require SSL when explicitly configured
|
||||
if shouldRequireSSL {
|
||||
cmd.Env = append(cmd.Env, "PGSSLMODE=require")
|
||||
log.Info("Using required SSL mode", "configuredHttps", db.Postgresql.IsHttps)
|
||||
uc.logger.Info("Using required SSL mode", "configuredHttps", db.Postgresql.IsHttps)
|
||||
} else {
|
||||
// SSL not explicitly required, but prefer it if available
|
||||
cmd.Env = append(cmd.Env, "PGSSLMODE=prefer")
|
||||
log.Info("Using preferred SSL mode", "configuredHttps", db.Postgresql.IsHttps)
|
||||
uc.logger.Info("Using preferred SSL mode", "configuredHttps", db.Postgresql.IsHttps)
|
||||
}
|
||||
|
||||
// Set other SSL parameters to avoid certificate issues
|
||||
@@ -220,7 +220,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage(
|
||||
// Start streaming into storage in its own goroutine
|
||||
saveErrCh := make(chan error, 1)
|
||||
go func() {
|
||||
saveErrCh <- storage.SaveFile(backupID, storageReader)
|
||||
saveErrCh <- storage.SaveFile(uc.logger, backupID, storageReader)
|
||||
}()
|
||||
|
||||
// Start pg_dump
|
||||
@@ -251,7 +251,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage(
|
||||
if config.IsShouldShutdown() {
|
||||
if pipeWriter, ok := countingWriter.writer.(*io.PipeWriter); ok {
|
||||
if err := pipeWriter.Close(); err != nil {
|
||||
log.Error("Failed to close counting writer", "error", err)
|
||||
uc.logger.Error("Failed to close counting writer", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage(
|
||||
// Close the pipe writer to signal end of data
|
||||
if pipeWriter, ok := countingWriter.writer.(*io.PipeWriter); ok {
|
||||
if err := pipeWriter.Close(); err != nil {
|
||||
log.Error("Failed to close counting writer", "error", err)
|
||||
uc.logger.Error("Failed to close counting writer", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage(
|
||||
|
||||
// Enhanced debugging for exit status 1 with empty stderr
|
||||
if exitCode == 1 && strings.TrimSpace(stderrStr) == "" {
|
||||
log.Error("pg_dump failed with exit status 1 but no stderr output",
|
||||
uc.logger.Error("pg_dump failed with exit status 1 but no stderr output",
|
||||
"pgBin", pgBin,
|
||||
"args", args,
|
||||
"env_vars", []string{
|
||||
@@ -323,7 +323,7 @@ func (uc *CreatePostgresqlBackupUsecase) streamToStorage(
|
||||
strings.Join(args, " "),
|
||||
)
|
||||
} else if exitCode == -1073741819 { // 0xC0000005 in decimal
|
||||
log.Error("PostgreSQL tool crashed with access violation",
|
||||
uc.logger.Error("PostgreSQL tool crashed with access violation",
|
||||
"pgBin", pgBin,
|
||||
"args", args,
|
||||
"exitCode", fmt.Sprintf("0x%X", uint32(exitCode)),
|
||||
|
||||
13
backend/internal/features/backups/usecases/postgresql/di.go
Normal file
13
backend/internal/features/backups/usecases/postgresql/di.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package usecases_postgresql
|
||||
|
||||
import (
|
||||
"postgresus-backend/internal/util/logger"
|
||||
)
|
||||
|
||||
var createPostgresqlBackupUsecase = &CreatePostgresqlBackupUsecase{
|
||||
logger.GetLogger(),
|
||||
}
|
||||
|
||||
func GetCreatePostgresqlBackupUsecase() *CreatePostgresqlBackupUsecase {
|
||||
return createPostgresqlBackupUsecase
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
"log/slog"
|
||||
"postgresus-backend/internal/util/tools"
|
||||
"time"
|
||||
|
||||
@@ -12,8 +12,6 @@ import (
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
var log = logger.GetLogger()
|
||||
|
||||
type PostgresqlDatabase struct {
|
||||
ID uuid.UUID `json:"id" gorm:"primaryKey;type:uuid;default:gen_random_uuid()"`
|
||||
|
||||
@@ -61,15 +59,19 @@ func (p *PostgresqlDatabase) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PostgresqlDatabase) TestConnection() error {
|
||||
func (p *PostgresqlDatabase) TestConnection(logger *slog.Logger) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
return testSingleDatabaseConnection(ctx, p)
|
||||
return testSingleDatabaseConnection(logger, ctx, p)
|
||||
}
|
||||
|
||||
// testSingleDatabaseConnection tests connection to a specific database for pg_dump
|
||||
func testSingleDatabaseConnection(ctx context.Context, p *PostgresqlDatabase) error {
|
||||
func testSingleDatabaseConnection(
|
||||
logger *slog.Logger,
|
||||
ctx context.Context,
|
||||
p *PostgresqlDatabase,
|
||||
) error {
|
||||
// For single database backup, we need to connect to the specific database
|
||||
if p.Database == nil || *p.Database == "" {
|
||||
return errors.New("database name is required for single database backup (pg_dump)")
|
||||
@@ -89,7 +91,7 @@ func testSingleDatabaseConnection(ctx context.Context, p *PostgresqlDatabase) er
|
||||
}
|
||||
defer func() {
|
||||
if closeErr := conn.Close(ctx); closeErr != nil {
|
||||
log.Error("Failed to close connection", "error", closeErr)
|
||||
logger.Error("Failed to close connection", "error", closeErr)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package databases
|
||||
|
||||
import "postgresus-backend/internal/features/users"
|
||||
import (
|
||||
"postgresus-backend/internal/features/users"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
)
|
||||
|
||||
var databaseRepository = &DatabaseRepository{}
|
||||
|
||||
var databaseService = &DatabaseService{
|
||||
databaseRepository,
|
||||
nil,
|
||||
logger.GetLogger(),
|
||||
}
|
||||
|
||||
var databaseController = &DatabaseController{
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package databases
|
||||
|
||||
import "github.com/google/uuid"
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type DatabaseValidator interface {
|
||||
Validate() error
|
||||
}
|
||||
|
||||
type DatabaseConnector interface {
|
||||
TestConnection() error
|
||||
TestConnection(logger *slog.Logger) error
|
||||
}
|
||||
|
||||
type DatabaseStorageChangeListener interface {
|
||||
|
||||
@@ -2,6 +2,7 @@ package databases
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"postgresus-backend/internal/features/databases/databases/postgresql"
|
||||
"postgresus-backend/internal/features/intervals"
|
||||
"postgresus-backend/internal/features/notifiers"
|
||||
@@ -102,8 +103,8 @@ func (d *Database) ValidateUpdate(old, new Database) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) TestConnection() error {
|
||||
return d.getSpecificDatabase().TestConnection()
|
||||
func (d *Database) TestConnection(logger *slog.Logger) error {
|
||||
return d.getSpecificDatabase().TestConnection(logger)
|
||||
}
|
||||
|
||||
func (d *Database) getSpecificDatabase() DatabaseConnector {
|
||||
|
||||
@@ -2,6 +2,7 @@ package databases
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
users_models "postgresus-backend/internal/features/users/models"
|
||||
"time"
|
||||
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
type DatabaseService struct {
|
||||
dbRepository *DatabaseRepository
|
||||
dbStorageChangeListener DatabaseStorageChangeListener
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (s *DatabaseService) SetDatabaseStorageChangeListener(
|
||||
@@ -131,7 +133,7 @@ func (s *DatabaseService) TestDatabaseConnection(
|
||||
return errors.New("you have not access to this database")
|
||||
}
|
||||
|
||||
err = database.TestConnection()
|
||||
err = database.TestConnection(s.logger)
|
||||
if err != nil {
|
||||
lastSaveError := err.Error()
|
||||
database.LastBackupErrorMessage = &lastSaveError
|
||||
@@ -146,7 +148,7 @@ func (s *DatabaseService) TestDatabaseConnection(
|
||||
func (s *DatabaseService) TestDatabaseConnectionDirect(
|
||||
database *Database,
|
||||
) error {
|
||||
return database.TestConnection()
|
||||
return database.TestConnection(s.logger)
|
||||
}
|
||||
|
||||
func (s *DatabaseService) GetDatabaseByID(
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package notifiers
|
||||
|
||||
import "postgresus-backend/internal/features/users"
|
||||
import (
|
||||
"postgresus-backend/internal/features/users"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
)
|
||||
|
||||
var notifierRepository = &NotifierRepository{}
|
||||
var notifierService = &NotifierService{
|
||||
notifierRepository,
|
||||
logger.GetLogger(),
|
||||
}
|
||||
var notifierController = &NotifierController{
|
||||
notifierService,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package notifiers
|
||||
|
||||
import "log/slog"
|
||||
|
||||
type NotificationSender interface {
|
||||
Send(heading string, message string) error
|
||||
Send(logger *slog.Logger, heading string, message string) error
|
||||
|
||||
Validate() error
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package notifiers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"postgresus-backend/internal/features/notifiers/notifiers/email_notifier"
|
||||
telegram_notifier "postgresus-backend/internal/features/notifiers/notifiers/telegram"
|
||||
webhook_notifier "postgresus-backend/internal/features/notifiers/notifiers/webhook"
|
||||
@@ -34,8 +35,8 @@ func (n *Notifier) Validate() error {
|
||||
return n.getSpecificNotifier().Validate()
|
||||
}
|
||||
|
||||
func (n *Notifier) Send(heading string, message string) error {
|
||||
err := n.getSpecificNotifier().Send(heading, message)
|
||||
func (n *Notifier) Send(logger *slog.Logger, heading string, message string) error {
|
||||
err := n.getSpecificNotifier().Send(logger, heading, message)
|
||||
|
||||
if err != nil {
|
||||
lastSendError := err.Error()
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/smtp"
|
||||
"time"
|
||||
@@ -56,7 +57,7 @@ func (e *EmailNotifier) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *EmailNotifier) Send(heading string, message string) error {
|
||||
func (e *EmailNotifier) Send(logger *slog.Logger, heading string, message string) error {
|
||||
// Compose email
|
||||
from := e.SMTPUser
|
||||
to := []string{e.TargetEmail}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -33,7 +34,7 @@ func (t *TelegramNotifier) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TelegramNotifier) Send(heading string, message string) error {
|
||||
func (t *TelegramNotifier) Send(logger *slog.Logger, heading string, message string) error {
|
||||
fullMessage := heading
|
||||
if message != "" {
|
||||
fullMessage = fmt.Sprintf("%s\n\n%s", heading, message)
|
||||
|
||||
@@ -6,15 +6,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var log = logger.GetLogger()
|
||||
|
||||
type WebhookNotifier struct {
|
||||
NotifierID uuid.UUID `json:"notifierId" gorm:"primaryKey;column:notifier_id"`
|
||||
WebhookURL string `json:"webhookUrl" gorm:"not null;column:webhook_url"`
|
||||
@@ -37,7 +35,7 @@ func (t *WebhookNotifier) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *WebhookNotifier) Send(heading string, message string) error {
|
||||
func (t *WebhookNotifier) Send(logger *slog.Logger, heading string, message string) error {
|
||||
switch t.WebhookMethod {
|
||||
case WebhookMethodGET:
|
||||
reqURL := fmt.Sprintf("%s?heading=%s&message=%s",
|
||||
@@ -52,7 +50,7 @@ func (t *WebhookNotifier) Send(heading string, message string) error {
|
||||
}
|
||||
defer func() {
|
||||
if cerr := resp.Body.Close(); cerr != nil {
|
||||
log.Error("failed to close response body", "error", cerr)
|
||||
logger.Error("failed to close response body", "error", cerr)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -85,7 +83,7 @@ func (t *WebhookNotifier) Send(heading string, message string) error {
|
||||
|
||||
defer func() {
|
||||
if cerr := resp.Body.Close(); cerr != nil {
|
||||
log.Error("failed to close response body", "error", cerr)
|
||||
logger.Error("failed to close response body", "error", cerr)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -2,16 +2,15 @@ package notifiers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
users_models "postgresus-backend/internal/features/users/models"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var log = logger.GetLogger()
|
||||
|
||||
type NotifierService struct {
|
||||
notifierRepository *NotifierRepository
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (s *NotifierService) SaveNotifier(
|
||||
@@ -87,7 +86,7 @@ func (s *NotifierService) SendTestNotification(
|
||||
return errors.New("you have not access to this notifier")
|
||||
}
|
||||
|
||||
err = notifier.Send("Test message", "This is a test message")
|
||||
err = notifier.Send(s.logger, "Test message", "This is a test message")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -102,7 +101,7 @@ func (s *NotifierService) SendTestNotification(
|
||||
func (s *NotifierService) SendTestNotificationToNotifier(
|
||||
notifier *Notifier,
|
||||
) error {
|
||||
return notifier.Send("Test message", "This is a test message")
|
||||
return notifier.Send(s.logger, "Test message", "This is a test message")
|
||||
}
|
||||
|
||||
func (s *NotifierService) SendNotification(
|
||||
@@ -121,20 +120,20 @@ func (s *NotifierService) SendNotification(
|
||||
return
|
||||
}
|
||||
|
||||
err = notifiedFromDb.Send(title, message)
|
||||
err = notifiedFromDb.Send(s.logger, title, message)
|
||||
if err != nil {
|
||||
errMsg := err.Error()
|
||||
notifiedFromDb.LastSendError = &errMsg
|
||||
|
||||
err = s.notifierRepository.Save(notifiedFromDb)
|
||||
if err != nil {
|
||||
log.Error("Failed to save notifier", "error", err)
|
||||
s.logger.Error("Failed to save notifier", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
notifiedFromDb.LastSendError = nil
|
||||
err = s.notifierRepository.Save(notifiedFromDb)
|
||||
if err != nil {
|
||||
log.Error("Failed to save notifier", "error", err)
|
||||
s.logger.Error("Failed to save notifier", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
package restores
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"postgresus-backend/internal/features/restores/enums"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
)
|
||||
|
||||
var log = logger.GetLogger()
|
||||
|
||||
type RestoreBackgroundService struct {
|
||||
restoreRepository *RestoreRepository
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (s *RestoreBackgroundService) Run() {
|
||||
if err := s.failRestoresInProgress(); err != nil {
|
||||
log.Error("Failed to fail restores in progress", "error", err)
|
||||
s.logger.Error("Failed to fail restores in progress", "error", err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,16 @@ import (
|
||||
"postgresus-backend/internal/features/restores/usecases"
|
||||
"postgresus-backend/internal/features/storages"
|
||||
"postgresus-backend/internal/features/users"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
)
|
||||
|
||||
var restoreBackupUsecase = &usecases.RestoreBackupUsecase{}
|
||||
var restoreRepository = &RestoreRepository{}
|
||||
var restoreService = &RestoreService{
|
||||
backups.GetBackupService(),
|
||||
restoreRepository,
|
||||
storages.GetStorageService(),
|
||||
restoreBackupUsecase,
|
||||
usecases.GetRestoreBackupUsecase(),
|
||||
logger.GetLogger(),
|
||||
}
|
||||
var restoreController = &RestoreController{
|
||||
restoreService,
|
||||
@@ -22,6 +23,7 @@ var restoreController = &RestoreController{
|
||||
|
||||
var restoreBackgroundService = &RestoreBackgroundService{
|
||||
restoreRepository,
|
||||
logger.GetLogger(),
|
||||
}
|
||||
|
||||
func GetRestoreController() *RestoreController {
|
||||
|
||||
@@ -2,6 +2,7 @@ package restores
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"postgresus-backend/internal/features/backups"
|
||||
"postgresus-backend/internal/features/databases"
|
||||
"postgresus-backend/internal/features/restores/enums"
|
||||
@@ -19,6 +20,7 @@ type RestoreService struct {
|
||||
restoreRepository *RestoreRepository
|
||||
storageService *storages.StorageService
|
||||
restoreBackupUsecase *usecases.RestoreBackupUsecase
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (s *RestoreService) GetRestores(
|
||||
@@ -53,7 +55,7 @@ func (s *RestoreService) RestoreBackupWithAuth(
|
||||
|
||||
go func() {
|
||||
if err := s.RestoreBackup(backup, requestDTO); err != nil {
|
||||
log.Error("Failed to restore backup", "error", err)
|
||||
s.logger.Error("Failed to restore backup", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
13
backend/internal/features/restores/usecases/di.go
Normal file
13
backend/internal/features/restores/usecases/di.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package usecases
|
||||
|
||||
import (
|
||||
usecases_postgresql "postgresus-backend/internal/features/restores/usecases/postgresql"
|
||||
)
|
||||
|
||||
var restoreBackupUsecase = &RestoreBackupUsecase{
|
||||
usecases_postgresql.GetRestorePostgresqlBackupUsecase(),
|
||||
}
|
||||
|
||||
func GetRestoreBackupUsecase() *RestoreBackupUsecase {
|
||||
return restoreBackupUsecase
|
||||
}
|
||||
13
backend/internal/features/restores/usecases/postgresql/di.go
Normal file
13
backend/internal/features/restores/usecases/postgresql/di.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package usecases_postgresql
|
||||
|
||||
import (
|
||||
"postgresus-backend/internal/util/logger"
|
||||
)
|
||||
|
||||
var restorePostgresqlBackupUsecase = &RestorePostgresqlBackupUsecase{
|
||||
logger.GetLogger(),
|
||||
}
|
||||
|
||||
func GetRestorePostgresqlBackupUsecase() *RestorePostgresqlBackupUsecase {
|
||||
return restorePostgresqlBackupUsecase
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -18,15 +19,14 @@ import (
|
||||
pgtypes "postgresus-backend/internal/features/databases/databases/postgresql"
|
||||
"postgresus-backend/internal/features/restores/models"
|
||||
"postgresus-backend/internal/features/storages"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
"postgresus-backend/internal/util/tools"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var log = logger.GetLogger()
|
||||
|
||||
type RestorePostgresqlBackupUsecase struct{}
|
||||
type RestorePostgresqlBackupUsecase struct {
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (uc *RestorePostgresqlBackupUsecase) Execute(
|
||||
restore models.Restore,
|
||||
@@ -37,7 +37,7 @@ func (uc *RestorePostgresqlBackupUsecase) Execute(
|
||||
return errors.New("database type not supported")
|
||||
}
|
||||
|
||||
log.Info(
|
||||
uc.logger.Info(
|
||||
"Restoring PostgreSQL backup via pg_restore",
|
||||
"restoreId",
|
||||
restore.ID,
|
||||
@@ -96,7 +96,7 @@ func (uc *RestorePostgresqlBackupUsecase) restoreFromStorage(
|
||||
storage *storages.Storage,
|
||||
pgConfig *pgtypes.PostgresqlDatabase,
|
||||
) error {
|
||||
log.Info(
|
||||
uc.logger.Info(
|
||||
"Restoring PostgreSQL backup from storage via temporary file",
|
||||
"pgBin",
|
||||
pgBin,
|
||||
@@ -142,7 +142,7 @@ func (uc *RestorePostgresqlBackupUsecase) restoreFromStorage(
|
||||
}
|
||||
|
||||
if info, err := os.Stat(pgpassFile); err == nil {
|
||||
log.Info("Temporary .pgpass file created successfully",
|
||||
uc.logger.Info("Temporary .pgpass file created successfully",
|
||||
"pgpassFile", pgpassFile,
|
||||
"size", info.Size(),
|
||||
"mode", info.Mode(),
|
||||
@@ -183,7 +183,7 @@ func (uc *RestorePostgresqlBackupUsecase) downloadBackupToTempFile(
|
||||
tempBackupFile := filepath.Join(tempDir, "backup.dump")
|
||||
|
||||
// Get backup data from storage
|
||||
log.Info(
|
||||
uc.logger.Info(
|
||||
"Downloading backup file from storage to temporary file",
|
||||
"backupId",
|
||||
backup.ID,
|
||||
@@ -197,7 +197,7 @@ func (uc *RestorePostgresqlBackupUsecase) downloadBackupToTempFile(
|
||||
}
|
||||
defer func() {
|
||||
if err := backupReader.Close(); err != nil {
|
||||
log.Error("Failed to close backup reader", "error", err)
|
||||
uc.logger.Error("Failed to close backup reader", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -209,7 +209,7 @@ func (uc *RestorePostgresqlBackupUsecase) downloadBackupToTempFile(
|
||||
}
|
||||
defer func() {
|
||||
if err := tempFile.Close(); err != nil {
|
||||
log.Error("Failed to close temporary file", "error", err)
|
||||
uc.logger.Error("Failed to close temporary file", "error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -226,7 +226,7 @@ func (uc *RestorePostgresqlBackupUsecase) downloadBackupToTempFile(
|
||||
return "", nil, fmt.Errorf("failed to close temporary backup file: %w", err)
|
||||
}
|
||||
|
||||
log.Info("Backup file written to temporary location", "tempFile", tempBackupFile)
|
||||
uc.logger.Info("Backup file written to temporary location", "tempFile", tempBackupFile)
|
||||
return tempBackupFile, cleanupFunc, nil
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ func (uc *RestorePostgresqlBackupUsecase) executePgRestore(
|
||||
pgConfig *pgtypes.PostgresqlDatabase,
|
||||
) error {
|
||||
cmd := exec.CommandContext(ctx, pgBin, args...)
|
||||
log.Info("Executing PostgreSQL restore command", "command", cmd.String())
|
||||
uc.logger.Info("Executing PostgreSQL restore command", "command", cmd.String())
|
||||
|
||||
// Setup environment variables
|
||||
uc.setupPgRestoreEnvironment(cmd, pgpassFile, pgConfig)
|
||||
@@ -302,7 +302,7 @@ func (uc *RestorePostgresqlBackupUsecase) setupPgRestoreEnvironment(
|
||||
|
||||
// Use the .pgpass file for authentication
|
||||
cmd.Env = append(cmd.Env, "PGPASSFILE="+pgpassFile)
|
||||
log.Info("Using temporary .pgpass file for authentication", "pgpassFile", pgpassFile)
|
||||
uc.logger.Info("Using temporary .pgpass file for authentication", "pgpassFile", pgpassFile)
|
||||
|
||||
// Add PostgreSQL-specific environment variables
|
||||
cmd.Env = append(cmd.Env, "PGCLIENTENCODING=UTF8")
|
||||
@@ -318,10 +318,10 @@ func (uc *RestorePostgresqlBackupUsecase) setupPgRestoreEnvironment(
|
||||
// Configure SSL settings
|
||||
if shouldRequireSSL {
|
||||
cmd.Env = append(cmd.Env, "PGSSLMODE=require")
|
||||
log.Info("Using required SSL mode", "configuredHttps", pgConfig.IsHttps)
|
||||
uc.logger.Info("Using required SSL mode", "configuredHttps", pgConfig.IsHttps)
|
||||
} else {
|
||||
cmd.Env = append(cmd.Env, "PGSSLMODE=prefer")
|
||||
log.Info("Using preferred SSL mode", "configuredHttps", pgConfig.IsHttps)
|
||||
uc.logger.Info("Using preferred SSL mode", "configuredHttps", pgConfig.IsHttps)
|
||||
}
|
||||
|
||||
// Set other SSL parameters to avoid certificate issues
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
type RestoreBackupUsecase struct {
|
||||
RestorePostgresqlBackupUsecase *usecases_postgresql.RestorePostgresqlBackupUsecase
|
||||
restorePostgresqlBackupUsecase *usecases_postgresql.RestorePostgresqlBackupUsecase
|
||||
}
|
||||
|
||||
func (uc *RestoreBackupUsecase) Execute(
|
||||
@@ -19,7 +19,7 @@ func (uc *RestoreBackupUsecase) Execute(
|
||||
storage *storages.Storage,
|
||||
) error {
|
||||
if restore.Backup.Database.Type == databases.DatabaseTypePostgres {
|
||||
return uc.RestorePostgresqlBackupUsecase.Execute(restore, backup, storage)
|
||||
return uc.restorePostgresqlBackupUsecase.Execute(restore, backup, storage)
|
||||
}
|
||||
|
||||
return errors.New("database type not supported")
|
||||
|
||||
@@ -2,12 +2,13 @@ package storages
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log/slog"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type StorageFileSaver interface {
|
||||
SaveFile(fileID uuid.UUID, file io.Reader) error
|
||||
SaveFile(logger *slog.Logger, fileID uuid.UUID, file io.Reader) error
|
||||
|
||||
GetFile(fileID uuid.UUID) (io.ReadCloser, error)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package storages
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"log/slog"
|
||||
local_storage "postgresus-backend/internal/features/storages/storages/local"
|
||||
s3_storage "postgresus-backend/internal/features/storages/storages/s3"
|
||||
|
||||
@@ -21,8 +22,8 @@ type Storage struct {
|
||||
S3Storage *s3_storage.S3Storage `json:"s3Storage" gorm:"foreignKey:StorageID"`
|
||||
}
|
||||
|
||||
func (s *Storage) SaveFile(fileID uuid.UUID, file io.Reader) error {
|
||||
err := s.getSpecificStorage().SaveFile(fileID, file)
|
||||
func (s *Storage) SaveFile(logger *slog.Logger, fileID uuid.UUID, file io.Reader) error {
|
||||
err := s.getSpecificStorage().SaveFile(logger, fileID, file)
|
||||
if err != nil {
|
||||
lastSaveError := err.Error()
|
||||
s.LastSaveError = &lastSaveError
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
local_storage "postgresus-backend/internal/features/storages/storages/local"
|
||||
s3_storage "postgresus-backend/internal/features/storages/storages/s3"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -87,7 +88,7 @@ func Test_Storage_BasicOperations(t *testing.T) {
|
||||
|
||||
fileID := uuid.New()
|
||||
|
||||
err = tc.storage.SaveFile(fileID, bytes.NewReader(fileData))
|
||||
err = tc.storage.SaveFile(logger.GetLogger(), fileID, bytes.NewReader(fileData))
|
||||
require.NoError(t, err, "SaveFile should succeed")
|
||||
|
||||
file, err := tc.storage.GetFile(fileID)
|
||||
@@ -104,7 +105,7 @@ func Test_Storage_BasicOperations(t *testing.T) {
|
||||
require.NoError(t, err, "Should be able to read test file")
|
||||
|
||||
fileID := uuid.New()
|
||||
err = tc.storage.SaveFile(fileID, bytes.NewReader(fileData))
|
||||
err = tc.storage.SaveFile(logger.GetLogger(), fileID, bytes.NewReader(fileData))
|
||||
require.NoError(t, err, "SaveFile should succeed")
|
||||
|
||||
err = tc.storage.DeleteFile(fileID)
|
||||
|
||||
@@ -3,16 +3,14 @@ package local_storage
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"postgresus-backend/internal/config"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var log = logger.GetLogger()
|
||||
|
||||
// LocalStorage uses ./postgresus_local_backups folder as a
|
||||
// directory for backups and ./postgresus_local_temp folder as a
|
||||
// directory for temp files
|
||||
@@ -24,20 +22,20 @@ func (l *LocalStorage) TableName() string {
|
||||
return "local_storages"
|
||||
}
|
||||
|
||||
func (l *LocalStorage) SaveFile(fileID uuid.UUID, file io.Reader) error {
|
||||
log.Info("Starting to save file to local storage", "fileId", fileID.String())
|
||||
func (l *LocalStorage) SaveFile(logger *slog.Logger, fileID uuid.UUID, file io.Reader) error {
|
||||
logger.Info("Starting to save file to local storage", "fileId", fileID.String())
|
||||
|
||||
if err := l.ensureDirectories(); err != nil {
|
||||
log.Error("Failed to ensure directories", "fileId", fileID.String(), "error", err)
|
||||
logger.Error("Failed to ensure directories", "fileId", fileID.String(), "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
tempFilePath := filepath.Join(config.GetEnv().TempFolder, fileID.String())
|
||||
log.Debug("Creating temp file", "fileId", fileID.String(), "tempPath", tempFilePath)
|
||||
logger.Debug("Creating temp file", "fileId", fileID.String(), "tempPath", tempFilePath)
|
||||
|
||||
tempFile, err := os.Create(tempFilePath)
|
||||
if err != nil {
|
||||
log.Error(
|
||||
logger.Error(
|
||||
"Failed to create temp file",
|
||||
"fileId",
|
||||
fileID.String(),
|
||||
@@ -52,26 +50,26 @@ func (l *LocalStorage) SaveFile(fileID uuid.UUID, file io.Reader) error {
|
||||
_ = tempFile.Close()
|
||||
}()
|
||||
|
||||
log.Debug("Copying file data to temp file", "fileId", fileID.String())
|
||||
logger.Debug("Copying file data to temp file", "fileId", fileID.String())
|
||||
_, err = io.Copy(tempFile, file)
|
||||
if err != nil {
|
||||
log.Error("Failed to write to temp file", "fileId", fileID.String(), "error", err)
|
||||
logger.Error("Failed to write to temp file", "fileId", fileID.String(), "error", err)
|
||||
return fmt.Errorf("failed to write to temp file: %w", err)
|
||||
}
|
||||
|
||||
if err = tempFile.Sync(); err != nil {
|
||||
log.Error("Failed to sync temp file", "fileId", fileID.String(), "error", err)
|
||||
logger.Error("Failed to sync temp file", "fileId", fileID.String(), "error", err)
|
||||
return fmt.Errorf("failed to sync temp file: %w", err)
|
||||
}
|
||||
|
||||
err = tempFile.Close()
|
||||
if err != nil {
|
||||
log.Error("Failed to close temp file", "fileId", fileID.String(), "error", err)
|
||||
logger.Error("Failed to close temp file", "fileId", fileID.String(), "error", err)
|
||||
return fmt.Errorf("failed to close temp file: %w", err)
|
||||
}
|
||||
|
||||
finalPath := filepath.Join(config.GetEnv().DataFolder, fileID.String())
|
||||
log.Debug(
|
||||
logger.Debug(
|
||||
"Moving file from temp to final location",
|
||||
"fileId",
|
||||
fileID.String(),
|
||||
@@ -81,7 +79,7 @@ func (l *LocalStorage) SaveFile(fileID uuid.UUID, file io.Reader) error {
|
||||
|
||||
// Move the file from temp to backups directory
|
||||
if err = os.Rename(tempFilePath, finalPath); err != nil {
|
||||
log.Error(
|
||||
logger.Error(
|
||||
"Failed to move file from temp to backups",
|
||||
"fileId",
|
||||
fileID.String(),
|
||||
@@ -95,7 +93,7 @@ func (l *LocalStorage) SaveFile(fileID uuid.UUID, file io.Reader) error {
|
||||
return fmt.Errorf("failed to move file from temp to backups: %w", err)
|
||||
}
|
||||
|
||||
log.Info(
|
||||
logger.Info(
|
||||
"Successfully saved file to local storage",
|
||||
"fileId",
|
||||
fileID.String(),
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -27,7 +28,7 @@ func (s *S3Storage) TableName() string {
|
||||
return "s3_storages"
|
||||
}
|
||||
|
||||
func (s *S3Storage) SaveFile(fileID uuid.UUID, file io.Reader) error {
|
||||
func (s *S3Storage) SaveFile(logger *slog.Logger, fileID uuid.UUID, file io.Reader) error {
|
||||
client, err := s.getClient()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -128,9 +128,13 @@ func testBackupRestoreForVersion(t *testing.T, pgVersion string) {
|
||||
}
|
||||
|
||||
// Make backup
|
||||
createBackupUC := &usecases_postgresql_backup.CreatePostgresqlBackupUsecase{}
|
||||
progressTracker := func(completedMBs float64) {}
|
||||
err = createBackupUC.Execute(backupID, backupDbConfig, storage, progressTracker)
|
||||
err = usecases_postgresql_backup.GetCreatePostgresqlBackupUsecase().Execute(
|
||||
backupID,
|
||||
backupDbConfig,
|
||||
storage,
|
||||
progressTracker,
|
||||
)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Create new database
|
||||
@@ -173,7 +177,7 @@ func testBackupRestoreForVersion(t *testing.T, pgVersion string) {
|
||||
}
|
||||
|
||||
// Restore the backup
|
||||
restoreBackupUC := &usecases_postgresql_restore.RestorePostgresqlBackupUsecase{}
|
||||
restoreBackupUC := usecases_postgresql_restore.GetRestorePostgresqlBackupUsecase()
|
||||
err = restoreBackupUC.Execute(restore, completedBackup, storage)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
@@ -2,16 +2,14 @@ package tools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
env_utils "postgresus-backend/internal/util/env"
|
||||
"postgresus-backend/internal/util/logger"
|
||||
)
|
||||
|
||||
var log = logger.GetLogger()
|
||||
|
||||
// GetPostgresqlExecutable returns the full path to a specific PostgreSQL executable
|
||||
// for the given version. Common executables include: pg_dump, psql, etc.
|
||||
// On Windows, automatically appends .exe extension.
|
||||
@@ -37,7 +35,11 @@ func GetPostgresqlExecutable(
|
||||
// client tools (pg_dump, psql) available.
|
||||
// In development: ./tools/postgresql/postgresql-{VERSION}/bin
|
||||
// In production: /usr/pgsql-{VERSION}/bin
|
||||
func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDir string) {
|
||||
func VerifyPostgresesInstallation(
|
||||
logger *slog.Logger,
|
||||
envMode env_utils.EnvMode,
|
||||
postgresesInstallDir string,
|
||||
) {
|
||||
versions := []PostgresqlVersion{
|
||||
PostgresqlVersion13,
|
||||
PostgresqlVersion14,
|
||||
@@ -54,7 +56,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi
|
||||
for _, version := range versions {
|
||||
binDir := getPostgresqlBasePath(version, envMode, postgresesInstallDir)
|
||||
|
||||
log.Info(
|
||||
logger.Info(
|
||||
"Verifying PostgreSQL installation",
|
||||
"version",
|
||||
string(version),
|
||||
@@ -64,7 +66,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi
|
||||
|
||||
if _, err := os.Stat(binDir); os.IsNotExist(err) {
|
||||
if envMode == env_utils.EnvModeDevelopment {
|
||||
log.Error(
|
||||
logger.Error(
|
||||
"PostgreSQL bin directory not found. Make sure PostgreSQL is installed. Read ./tools/readme.md for details",
|
||||
"version",
|
||||
string(version),
|
||||
@@ -72,7 +74,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi
|
||||
binDir,
|
||||
)
|
||||
} else {
|
||||
log.Error(
|
||||
logger.Error(
|
||||
"PostgreSQL bin directory not found. Please ensure PostgreSQL client tools are installed.",
|
||||
"version",
|
||||
string(version),
|
||||
@@ -91,7 +93,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi
|
||||
postgresesInstallDir,
|
||||
)
|
||||
|
||||
log.Info(
|
||||
logger.Info(
|
||||
"Checking for PostgreSQL command",
|
||||
"command",
|
||||
cmd,
|
||||
@@ -103,7 +105,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi
|
||||
|
||||
if _, err := os.Stat(cmdPath); os.IsNotExist(err) {
|
||||
if envMode == env_utils.EnvModeDevelopment {
|
||||
log.Error(
|
||||
logger.Error(
|
||||
"PostgreSQL command not found. Make sure PostgreSQL is installed. Read ./tools/readme.md for details",
|
||||
"command",
|
||||
cmd,
|
||||
@@ -113,7 +115,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi
|
||||
cmdPath,
|
||||
)
|
||||
} else {
|
||||
log.Error(
|
||||
logger.Error(
|
||||
"PostgreSQL command not found. Please ensure PostgreSQL client tools are properly installed.",
|
||||
"command",
|
||||
cmd,
|
||||
@@ -126,7 +128,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
log.Info(
|
||||
logger.Info(
|
||||
"PostgreSQL command found",
|
||||
"command",
|
||||
cmd,
|
||||
@@ -135,7 +137,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi
|
||||
)
|
||||
}
|
||||
|
||||
log.Info(
|
||||
logger.Info(
|
||||
"Installation of PostgreSQL verified",
|
||||
"version",
|
||||
string(version),
|
||||
@@ -144,7 +146,7 @@ func VerifyPostgresesInstallation(envMode env_utils.EnvMode, postgresesInstallDi
|
||||
)
|
||||
}
|
||||
|
||||
log.Info("All PostgreSQL version-specific client tools verification completed successfully!")
|
||||
logger.Info("All PostgreSQL version-specific client tools verification completed successfully!")
|
||||
}
|
||||
|
||||
func getPostgresqlBasePath(
|
||||
|
||||
Reference in New Issue
Block a user