deploy CI

This commit is contained in:
Fran Jurmanović
2025-07-04 19:25:34 +02:00
parent 12e259270d
commit b1792e1c71
8 changed files with 994 additions and 7665 deletions

256
scripts/README.md Normal file
View File

@@ -0,0 +1,256 @@
# ACC Server Manager Deployment Scripts
This directory contains scripts and tools for deploying the ACC Server Manager to a Windows server.
## Overview
The deployment process automates the following steps:
1. Build the application binaries for Windows
2. Copy binaries to the target server
3. Stop the Windows service
4. Backup current deployment
5. Deploy new binaries
6. Run database migrations
7. Start the Windows service
8. Verify deployment success
## Files
- `deploy.ps1` - Main PowerShell deployment script
- `deploy.bat` - Batch file wrapper for easier execution
- `deploy.config.example` - Configuration template
- `README.md` - This documentation
## Prerequisites
### Local Machine (Build Environment)
- Go 1.23 or later
- PowerShell (Windows PowerShell 5.1+ or PowerShell Core 7+)
- SSH client (OpenSSH recommended)
- SCP utility
### Target Windows Server
- Windows Server 2016 or later
- PowerShell 5.1 or later
- SSH Server (OpenSSH Server or similar)
- ACC Server Manager Windows service configured
## Setup
### 1. Configure SSH Access
Ensure SSH access to your Windows server:
```powershell
# On Windows Server, install OpenSSH Server
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
```
### 2. Create Deployment Configuration
Copy the configuration template and customize it:
```bash
cp deploy.config.example deploy.config
# Edit deploy.config with your server details
```
### 3. Set Up Windows Service
Ensure the ACC Server Manager is installed as a Windows service on the target server. You can use tools like NSSM or create a native Windows service.
## Usage
### Option 1: Using Batch Script (Recommended)
```batch
# Basic deployment
deploy.bat 192.168.1.100 admin "C:\AccServerManager"
# With additional options
deploy.bat 192.168.1.100 admin "C:\AccServerManager" -SkipTests
# Test deployment (dry run)
deploy.bat 192.168.1.100 admin "C:\AccServerManager" -WhatIf
```
### Option 2: Using PowerShell Script Directly
```powershell
# Basic deployment
.\deploy.ps1 -ServerHost "192.168.1.100" -ServerUser "admin" -DeployPath "C:\AccServerManager"
# With custom service name
.\deploy.ps1 -ServerHost "192.168.1.100" -ServerUser "admin" -DeployPath "C:\AccServerManager" -ServiceName "MyAccService"
# Skip tests and build
.\deploy.ps1 -ServerHost "192.168.1.100" -ServerUser "admin" -DeployPath "C:\AccServerManager" -SkipTests -SkipBuild
# Dry run
.\deploy.ps1 -ServerHost "192.168.1.100" -ServerUser "admin" -DeployPath "C:\AccServerManager" -WhatIf
```
### Option 3: Using GitHub Actions
The CI/CD pipeline automatically deploys when changes are pushed to the main branch. Configure the following secrets in your GitHub repository:
- `WINDOWS_SERVER_HOST` - Server hostname or IP
- `WINDOWS_SERVER_USER` - SSH username
- `WINDOWS_SERVER_SSH_KEY` - SSH private key
- `DEPLOY_PATH` - Deployment directory on server
- `SLACK_WEBHOOK_URL` - (Optional) Slack webhook for notifications
## Parameters
### Required Parameters
- `ServerHost` - Target Windows server hostname or IP address
- `ServerUser` - Username for SSH connection
- `DeployPath` - Full path where the application will be deployed
### Optional Parameters
- `ServiceName` - Windows service name (default: "ACC Server Manager")
- `BinaryName` - Main binary name (default: "acc-server-manager")
- `MigrateBinaryName` - Migration binary name (default: "acc-migrate")
- `SkipBuild` - Skip the build process
- `SkipTests` - Skip running tests
- `WhatIf` - Show what would be done without executing
## Deployment Process Details
### 1. Build Phase
- Runs Go tests (unless `-SkipTests` is specified)
- Builds API binary for Windows (GOOS=windows, GOARCH=amd64)
- Builds migration tool for Windows
- Creates binaries in `.\build` directory
### 2. Pre-deployment
- Copies binaries to server's temporary directory
- Creates deployment script on server
### 3. Deployment
- Stops the Windows service
- Creates backup of current deployment
- Copies new binaries to deployment directory
- Runs database migrations
- Starts the Windows service
- Verifies service is running
### 4. Rollback (if deployment fails)
- Restores from backup
- Restarts service with previous version
- Reports failure
### 5. Cleanup
- Removes temporary files
- Keeps last 5 backups (configurable)
## Troubleshooting
### Common Issues
#### SSH Connection Failed
```
Test-NetConnection -ComputerName <server> -Port 22
```
Ensure SSH server is running and accessible.
#### Service Not Found
Verify the service name matches exactly:
```powershell
Get-Service -Name "ACC Server Manager"
```
#### Permission Denied
Ensure the SSH user has permissions to:
- Stop/start the service
- Write to the deployment directory
- Execute PowerShell scripts
#### Build Failures
Check Go version and dependencies:
```bash
go version
go mod tidy
go test ./...
```
### Debug Mode
Run with verbose output:
```powershell
$VerbosePreference = "Continue"
.\deploy.ps1 -ServerHost "..." -ServerUser "..." -DeployPath "..." -Verbose
```
### Log Files
Deployment logs are stored in:
- Local: PowerShell transcript files
- Remote: Windows Event Log (Application log)
## Security Considerations
1. **SSH Keys**: Use SSH key authentication instead of passwords
2. **Service Account**: Run the service with minimal required permissions
3. **Firewall**: Restrict SSH access to deployment machines only
4. **Backup Encryption**: Consider encrypting backup files
5. **Secrets Management**: Use secure storage for configuration files
## Customization
### Custom Migration Scripts
Place custom migration scripts in the `scripts/migrations` directory. They will be executed in alphabetical order.
### Pre/Post Deployment Hooks
Configure custom scripts in the deployment configuration:
```ini
PreDeployScript=scripts/pre-deploy.ps1
PostDeployScript=scripts/post-deploy.ps1
```
### Environment Variables
Set environment variables during deployment:
```ini
EnvironmentVariables=ENV=production,LOG_LEVEL=info
```
## Monitoring and Notifications
### Slack Notifications
Configure Slack webhook URL to receive deployment notifications:
```ini
SlackWebhookUrl=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
```
### Health Checks
Configure health check endpoint to verify deployment:
```ini
HealthCheckUrl=http://localhost:8080/health
HealthCheckTimeout=60
```
## Best Practices
1. **Test deployments** in a staging environment first
2. **Use the `-WhatIf` flag** to preview changes
3. **Monitor service logs** after deployment
4. **Keep backups** of working deployments
5. **Use version tagging** for releases
6. **Document configuration changes**
7. **Test rollback procedures** regularly
## Support
For issues with deployment scripts:
1. Check the troubleshooting section
2. Review deployment logs
3. Verify server prerequisites
4. Test SSH connectivity manually
5. Check Windows service configuration
For application-specific issues, refer to the main project documentation.

86
scripts/deploy.bat Normal file
View File

@@ -0,0 +1,86 @@
@echo off
setlocal enabledelayedexpansion
:: ACC Server Manager Deployment Script
:: This is a wrapper for the PowerShell deployment script
echo.
echo ===================================
echo ACC Server Manager Deployment Tool
echo ===================================
echo.
:: Check if PowerShell is available
where powershell >nul 2>&1
if %errorlevel% neq 0 (
echo ERROR: PowerShell is not installed or not in PATH
echo Please install PowerShell to use this deployment script
pause
exit /b 1
)
:: Check if required parameters are provided
if "%~1"=="" (
echo Usage: deploy.bat [ServerHost] [ServerUser] [DeployPath] [additional options]
echo.
echo Examples:
echo deploy.bat 192.168.1.100 admin "C:\AccServerManager"
echo deploy.bat server.example.com deploy "C:\Services\AccServerManager" -SkipTests
echo deploy.bat 192.168.1.100 admin "C:\AccServerManager" -WhatIf
echo.
echo For more options, run: powershell -File scripts\deploy.ps1
pause
exit /b 1
)
:: Set variables
set SERVER_HOST=%~1
set SERVER_USER=%~2
set DEPLOY_PATH=%~3
:: Shift parameters to get additional options
shift
shift
shift
set ADDITIONAL_PARAMS=
:loop
if "%~1"=="" goto :continue
set ADDITIONAL_PARAMS=%ADDITIONAL_PARAMS% %1
shift
goto :loop
:continue
echo Server Host: %SERVER_HOST%
echo Server User: %SERVER_USER%
echo Deploy Path: %DEPLOY_PATH%
if not "%ADDITIONAL_PARAMS%"=="" (
echo Additional Parameters: %ADDITIONAL_PARAMS%
)
echo.
:: Confirm deployment
set /p CONFIRM=Do you want to proceed with deployment? (Y/N):
if /i not "%CONFIRM%"=="Y" (
echo Deployment cancelled.
pause
exit /b 0
)
echo.
echo Starting deployment...
echo.
:: Execute PowerShell deployment script
powershell -ExecutionPolicy Bypass -File "%~dp0deploy.ps1" -ServerHost "%SERVER_HOST%" -ServerUser "%SERVER_USER%" -DeployPath "%DEPLOY_PATH%" %ADDITIONAL_PARAMS%
if %errorlevel% neq 0 (
echo.
echo Deployment failed with error code: %errorlevel%
pause
exit /b %errorlevel%
)
echo.
echo Deployment completed successfully!
pause

View File

@@ -0,0 +1,109 @@
# ACC Server Manager Deployment Configuration
# Copy this file to deploy.config and fill in your server details
[Server]
# Windows server hostname or IP address
ServerHost=192.168.1.100
# Username for SSH connection to Windows server
ServerUser=admin
# Full path where the application will be deployed on the server
DeployPath=C:\AccServerManager
# Windows service name (must match the service installed on the server)
ServiceName=ACC Server Manager
[Build]
# Main application binary name (without .exe extension)
BinaryName=acc-server-manager
# Migration tool binary name (without .exe extension)
MigrateBinaryName=acc-migrate
# Skip running tests during build (true/false)
SkipTests=false
# Skip building binaries (useful if you already have them built)
SkipBuild=false
[Deployment]
# Backup retention - number of backup directories to keep
BackupRetention=5
# Service stop timeout in seconds
ServiceStopTimeout=30
# Service start timeout in seconds
ServiceStartTimeout=30
# Enable rollback on deployment failure (true/false)
EnableRollback=true
[Notifications]
# Slack webhook URL for deployment notifications (optional)
SlackWebhookUrl=
# Discord webhook URL for deployment notifications (optional)
DiscordWebhookUrl=
# Email settings for notifications (optional)
EmailSmtpServer=
EmailSmtpPort=587
EmailUsername=
EmailPassword=
EmailFrom=
EmailTo=
[SSH]
# SSH private key file path (optional, uses default SSH key if not specified)
SshKeyPath=
# SSH port (default is 22)
SshPort=22
# SSH connection timeout in seconds
SshTimeout=30
[Database]
# Database connection string template for migrations
# This will be passed to the migration tool
DatabaseConnectionString=
# Run migrations automatically during deployment (true/false)
AutoMigrate=true
# Migration timeout in seconds
MigrationTimeout=300
[Advanced]
# PowerShell execution policy for remote execution
ExecutionPolicy=Bypass
# Temporary directory on remote server for file transfers
RemoteTempPath=C:\temp
# Local build directory
LocalBuildPath=.\build
# Additional Go build flags
GoBuildFlags=-ldflags="-s -w"
# Pre-deployment script to run locally (optional)
PreDeployScript=
# Post-deployment script to run on remote server (optional)
PostDeployScript=
# Environment variables to set during deployment (comma-separated)
# Format: KEY1=VALUE1,KEY2=VALUE2
EnvironmentVariables=
# Custom service restart command (if service management is different)
ServiceRestartCommand=
# Health check URL to verify deployment success
HealthCheckUrl=http://localhost:8080/health
# Health check timeout in seconds
HealthCheckTimeout=60

310
scripts/deploy.ps1 Normal file
View File

@@ -0,0 +1,310 @@
param(
[Parameter(Mandatory=$true)]
[string]$ServerHost,
[Parameter(Mandatory=$true)]
[string]$ServerUser,
[Parameter(Mandatory=$true)]
[string]$DeployPath,
[string]$ServiceName = "ACC Server Manager",
[string]$BinaryName = "acc-server-manager",
[string]$MigrateBinaryName = "acc-migrate",
[switch]$SkipBuild,
[switch]$SkipTests,
[switch]$WhatIf
)
# Configuration
$ErrorActionPreference = "Stop"
$LocalBuildPath = ".\build"
$RemoteTempPath = "C:\temp"
function Write-Status {
param([string]$Message, [string]$Color = "Green")
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] $Message" -ForegroundColor $Color
}
function Write-Error-Status {
param([string]$Message)
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] ERROR: $Message" -ForegroundColor Red
}
function Write-Warning-Status {
param([string]$Message)
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] WARNING: $Message" -ForegroundColor Yellow
}
function Test-Prerequisites {
Write-Status "Checking prerequisites..."
# Check if Go is installed
if (-not (Get-Command go -ErrorAction SilentlyContinue)) {
throw "Go is not installed or not in PATH"
}
# Check if we can connect to the server
$testConnection = Test-NetConnection -ComputerName $ServerHost -Port 22 -WarningAction SilentlyContinue
if (-not $testConnection.TcpTestSucceeded) {
Write-Warning-Status "Cannot connect to $ServerHost on port 22. Make sure SSH is enabled."
}
Write-Status "Prerequisites check completed"
}
function Build-Application {
if ($SkipBuild) {
Write-Status "Skipping build (SkipBuild flag set)"
return
}
Write-Status "Building application..."
# Clean build directory
if (Test-Path $LocalBuildPath) {
Remove-Item -Path $LocalBuildPath -Recurse -Force
}
New-Item -ItemType Directory -Path $LocalBuildPath -Force | Out-Null
# Run tests
if (-not $SkipTests) {
Write-Status "Running tests..."
& go test -v ./...
if ($LASTEXITCODE -ne 0) {
throw "Tests failed"
}
}
# Build API for Windows
Write-Status "Building API binary..."
$env:GOOS = "windows"
$env:GOARCH = "amd64"
& go build -o "$LocalBuildPath\$BinaryName.exe" .\cmd\api
if ($LASTEXITCODE -ne 0) {
throw "Failed to build API binary"
}
# Build migration tool for Windows
Write-Status "Building migration binary..."
& go build -o "$LocalBuildPath\$MigrateBinaryName.exe" .\cmd\migrate
if ($LASTEXITCODE -ne 0) {
throw "Failed to build migration binary"
}
# Reset environment variables
Remove-Item Env:\GOOS -ErrorAction SilentlyContinue
Remove-Item Env:\GOARCH -ErrorAction SilentlyContinue
Write-Status "Build completed successfully"
}
function Copy-FilesToServer {
Write-Status "Copying files to server..."
if ($WhatIf) {
Write-Status "WHAT-IF: Would copy files to $ServerHost" -Color "Cyan"
return
}
# Copy binaries to server
scp -o StrictHostKeyChecking=no "$LocalBuildPath\$BinaryName.exe" "${ServerUser}@${ServerHost}:${RemoteTempPath}/"
if ($LASTEXITCODE -ne 0) {
throw "Failed to copy API binary to server"
}
scp -o StrictHostKeyChecking=no "$LocalBuildPath\$MigrateBinaryName.exe" "${ServerUser}@${ServerHost}:${RemoteTempPath}/"
if ($LASTEXITCODE -ne 0) {
throw "Failed to copy migration binary to server"
}
Write-Status "Files copied successfully"
}
function Deploy-ToServer {
Write-Status "Deploying to server..."
if ($WhatIf) {
Write-Status "WHAT-IF: Would deploy to $ServerHost" -Color "Cyan"
return
}
# Create deployment script
$deployScript = @"
Write-Host "Starting deployment process..." -ForegroundColor Green
# Check if service exists and stop it
`$service = Get-Service -Name '$ServiceName' -ErrorAction SilentlyContinue
if (`$service) {
Write-Host "Stopping service: $ServiceName" -ForegroundColor Yellow
Stop-Service -Name '$ServiceName' -Force
# Wait for service to stop
`$timeout = 30
`$elapsed = 0
while (`$service.Status -ne 'Stopped' -and `$elapsed -lt `$timeout) {
Start-Sleep -Seconds 1
`$elapsed++
`$service.Refresh()
}
if (`$service.Status -ne 'Stopped') {
Write-Error "Failed to stop service within timeout"
exit 1
}
Write-Host "Service stopped successfully" -ForegroundColor Green
} else {
Write-Host "Service not found: $ServiceName" -ForegroundColor Yellow
}
# Create backup of current deployment
`$backupPath = "$DeployPath\backup_`$(Get-Date -Format 'yyyyMMdd_HHmmss')"
if (Test-Path "$DeployPath\$BinaryName.exe") {
Write-Host "Creating backup at: `$backupPath" -ForegroundColor Yellow
New-Item -ItemType Directory -Path `$backupPath -Force | Out-Null
Copy-Item "$DeployPath\*" -Destination `$backupPath -Recurse -Force
}
# Copy new binaries
Write-Host "Copying new binaries to: $DeployPath" -ForegroundColor Yellow
if (-not (Test-Path "$DeployPath")) {
New-Item -ItemType Directory -Path "$DeployPath" -Force | Out-Null
}
Copy-Item "$RemoteTempPath\$BinaryName.exe" -Destination "$DeployPath\$BinaryName.exe" -Force
Copy-Item "$RemoteTempPath\$MigrateBinaryName.exe" -Destination "$DeployPath\$MigrateBinaryName.exe" -Force
# Run migrations
Write-Host "Running database migrations..." -ForegroundColor Yellow
try {
`$migrateResult = & "$DeployPath\$MigrateBinaryName.exe" 2>&1
Write-Host "Migration output: `$migrateResult" -ForegroundColor Cyan
} catch {
Write-Warning "Migration failed: `$_"
}
# Start service
if (`$service) {
Write-Host "Starting service: $ServiceName" -ForegroundColor Yellow
Start-Service -Name '$ServiceName'
# Wait for service to start
`$timeout = 30
`$elapsed = 0
while (`$service.Status -ne 'Running' -and `$elapsed -lt `$timeout) {
Start-Sleep -Seconds 1
`$elapsed++
`$service.Refresh()
}
if (`$service.Status -ne 'Running') {
Write-Error "Failed to start service within timeout"
# Rollback
Write-Host "Rolling back deployment..." -ForegroundColor Red
if (Test-Path `$backupPath) {
Copy-Item "`$backupPath\*" -Destination "$DeployPath" -Recurse -Force
Start-Service -Name '$ServiceName'
}
exit 1
}
Write-Host "Service started successfully" -ForegroundColor Green
} else {
Write-Host "Service not configured. Manual start required." -ForegroundColor Yellow
}
# Cleanup old backups (keep last 5)
`$backupDir = Split-Path "$DeployPath" -Parent
Get-ChildItem -Path `$backupDir -Directory -Name "backup_*" |
Sort-Object -Descending |
Select-Object -Skip 5 |
ForEach-Object { Remove-Item -Path "`$backupDir\`$_" -Recurse -Force }
# Cleanup temp files
Remove-Item "$RemoteTempPath\$BinaryName.exe" -Force -ErrorAction SilentlyContinue
Remove-Item "$RemoteTempPath\$MigrateBinaryName.exe" -Force -ErrorAction SilentlyContinue
Write-Host "Deployment completed successfully!" -ForegroundColor Green
"@
# Save script to temp file
$tempScript = [System.IO.Path]::GetTempFileName() + ".ps1"
$deployScript | Out-File -FilePath $tempScript -Encoding UTF8
try {
# Copy deployment script to server
scp -o StrictHostKeyChecking=no $tempScript "${ServerUser}@${ServerHost}:${RemoteTempPath}/deploy_script.ps1"
if ($LASTEXITCODE -ne 0) {
throw "Failed to copy deployment script to server"
}
# Execute deployment script on server
ssh -o StrictHostKeyChecking=no "${ServerUser}@${ServerHost}" "powershell.exe -ExecutionPolicy Bypass -File ${RemoteTempPath}/deploy_script.ps1"
if ($LASTEXITCODE -ne 0) {
throw "Deployment script failed on server"
}
# Cleanup deployment script
ssh -o StrictHostKeyChecking=no "${ServerUser}@${ServerHost}" "del ${RemoteTempPath}/deploy_script.ps1"
} finally {
# Remove temp script
Remove-Item $tempScript -Force -ErrorAction SilentlyContinue
}
Write-Status "Deployment completed successfully"
}
function Show-Usage {
Write-Host @"
ACC Server Manager Deployment Script
Usage: .\deploy.ps1 -ServerHost <host> -ServerUser <user> -DeployPath <path> [options]
Parameters:
-ServerHost Target Windows server hostname or IP
-ServerUser Username for SSH connection
-DeployPath Deployment directory on target server
-ServiceName Windows service name (default: "ACC Server Manager")
-BinaryName Main binary name (default: "acc-server-manager")
-MigrateBinaryName Migration binary name (default: "acc-migrate")
-SkipBuild Skip the build process
-SkipTests Skip running tests
-WhatIf Show what would be done without executing
Examples:
.\deploy.ps1 -ServerHost "192.168.1.100" -ServerUser "admin" -DeployPath "C:\AccServerManager"
.\deploy.ps1 -ServerHost "server.example.com" -ServerUser "deploy" -DeployPath "C:\Services\AccServerManager" -SkipTests
.\deploy.ps1 -ServerHost "192.168.1.100" -ServerUser "admin" -DeployPath "C:\AccServerManager" -WhatIf
Requirements:
- Go installed locally
- SSH client (OpenSSH)
- SCP utility
- PowerShell on target Windows server
- SSH server running on target Windows server
"@ -ForegroundColor Cyan
}
# Main execution
try {
Write-Status "Starting ACC Server Manager deployment" -Color "Cyan"
Write-Status "Target: $ServerUser@$ServerHost"
Write-Status "Deploy Path: $DeployPath"
Write-Status "Service Name: $ServiceName"
if ($WhatIf) {
Write-Status "WHAT-IF MODE: No changes will be made" -Color "Cyan"
}
Test-Prerequisites
Build-Application
Copy-FilesToServer
Deploy-ToServer
Write-Status "Deployment completed successfully!" -Color "Green"
} catch {
Write-Error-Status $_.Exception.Message
Write-Host "Deployment failed. Check the error above for details." -ForegroundColor Red
exit 1
}