update and bugfix deployment
This commit is contained in:
+2
-1
@@ -41,7 +41,8 @@ bamort
|
||||
|
||||
maintenance/testdata/*
|
||||
testdata/*_data.db*
|
||||
tmp/main
|
||||
tmp/*
|
||||
!tmp/.gitkeep
|
||||
uploads/*
|
||||
xporttemp/*
|
||||
export_temp/*
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ services:
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- ./templates:/app/templates
|
||||
- ./tmp:/app/tmp
|
||||
restart: unless-stopped
|
||||
|
||||
frontend:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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 ""
|
||||
|
||||
Reference in New Issue
Block a user