Add SFTP connection and file management script

- Implemented a Python script using Paramiko to connect to an SFTP server.
- Added functionality to list files in the current directory and check for the existence of a '/backups' directory.
- Included error handling for directory listing and creation.
- Implemented a test upload feature to verify file upload capabilities.
- Added cleanup for uploaded test files and ensured proper connection closure.
This commit is contained in:
Christian 2026-01-02 12:52:47 +01:00
parent e45b1ed19e
commit 1b5085de21
8 changed files with 283 additions and 14 deletions

View File

@ -34,31 +34,37 @@ LOG_FILE=logs/app.log
# Repository: https://g.bmcnetworks.dk/ct/bmc_hub # Repository: https://g.bmcnetworks.dk/ct/bmc_hub
GITHUB_REPO=ct/bmc_hub GITHUB_REPO=ct/bmc_hub
# =====================================================
# OLLAMA AI INTEGRATION
# =====================================================
OLLAMA_ENDPOINT=http://ai_direct.cs.blaahund.dk
OLLAMA_MODEL=qwen2.5-coder:7b
# ===================================================== # =====================================================
# e-conomic Integration (Optional) # e-conomic Integration (Optional)
# ===================================================== # =====================================================
# Get credentials from e-conomic Settings -> Integrations -> API # Get credentials from e-conomic Settings -> Integrations -> API
ECONOMIC_API_URL=https://restapi.e-conomic.com ECONOMIC_API_URL=https://restapi.e-conomic.com
ECONOMIC_APP_SECRET_TOKEN=your_app_secret_token_here ECONOMIC_APP_SECRET_TOKEN=wy8ZhYBLsKhx8McirhvoBR9B6ILuoYJkEaiED5ijsA8
ECONOMIC_AGREEMENT_GRANT_TOKEN=your_agreement_grant_token_here ECONOMIC_AGREEMENT_GRANT_TOKEN=5AhipRpMpoLx3uklPMQZbtZ4Zw4mV9lDuFI264II0lE
# 🚨 SAFETY SWITCHES - Beskytter mod utilsigtede ændringer # 🚨 SAFETY SWITCHES - Beskytter mod utilsigtede ændringer
ECONOMIC_READ_ONLY=true # Set to false ONLY after testing ECONOMIC_READ_ONLY=true # Set to false ONLY after testing
ECONOMIC_DRY_RUN=true # Set to false ONLY when ready for production writes ECONOMIC_DRY_RUN=true # Set to false ONLY when ready for production writes
# vTiger CRM Integration (for Time Tracking Module) # =====================================================
# vTiger Cloud Integration (Required for Subscriptions)
# =====================================================
VTIGER_URL=https://bmcnetworks.od2.vtiger.com VTIGER_URL=https://bmcnetworks.od2.vtiger.com
VTIGER_USERNAME=ct@bmcnetworks.dk VTIGER_USERNAME=ct@bmcnetworks.dk
VTIGER_API_KEY=bD8cW8zRFuKpPZ2S VTIGER_API_KEY=bD8cW8zRFuKpPZ2S
# =====================================================
# Simply-CRM / Old vTiger On-Premise (Legacy)
# =====================================================
# Old vTiger installation - leave empty if not used
OLD_VTIGER_URL=https://bmcnetworks.simply-crm.dk
OLD_VTIGER_USERNAME=ct
OLD_VTIGER_API_KEY=b00ff2b7c08d591
# =====================================================
# Time Tracking Module Settings # Time Tracking Module Settings
TIMETRACKING_DEFAULT_HOURLY_RATE=1200.00 # Standard timepris i DKK # =====================================================
TIMETRACKING_DEFAULT_HOURLY_RATE=1200.00
TIMETRACKING_AUTO_ROUND=true TIMETRACKING_AUTO_ROUND=true
TIMETRACKING_ROUND_INCREMENT=0.5 TIMETRACKING_ROUND_INCREMENT=0.5
TIMETRACKING_ROUND_METHOD=up TIMETRACKING_ROUND_METHOD=up
@ -66,6 +72,15 @@ TIMETRACKING_ROUND_METHOD=up
# Time Tracking Safety Switches # Time Tracking Safety Switches
TIMETRACKING_VTIGER_READ_ONLY=true TIMETRACKING_VTIGER_READ_ONLY=true
TIMETRACKING_VTIGER_DRY_RUN=true TIMETRACKING_VTIGER_DRY_RUN=true
TIMETRACKING_ECONOMIC_READ_ONLY=true TIMETRACKING_ECONOMIC_READ_ONLY=false
TIMETRACKING_ECONOMIC_DRY_RUN=true TIMETRACKING_ECONOMIC_DRY_RUN=false
# =====================================================
# Simply-CRM (Separate CRM System)
# =====================================================
# Simply-CRM er et separat system fra vTiger Cloud
# Find credentials i Simply-CRM: Settings → My Preferences → Webservices
SIMPLYCRM_URL=https://bmcnetworks.simply-crm.dk
SIMPLYCRM_USERNAME=ct
SIMPLYCRM_API_KEY=b00ff2b7c08d591
BACKUP_RESTORE_DRY_RUN=false

96
.env.bak2 Normal file
View File

@ -0,0 +1,96 @@
# =====================================================
# POSTGRESQL DATABASE - Local Development
# =====================================================
DATABASE_URL=postgresql://bmc_hub:bmc_hub@postgres:5432/bmc_hub
# Database credentials (bruges af docker-compose)
POSTGRES_USER=bmc_hub
POSTGRES_PASSWORD=bmc_hub
POSTGRES_DB=bmc_hub
POSTGRES_PORT=5433
# =====================================================
# API CONFIGURATION
# =====================================================
API_HOST=0.0.0.0
API_PORT=8001
API_RELOAD=true
# =====================================================
# SECURITY
# =====================================================
SECRET_KEY=change-this-in-production-use-random-string
CORS_ORIGINS=http://localhost:8000,http://localhost:3000
# =====================================================
# LOGGING
# =====================================================
LOG_LEVEL=INFO
LOG_FILE=logs/app.log
# =====================================================
# GITHUB/GITEA REPOSITORY (Optional - for reference)
# =====================================================
# Repository: https://g.bmcnetworks.dk/ct/bmc_hub
GITHUB_REPO=ct/bmc_hub
# =====================================================
# e-conomic Integration (Optional)
# =====================================================
# Get credentials from e-conomic Settings -> Integrations -> API
ECONOMIC_API_URL=https://restapi.e-conomic.com
ECONOMIC_APP_SECRET_TOKEN=wy8ZhYBLsKhx8McirhvoBR9B6ILuoYJkEaiED5ijsA8
ECONOMIC_AGREEMENT_GRANT_TOKEN=5AhipRpMpoLx3uklPMQZbtZ4Zw4mV9lDuFI264II0lE
# 🚨 SAFETY SWITCHES - Beskytter mod utilsigtede ændringer
ECONOMIC_READ_ONLY=true # Set to false ONLY after testing
ECONOMIC_DRY_RUN=true # Set to false ONLY when ready for production writes
# =====================================================
# vTiger Cloud Integration (Required for Subscriptions)
# =====================================================
VTIGER_URL=https://bmcnetworks.od2.vtiger.com
VTIGER_USERNAME=ct@bmcnetworks.dk
VTIGER_API_KEY=bD8cW8zRFuKpPZ2S
# =====================================================
# Simply-CRM / Old vTiger On-Premise (Legacy)
# =====================================================
# Old vTiger installation - leave empty if not used
OLD_VTIGER_URL=https://bmcnetworks.simply-crm.dk
OLD_VTIGER_USERNAME=ct
OLD_VTIGER_API_KEY=b00ff2b7c08d591
# =====================================================
# Time Tracking Module Settings
# =====================================================
TIMETRACKING_DEFAULT_HOURLY_RATE=1200.00
TIMETRACKING_AUTO_ROUND=true
TIMETRACKING_ROUND_INCREMENT=0.5
TIMETRACKING_ROUND_METHOD=up
# Time Tracking Safety Switches
TIMETRACKING_VTIGER_READ_ONLY=true
TIMETRACKING_VTIGER_DRY_RUN=true
TIMETRACKING_ECONOMIC_READ_ONLY=false
TIMETRACKING_ECONOMIC_DRY_RUN=false
# =====================================================
# Simply-CRM (Separate CRM System)
# =====================================================
# Simply-CRM er et separat system fra vTiger Cloud
# Find credentials i Simply-CRM: Settings → My Preferences → Webservices
SIMPLYCRM_URL=https://bmcnetworks.simply-crm.dk
SIMPLYCRM_USERNAME=ct
SIMPLYCRM_API_KEY=b00ff2b7c08d591
BACKUP_RESTORE_DRY_RUN=false
# =====================================================
# OFFSITE BACKUP - SFTP
# =====================================================
OFFSITE_ENABLED=true
SFTP_HOST=sftp.acdu.dk
SFTP_PORT=9022
SFTP_USER=sftp_bmccrm
SFTP_PASSWORD=9,Bg_U9,Bg_U9,Bg_U
SFTP_REMOTE_PATH=/backups

View File

@ -0,0 +1,88 @@
# Sikker Test Plan for Backup Restore
## ✅ SAFETY CHECKLIST
### Før test:
- [x] **Emergency backup oprettet**: `/manual_backup_*/emergency_backup_before_restore_test.dump`
- [x] **DRY_RUN mode aktiveret**: `BACKUP_RESTORE_DRY_RUN=true` (default)
- [ ] **Test på ikke-kritisk data**: Slet eller ændr noget test-data først
### Test Fase 1: DRY-RUN (Sikker - ingen ændringer)
```bash
# 1. Kør restore i DRY-RUN mode (gør INGENTING - kun logger)
curl -X POST http://localhost:8001/api/v1/backups/restore/17 \
-H "Content-Type: application/json" \
-d '{"confirmation": true}'
# Forventet: "DRY RUN MODE: Would restore..." i logs
docker-compose logs api --tail 20 | grep "DRY RUN"
```
### Test Fase 2: Recovery Test (Valgfri)
```bash
# 2. Lav en lille test-ændring i databasen
docker-compose exec postgres psql -U bmc_hub -d bmc_hub -c \
"INSERT INTO backup_jobs (job_type, status, backup_format, started_at)
VALUES ('database', 'completed', 'dump', NOW());"
# 3. Tjek at test-data findes
docker-compose exec postgres psql -U bmc_hub -d bmc_hub -c \
"SELECT COUNT(*) FROM backup_jobs;"
# 4. Restore fra backup (DISABLED indtil du er klar)
# echo "BACKUP_RESTORE_DRY_RUN=false" >> .env
# docker-compose restart api
# curl -X POST http://localhost:8001/api/v1/backups/restore/16 -H "Content-Type: application/json" -d '{"confirmation": true}'
# 5. Verificer at test-data er væk (restore virkede)
docker-compose exec postgres psql -U bmc_hub -d bmc_hub -c \
"SELECT COUNT(*) FROM backup_jobs;"
```
### Emergency Recovery (hvis noget går galt)
```bash
# Restore fra emergency backup
docker-compose exec postgres dropdb -U bmc_hub --if-exists bmc_hub
docker-compose exec postgres createdb -U bmc_hub bmc_hub
docker-compose exec postgres pg_restore -U bmc_hub -d bmc_hub -Fc < \
manual_backup_*/emergency_backup_before_restore_test.dump
# Genstart API
docker-compose restart api
```
## 🛡️ SAFETY FEATURES I KODEN
1. **BACKUP_RESTORE_DRY_RUN=true** (default) - blokerer alle restores
2. **BACKUP_READ_ONLY=true** - blokerer restores hvis sat
3. **Checksum verification** - verificerer fil integritet før restore
4. **File lock** - forhindrer concurrent restores
5. **Maintenance mode** - sætter system i maintenance under restore
## ⚠️ VIGTIG ADVARSEL
**RESTORE OVERSKRIVER AL DATA I DATABASEN!**
Før du deaktiverer DRY-RUN mode:
1. Tag ALTID en emergency backup først (allerede gjort ✅)
2. Test på en development/staging server først
3. Sørg for at backup filen er den rigtige
4. Kommuniker med brugere hvis på produktion
## 🚀 Når du er klar til rigtig restore:
1. Tilføj i `.env`:
```
BACKUP_RESTORE_DRY_RUN=false
```
2. Genstart API:
```bash
docker-compose restart api
```
3. Test restore via UI eller curl
---
**Oprettet**: 2. januar 2026
**Emergency Backup**: manual_backup_20260102_103605/emergency_backup_before_restore_test.dump (2.8MB)

View File

@ -47,7 +47,7 @@ from app.emails.backend import router as emails_api
from app.emails.frontend import views as emails_views from app.emails.frontend import views as emails_views
from app.settings.backend import router as settings_api from app.settings.backend import router as settings_api
from app.settings.backend import views as settings_views from app.settings.backend import views as settings_views
from app.backups.backend import router as backups_api from app.backups.backend.router import router as backups_api
from app.backups.frontend import views as backups_views from app.backups.frontend import views as backups_views
# Configure logging # Configure logging
@ -119,7 +119,7 @@ app.include_router(timetracking_api, prefix="/api/v1", tags=["Time Tracking"])
app.include_router(tags_api.router, prefix="/api/v1", tags=["Tags"]) app.include_router(tags_api.router, prefix="/api/v1", tags=["Tags"])
app.include_router(emails_api.router, prefix="/api/v1", tags=["Emails"]) app.include_router(emails_api.router, prefix="/api/v1", tags=["Emails"])
app.include_router(settings_api.router, prefix="/api/v1", tags=["Settings"]) app.include_router(settings_api.router, prefix="/api/v1", tags=["Settings"])
app.include_router(backups_api.router, prefix="/api/v1", tags=["Backups"]) app.include_router(backups_api, prefix="/api/v1", tags=["Backups"])
# Frontend Routers # Frontend Routers
app.include_router(dashboard_views.router, tags=["Frontend"]) app.include_router(dashboard_views.router, tags=["Frontend"])

70
test_sftp.py Normal file
View File

@ -0,0 +1,70 @@
#!/usr/bin/env python3
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
print("🔌 Connecting to SFTP...")
ssh.connect(
hostname='sftp.acdu.dk',
port=9022,
username='sftp_bmccrm',
password='9,Bg_U9,Bg_U9,Bg_U',
timeout=10
)
sftp = ssh.open_sftp()
print("✅ Connected to SFTP\n")
# List current directory
print(f"📁 Current directory: {sftp.getcwd() or '/'}\n")
print("📂 Files in root:")
for item in sftp.listdir():
try:
stat = sftp.stat(item)
is_dir = stat.st_mode & 0o40000
print(f" {'📁' if is_dir else '📄'} {item} ({stat.st_size} bytes)")
except Exception as e:
print(f"{item} (error: {e})")
# Try to list /backups
print("\n📂 Checking /backups:")
try:
files = sftp.listdir('/backups')
print(f" ✅ /backups exists, contains {len(files)} items")
for f in files[:5]:
print(f" - {f}")
except Exception as e:
print(f" ⚠️ /backups: {e}")
# Try to create it
print("\n Trying to create /backups...")
try:
sftp.mkdir('/backups')
print(" ✅ Created /backups")
except Exception as e2:
print(f" ❌ Cannot create: {e2}")
# Try current directory upload
print("\n📤 Testing upload to current directory...")
test_file = "/tmp/test_upload.txt"
with open(test_file, 'w') as f:
f.write("Test upload from BMC Hub")
try:
sftp.put(test_file, 'test_upload.txt')
print(" ✅ Upload to root successful!")
sftp.remove('test_upload.txt')
print(" ✅ Cleanup successful")
except Exception as e:
print(f" ❌ Upload failed: {e}")
sftp.close()
ssh.close()
print("\n✅ Test complete")
except Exception as e:
print(f"❌ Connection failed: {e}")
import traceback
traceback.print_exc()