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:
parent
e45b1ed19e
commit
1b5085de21
39
.env.bak
39
.env.bak
@ -34,31 +34,37 @@ LOG_FILE=logs/app.log
|
||||
# Repository: https://g.bmcnetworks.dk/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)
|
||||
# =====================================================
|
||||
# Get credentials from e-conomic Settings -> Integrations -> API
|
||||
ECONOMIC_API_URL=https://restapi.e-conomic.com
|
||||
ECONOMIC_APP_SECRET_TOKEN=your_app_secret_token_here
|
||||
ECONOMIC_AGREEMENT_GRANT_TOKEN=your_agreement_grant_token_here
|
||||
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 CRM Integration (for Time Tracking Module)
|
||||
# =====================================================
|
||||
# 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 # Standard timepris i DKK
|
||||
# =====================================================
|
||||
TIMETRACKING_DEFAULT_HOURLY_RATE=1200.00
|
||||
TIMETRACKING_AUTO_ROUND=true
|
||||
TIMETRACKING_ROUND_INCREMENT=0.5
|
||||
TIMETRACKING_ROUND_METHOD=up
|
||||
@ -66,6 +72,15 @@ TIMETRACKING_ROUND_METHOD=up
|
||||
# Time Tracking Safety Switches
|
||||
TIMETRACKING_VTIGER_READ_ONLY=true
|
||||
TIMETRACKING_VTIGER_DRY_RUN=true
|
||||
TIMETRACKING_ECONOMIC_READ_ONLY=true
|
||||
TIMETRACKING_ECONOMIC_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
|
||||
|
||||
96
.env.bak2
Normal file
96
.env.bak2
Normal 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
|
||||
88
BACKUP_RESTORE_TEST_PLAN.md
Normal file
88
BACKUP_RESTORE_TEST_PLAN.md
Normal 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)
|
||||
4
main.py
4
main.py
@ -47,7 +47,7 @@ from app.emails.backend import router as emails_api
|
||||
from app.emails.frontend import views as emails_views
|
||||
from app.settings.backend import router as settings_api
|
||||
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
|
||||
|
||||
# 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(emails_api.router, prefix="/api/v1", tags=["Emails"])
|
||||
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
|
||||
app.include_router(dashboard_views.router, tags=["Frontend"])
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
70
test_sftp.py
Normal file
70
test_sftp.py
Normal 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()
|
||||
Loading…
Reference in New Issue
Block a user