update and bugfix deployment

This commit is contained in:
2026-01-18 21:47:05 +01:00
parent 114a3e38b0
commit 0da2ad556d
8 changed files with 228 additions and 82 deletions
+2 -1
View File
@@ -41,7 +41,8 @@ bamort
maintenance/testdata/*
testdata/*_data.db*
tmp/main
tmp/*
!tmp/.gitkeep
uploads/*
xporttemp/*
export_temp/*
+9 -8
View File
@@ -61,12 +61,12 @@ func printHelp() {
fmt.Printf(" %sversion%s Show version information\n", ColorGreen, ColorReset)
fmt.Printf(" %shelp%s Show this help message\n", ColorGreen, ColorReset)
fmt.Println("\nArguments:")
fmt.Printf(" %s[dir]%s Directory for export/import (default: ./export_temp)\n", ColorCyan, ColorReset)
fmt.Printf(" %s[dir]%s Directory for export/import (default: ./tmp)\n", ColorCyan, ColorReset)
fmt.Println("\nExamples:")
fmt.Println(" deploy prepare # Create deployment package in ./export_temp")
fmt.Println(" deploy prepare # Create deployment package in ./tmp")
fmt.Println(" deploy prepare /path/pkg # Create deployment package in /path/pkg")
fmt.Println(" deploy deploy # Run deployment without importing data")
fmt.Println(" deploy deploy ./export_temp # Run deployment and import master data")
fmt.Println(" deploy deploy ./tmp # Run deployment and import master data")
fmt.Println(" deploy validate # Validate database schema")
fmt.Println("\nDeployment Workflow:")
fmt.Println(" Source System: deploy prepare /shared/pkg # Export master data")
@@ -165,7 +165,7 @@ func cmdPrepare() {
orchestrator := deployment.NewOrchestrator(database.DB)
exportDir := "./export_temp"
exportDir := "./tmp"
if len(os.Args) > 2 {
exportDir = os.Args[2]
}
@@ -183,11 +183,12 @@ func cmdPrepare() {
fmt.Println()
printSuccess("Deployment package created successfully!")
fmt.Printf("\n%sPackage Details:%s\n", ColorBold, ColorReset)
fmt.Printf(" Version: %s\n", pkg.Version)
fmt.Printf(" Export File: %s\n", pkg.ExportPath)
fmt.Printf(" Timestamp: %s\n", pkg.Timestamp.Format("2006-01-02 15:04:05"))
fmt.Printf(" Version: %s\n", pkg.Version)
fmt.Printf(" Export Dir: %s\n", pkg.ExportPath)
fmt.Printf(" Archive: %s\n", pkg.TarballPath)
fmt.Printf(" Timestamp: %s\n", pkg.Timestamp.Format("2006-01-02 15:04:05"))
fmt.Println()
fmt.Println("This export can be imported on the target system after migration.")
fmt.Println("Transfer the archive file to the target system for deployment.")
fmt.Println()
}
+94 -5
View File
@@ -1,13 +1,18 @@
package deployment
import (
"archive/tar"
"bamort/config"
"bamort/deployment/backup"
"bamort/deployment/migrations"
"bamort/deployment/version"
"bamort/gsmaster"
"bamort/logger"
"compress/gzip"
"fmt"
"io"
"os"
"path/filepath"
"time"
"gorm.io/gorm"
@@ -154,9 +159,25 @@ func (o *DeploymentOrchestrator) PrepareDeploymentPackage(exportDir string) (*De
pkg.ExportPath = exportDir
logger.Info("✓ Master data exported to %s", exportDir)
// Create tar.gz archive
logger.Info("Creating deployment package archive...")
tarballName := fmt.Sprintf("deployment_package_%s_%s.tar.gz",
config.GetVersion(),
time.Now().Format("20060102-150405"))
tarballPath := filepath.Join(filepath.Dir(exportDir), tarballName)
err = createTarGz(exportDir, tarballPath)
if err != nil {
return nil, fmt.Errorf("failed to create tar.gz archive: %w", err)
}
pkg.TarballPath = tarballPath
logger.Info("✓ Package archive created: %s", tarballPath)
logger.Info("═══════════════════════════════════════════════════")
logger.Info("Deployment Package Ready")
logger.Info("Directory: %s", exportDir)
logger.Info("Export Directory: %s", exportDir)
logger.Info("Archive: %s", tarballPath)
logger.Info("═══════════════════════════════════════════════════")
return pkg, nil
@@ -164,9 +185,10 @@ func (o *DeploymentOrchestrator) PrepareDeploymentPackage(exportDir string) (*De
// DeploymentPackage contains information about a deployment package
type DeploymentPackage struct {
Version string
Timestamp time.Time
ExportPath string
Version string
Timestamp time.Time
ExportPath string
TarballPath string
}
// FullDeploymentWithImport performs a complete deployment including data import
@@ -192,7 +214,7 @@ func (o *DeploymentOrchestrator) FullDeploymentWithImport(importFilePath string)
// Step 2: Export current state (before migration)
logger.Info("Step 2/5: Exporting current master data state...")
exportDir := "./export_temp"
exportDir := "./tmp"
err = gsmaster.ExportAll(exportDir)
if err != nil {
report.Warnings = append(report.Warnings, fmt.Sprintf("Current state export failed: %v", err))
@@ -257,3 +279,70 @@ func (o *DeploymentOrchestrator) FullDeploymentWithImport(importFilePath string)
return report, nil
}
// createTarGz creates a tar.gz archive from a directory
func createTarGz(sourceDir, targetPath string) error {
// Create the tar.gz file
outFile, err := os.Create(targetPath)
if err != nil {
return fmt.Errorf("failed to create tar.gz file: %w", err)
}
defer outFile.Close()
// Create gzip writer
gzWriter := gzip.NewWriter(outFile)
defer gzWriter.Close()
// Create tar writer
tarWriter := tar.NewWriter(gzWriter)
defer tarWriter.Close()
// Get the base name for the archive
baseName := filepath.Base(sourceDir)
// Walk the directory tree
err = filepath.Walk(sourceDir, func(file string, fi os.FileInfo, err error) error {
if err != nil {
return err
}
// Create tar header
header, err := tar.FileInfoHeader(fi, fi.Name())
if err != nil {
return fmt.Errorf("failed to create tar header: %w", err)
}
// Update the name to be relative to the source dir
relPath, err := filepath.Rel(sourceDir, file)
if err != nil {
return fmt.Errorf("failed to get relative path: %w", err)
}
header.Name = filepath.Join(baseName, relPath)
// Write header
if err := tarWriter.WriteHeader(header); err != nil {
return fmt.Errorf("failed to write tar header: %w", err)
}
// If it's a file, write its content
if !fi.IsDir() {
f, err := os.Open(file)
if err != nil {
return fmt.Errorf("failed to open file: %w", err)
}
defer f.Close()
if _, err := io.Copy(tarWriter, f); err != nil {
return fmt.Errorf("failed to write file content: %w", err)
}
}
return nil
})
if err != nil {
return fmt.Errorf("failed to walk directory: %w", err)
}
return nil
}
View File
+1
View File
@@ -19,6 +19,7 @@ services:
working_dir: /app
volumes:
- ./templates:/app/templates
- ./tmp:/app/tmp
restart: unless-stopped
frontend:
+53 -24
View File
@@ -46,8 +46,8 @@ Available commands:
|---------|-------------|-------|
| `version` | Show version information | `./deploy version` |
| `status` | Show current DB version and pending migrations | `./deploy status` |
| `prepare` | Create deployment package with master data | `./deploy prepare [export_dir]` |
| `deploy` | Run full deployment (backup → migrate → validate) | `./deploy deploy` |
| `prepare [dir]` | Create deployment package with master data | `./deploy prepare [export_dir]` |
| `deploy [dir]` | Run full deployment (backup → migrate → import → validate) | `./deploy deploy [import_dir]` |
| `validate` | Validate database schema and data integrity | `./deploy validate` |
| `help` | Show help message | `./deploy help` |
@@ -143,7 +143,7 @@ go build -o deploy cmd/deploy/main.go
# Check current database status
./deploy status
# Create deployment package (exports to ./export_temp by default)
# Create deployment package (exports to ./tmp by default)
./deploy prepare
# Or specify custom export directory
@@ -158,7 +158,11 @@ The deployment package includes:
**Important**: The deployment package does NOT include user data (characters, user accounts). User data remains on the target system and is migrated during deployment.
Package location: `backend/export_temp/`
Package files:
- Export directory: `backend/tmp/`
- Archive: `backend/deployment_package_<version>_<timestamp>.tar.gz`
**Transfer the archive file** to the target system for deployment.
### 4. Git: Commit and Tag
@@ -242,11 +246,13 @@ Run the deployment script on the target system:
```bash
cd $BASEDIR
# Option 1: Deploy without deployment package (code + migrations only)
./scripts/deploy-production.sh v0.1.38
# Option 1: Deploy with migrations and master data import
# (Recommended for version upgrades with new game content)
./scripts/deploy-production.sh v0.1.38 deployment_package_0.1.38_20260118-120000.tar.gz
# Option 2: Deploy with deployment package (code + migrations + master data)
./scripts/deploy-production.sh v0.1.38 deployment_package_0.1.38.tar.gz
# Option 2: Deploy with migrations only (no master data changes)
# (Use for bug fixes or feature updates without game content changes)
./scripts/deploy-production.sh v0.1.38
```
**Deployment will prompt for confirmation**:
@@ -279,15 +285,20 @@ Type 'DEPLOY' to continue:
- Stops frontend container to prevent user access during migration
- Backend remains running
6. **Run database migrations**
- Executes pending database migrations
- Automatically rolls back on migration failure
- Restores backup if rollback occurs
7. **Import master data** (if deployment package provided)
- Extracts deployment package
6. **Extract deployment package** (if provided)
- Extracts deployment package to temporary directory
- Copies master data to backend container
- Imports system data (skills, spells, equipment, etc.)
- Prepares import directory path
7. **Run deployment command**
- Executes `deploy deploy [importDir]` in backend container
- Creates backup of current database state
- Exports current master data
- Checks version compatibility
- Applies pending database migrations
- Imports master data (if package provided)
- Validates database schema
- Automatically rolls back on failure
8. **Restart backend**
- Restarts backend container with new code
@@ -306,6 +317,7 @@ Type 'DEPLOY' to continue:
11. **Final validation**
- Verifies all services are running
- Reports deployment status
- Cleans up temporary files
**Deployment log**: Saved to `logs/deploy-YYYYMMDD-HHMMSS.log`
@@ -457,9 +469,14 @@ docker exec bamort-backend /app/deploy status
# Check specific migration file
# Migrations located in: backend/deployment/migrations/
# Test migration locally first
# Test migration locally first (without import)
cd $BASEDIR/backend
DATABASE_TYPE=sqlite ./deploy deploy
go build -o deploy cmd/deploy/main.go
./deploy deploy
# Or test with import
./deploy prepare ./test_export
./deploy deploy ./test_export
# Fix migration code if needed
# Rollback production deployment
@@ -478,12 +495,16 @@ tar -tzf deployment_package_0.1.38.tar.gz
# Verify package was created correctly
cd $BASEDIR/backend
./deploy prepare
ls -lh export_temp/
go build -o deploy cmd/deploy/main.go
./deploy prepare ./test_export
ls -lh ./test_export/
# Import manually if needed
docker cp export_temp/masterdata bamort-backend:/app/masterdata
docker exec bamort-backend /app/deploy import-masterdata --path /app/masterdata --verbose
docker cp ./test_export bamort-backend:/tmp/import_data
docker exec bamort-backend /app/deploy deploy /tmp/import_data
# Or just run migrations without import
docker exec bamort-backend /app/deploy deploy
```
### Problem: Insufficient disk space
@@ -532,9 +553,10 @@ sudo systemctl status docker
# Update version
./scripts/update-version.sh 0.1.38 auto
# Create deployment package
# Create deployment package (includes tar.gz archive)
cd backend && go build -o deploy cmd/deploy/main.go
./deploy prepare
# Transfer the generated .tar.gz file to target system
```
### Git Commands
@@ -546,9 +568,16 @@ git push origin v0.1.38
### Target System Commands
```bash
# Deploy
# Deploy without master data import (migrations only)
./scripts/deploy-production.sh v0.1.38
# Deploy with master data import
./scripts/deploy-production.sh v0.1.38 deployment_package_0.1.38.tar.gz
# Or run deployment tool directly
docker exec bamort-backend /app/deploy deploy # Migrations only
docker exec bamort-backend /app/deploy deploy /import/dir # With import
# Rollback
./scripts/rollback.sh backups/pre-deploy-v0.1.38-TIMESTAMP.sql
+54 -34
View File
@@ -113,52 +113,72 @@ log "→ Stopping frontend to prevent user access..."
docker-compose -f "$DOCKER_COMPOSE_FILE" stop frontend
log "✓ Frontend stopped"
# Run database migrations
log ""
log "→ Running database migrations..."
docker exec bamort-backend /app/deploy migrate --verbose || {
log "❌ Database migration failed"
log "Rolling back..."
docker-compose -f "$DOCKER_COMPOSE_FILE" down
git checkout main
docker-compose -f "$DOCKER_COMPOSE_FILE" up -d
log ""
log "To restore database backup:"
log " ./scripts/rollback.sh $BACKUP_FILE"
exit 1
}
log "✓ Migrations completed successfully"
# Import master data if deployment package provided
# Prepare import directory if deployment package provided
IMPORT_DIR=""
if [ -n "$DEPLOYMENT_PACKAGE" ] && [ -f "$DEPLOYMENT_PACKAGE" ]; then
log ""
log "→ Extracting deployment package..."
TEMP_DIR=$(mktemp -d)
tar -xzf "$DEPLOYMENT_PACKAGE" -C "$TEMP_DIR" || {
IMPORT_DIR="/tmp/bamort-deploy-$(date +%s)"
mkdir -p "$IMPORT_DIR"
tar -xzf "$DEPLOYMENT_PACKAGE" -C "$IMPORT_DIR" || {
log "❌ Failed to extract deployment package"
rm -rf "$TEMP_DIR"
rm -rf "$IMPORT_DIR"
exit 1
}
log "✓ Package extracted"
log "✓ Package extracted to $IMPORT_DIR"
log ""
log "→ Importing master data..."
docker cp "$TEMP_DIR/masterdata" bamort-backend:/app/masterdata || {
log "❌ Failed to copy master data"
rm -rf "$TEMP_DIR"
# Copy to backend container
log "→ Copying master data to backend container..."
docker cp "$IMPORT_DIR" bamort-backend:/tmp/deploy_import || {
log "❌ Failed to copy master data to container"
rm -rf "$IMPORT_DIR"
exit 1
}
docker exec bamort-backend /app/deploy import-masterdata --path /app/masterdata --verbose || {
log "⚠️ Master data import had issues (check logs)"
}
log "✓ Master data import completed"
rm -rf "$TEMP_DIR"
log "✓ Master data copied to container"
CONTAINER_IMPORT_DIR="/tmp/deploy_import"
elif [ -n "$DEPLOYMENT_PACKAGE" ]; then
log "⚠️ Deployment package not found: $DEPLOYMENT_PACKAGE"
else
log "️ No deployment package provided, skipping master data import"
log "️ No deployment package provided, migrations only"
fi
# Run deployment (migrations + optional import)
log ""
if [ -n "$CONTAINER_IMPORT_DIR" ]; then
log "→ Running deployment with master data import..."
docker exec bamort-backend /app/deploy deploy "$CONTAINER_IMPORT_DIR" || {
log "❌ Deployment failed"
log "Rolling back..."
docker-compose -f "$DOCKER_COMPOSE_FILE" down
git checkout main
docker-compose -f "$DOCKER_COMPOSE_FILE" up -d
log ""
log "To restore database backup:"
log " ./scripts/rollback.sh $BACKUP_FILE"
[ -n "$IMPORT_DIR" ] && rm -rf "$IMPORT_DIR"
exit 1
}
log "✓ Deployment completed (migrations + master data import)"
else
log "→ Running deployment (migrations only)..."
docker exec bamort-backend /app/deploy deploy || {
log "❌ Deployment failed"
log "Rolling back..."
docker-compose -f "$DOCKER_COMPOSE_FILE" down
git checkout main
docker-compose -f "$DOCKER_COMPOSE_FILE" up -d
log ""
log "To restore database backup:"
log " ./scripts/rollback.sh $BACKUP_FILE"
exit 1
}
log "✓ Deployment completed (migrations only)"
fi
# Cleanup temp directory
if [ -n "$IMPORT_DIR" ] && [ -d "$IMPORT_DIR" ]; then
rm -rf "$IMPORT_DIR"
log "✓ Cleaned up temporary files"
fi
# Update backend (restart to ensure clean state)
+15 -10
View File
@@ -79,18 +79,23 @@ for i in {1..30}; do
sleep 2
done
# Check for pending migrations
# Run deployment (migrations)
echo ""
echo "→ Checking migration status..."
HEALTH_CHECK=$(curl -s http://localhost:8182/api/system/health 2>/dev/null || echo "{}")
MIGRATIONS_PENDING=$(echo "$HEALTH_CHECK" | grep -o '"migrations_pending":[^,}]*' | cut -d':' -f2 || echo "unknown")
echo "→ Running database deployment..."
docker exec bamort-backend /app/deploy deploy || {
echo "❌ Deployment failed"
echo "Please check logs: docker logs bamort-backend"
exit 1
}
echo "✓ Deployment completed"
if [ "$MIGRATIONS_PENDING" = "true" ]; then
echo "⚠️ Migrations pending - please run migrations manually"
echo " docker exec bamort-backend /app/deploy migrations apply --all"
elif [ "$MIGRATIONS_PENDING" = "false" ]; then
echo "✓ No pending migrations"
fi
# Validate deployment
echo ""
echo "→ Validating deployment..."
docker exec bamort-backend /app/deploy validate || {
echo "⚠️ Validation warnings detected (check logs)"
}
echo "✓ Validation complete"
# Restart frontend
echo ""