Compare commits

..

3 Commits

Author SHA1 Message Date
Claude Agent
e08ffb1b68 docs(vm201): document ROA + CONTAFIN update server (IIS apps)
Adds vm201-roa-update-server.md describing the two IIS virtual apps under
roa.romfast.ro that distribute application updates to ROMFAST clients:

- /roaupdate -> D:\ROAUPDATE: per-client VFP XML manifests, _ARHIVE ZIPs
  for 35+ ROA modules (ROACONT, ROAFACTURARE, ROAGEST, etc.), SVN-backed
  DB scripts, xmlupdatecreator workflow.
- /contafinupdate -> D:\APPUPDATESERVERAVFP: ActiveVFP server with
  AVFPHandler for *.avfp requests, VFP9 runtime.

Also captures the full IIS site inventory (Default Web Site, ROA2WEB,
Dokploy, Gitea, roa-qr, roa-apps) verified live on 2026-04-25, and lists
the configured client manifests (ROMFAST, ROMPETROL, ARGENTA, etc.).

Cross-references added in proxmox/README.md and vm201-windows/README.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:14:05 +00:00
Claude Agent
21f1e9affe docs(vm201): add btgo-playwright Windows service documentation
Document the BT George scraper running on VM 201:
- Python + Playwright SDK (HEADLESS=false required for WAF bypass)
- Windows Service deploy with Telegram notifications
- Cross-references in proxmox/README.md and vm201-windows/README.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 22:08:48 +00:00
Claude Agent
8846c9c855 docs(dr): document failback DR -> PRIMARY procedure + restore script
Adds end-to-end procedure for moving production back from DR (10.0.20.37)
to a repaired/reinstalled PRIMARY (10.0.20.36): final RMAN backup on DR
in restricted/read-only mode, RMAN restore on PRIMARY, app connection
switch, scheduled-task reactivation, VM 109 stop. Companion PowerShell
script handles the restore with sanity checks (IP, NFS, backup freshness)
and aborts if Oracle major version != 19, since failback to 21c would
need an extra dictionary upgrade step (~30-60 min) that adds untested
risk during the critical window — recommended path is 19c failback then
upgrade later in a planned window.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:18:09 +00:00
7 changed files with 1335 additions and 11 deletions

View File

@@ -62,6 +62,8 @@ proxmox/
│ ├── docs/
│ │ ├── vm201-certificat-letsencrypt-iis.md
│ │ ├── vm201-dokploy-infrastructure.md # Arhitectură Dokploy + domenii
│ │ ├── vm201-roa-update-server.md # Server update aplicații ROA + CONTAFIN
│ │ ├── vm201-btgo-playwright-service.md # Scraper BT George (Playwright Python)
│ │ ├── vm201-troubleshooting-backup-nfs.md
│ │ └── vm201-troubleshooting-pana-curent-2026-01-11.md
│ ├── iis-configs/ # web.config pentru site-uri IIS
@@ -306,12 +308,15 @@ ssh claude@100.95.55.51
### VM 201 - Windows 11
**Director:** `vm201-windows/`
**IP:** DHCP | **Host:** pvemini | **Rol:** Reverse proxy IIS, client aplicații
**IP:** DHCP | **Host:** pvemini | **Rol:** Server update aplicații ROA + CONTAFIN, reverse proxy IIS, client aplicații, scraper BT George
| Fișier | Descriere |
|--------|-----------|
| `README.md` | Configurație hardware, servicii, rețea, backup |
| `docs/vm201-certificat-letsencrypt-iis.md` | Certificate SSL Let's Encrypt, Win-ACME, SNI |
| `docs/vm201-dokploy-infrastructure.md` | Arhitectură Dokploy + domenii |
| `docs/vm201-roa-update-server.md` | Server update aplicații ROA (`/roaupdate`) + CONTAFIN AVFP (`/contafinupdate`) |
| `docs/vm201-btgo-playwright-service.md` | Scraper BT George — Playwright Python SDK, Windows Service |
| `docs/vm201-troubleshooting-backup-nfs.md` | Incident backup NFS (2025-10-08) |
| `docs/vm201-troubleshooting-pana-curent-2026-01-11.md` | Incident pană curent |
| `scripts/check-ssl-certificates.ps1` | Verificare/reînnoire certificate (Windows) |
@@ -428,6 +433,8 @@ ssh root@10.0.20.201 "qm snapshot 302 pre-test --description 'Before ROA test'"
- **Informații generale** → `vm201-windows/README.md`
- **Configurez site-uri IIS noi (Dokploy)** → `vm201-windows/docs/vm201-dokploy-infrastructure.md`
- **Script setup IIS automat** → `vm201-windows/scripts/setup-new-iis-sites.ps1`
- **Publicare versiune nouă ROA / CONTAFIN către clienți** → `vm201-windows/docs/vm201-roa-update-server.md`
- **Scraper BT George (btgo-playwright)** → `vm201-windows/docs/vm201-btgo-playwright-service.md`
### Dokploy + Traefik (LXC 103)
- **Deploy aplicație nouă** → `lxc103-dokploy/README.md` → "Workflow: Adăugare App Nouă"

View File

@@ -97,6 +97,19 @@ D:\oracle\scripts\rman_restore_from_zero.cmd
# 4. Database is now RUNNING - Update app connections to 10.0.20.37
```
### 🔄 Failback DR → PRIMARY (when production is repaired)
Procedura inversă, pentru când serverul de producție a fost reparat sau reinstalat și
trebuie mutată producția înapoi pe `10.0.20.36`:
> ⚠️ **Pe PRIMARY instalează Oracle 19c (NU 21c) pentru failback acut.** Backup-urile sunt 19.3. 21c poate restore tehnic, dar cere upgrade-of-dictionary suplimentar (~30-60 min în plus) — risc inutil în fereastra de criză. Migrarea la 21c se face separat după failback. Detalii în `FAILBACK_PROCEDURE.md`.
➡️ Vezi **[docs/FAILBACK_PROCEDURE.md](docs/FAILBACK_PROCEDURE.md)** — pași end-to-end:
- Backup final pe DR (cu DB în read-only / restricted)
- Restore pe PRIMARY nou cu `scripts/rman_restore_to_primary.ps1`
- Switch connection strings + reactivare scheduled tasks RMAN
- Stop VM 109, revenire la state normal
### 🧪 Weekly Test (Every Saturday)
```bash
@@ -557,6 +570,7 @@ vm109-windows-dr/
├── docs/
│ ├── PLAN_TESTARE_MONITORIZARE.md # Plan testare și monitorizare DR
│ ├── PROXMOX_NOTIFICATIONS_README.md # Configurare notificări Proxmox
│ ├── FAILBACK_PROCEDURE.md # Failback DR → PRIMARY (procedura inversă)
│ └── archive/ # Planuri și statusuri anterioare
│ ├── DR_UPGRADE_TO_CUMULATIVE_PLAN.md
│ ├── DR_VM_MIGRATION_GUIDE.md
@@ -568,7 +582,8 @@ vm109-windows-dr/
├── rman_backup.bat # RMAN full backup (Windows)
├── rman_backup_incremental.bat # RMAN incremental (Windows)
├── transfer_backups.ps1 # Transfer backup-uri (Windows)
├── rman_restore_from_zero.ps1 # Restore complet (Windows DR)
├── rman_restore_from_zero.ps1 # Restore PRIMARY → DR (disaster activation)
├── rman_restore_to_primary.ps1 # Restore DR → PRIMARY (failback)
├── cleanup_database.ps1 # Cleanup după test (Windows DR)
└── *.ps1 # Alte scripturi configurare
```

View File

@@ -0,0 +1,362 @@
# Failback DR → PRIMARY (procedura inversă)
Procedura de revenire de pe serverul DR (VM 109, `10.0.20.37`) pe serverul de producție reparat sau reinstalat (PRIMARY, `10.0.20.36`).
> **Context**: Această procedură se aplică DUPĂ ce DR a preluat producția (vezi `README.md` § "Emergency DR Activation"). Aplicațiile rulează pe DR (`10.0.20.37:1521/ROA`), PRIMARY a fost reparat sau reinstalat de la zero, și acum trebuie mutată producția înapoi pe PRIMARY.
---
## ⚠️ ATENȚIE: Pe PRIMARY instalează Oracle **19c** (recomandat ferm pentru failback)
Backup-urile RMAN existente sunt luate din Oracle **19.3** (`ORACLE_HOME = WINDOWS.X64_193000_db_home`, `compatible=19.0.0`).
**Instalează Oracle Database 19c:**
- Versiune: **Oracle Database 19c** (19.3 base + ultimul Release Update)
- Edition: aceeași cu cea originală — verifică pe DR cu `SELECT banner FROM v$version;`
- Installer: `WINDOWS.X64_193000_db_home.zip` (Oracle eDelivery / OTN)
- Path identic cu DR pentru ca scriptul de restore să funcționeze fără modificări
**De ce NU 21c (sau 23ai) la failback:**
Tehnic, RMAN 21c **poate** citi backup-uri 19c (controlfile + datafiles + archivelogs se restore). DAR: datafile headers rămân 19c → `ALTER DATABASE OPEN RESETLOGS` eșuează în mod normal. Path-ul corect pe 21c este:
```
RESTORE CONTROLFILE → RESTORE DATABASE → RECOVER DATABASE
→ STARTUP UPGRADE (NU OPEN normal)
→ dbupgrade (sau catctl.pl catupgrd.sql) ~30-60 min
→ ALTER DATABASE OPEN RESETLOGS
→ @utlrp.sql (recompile invalid objects)
→ ALTER SYSTEM SET COMPATIBLE='21.0.0' SCOPE=SPFILE (ireversibil, după validare)
```
**Probleme cu acest drum la failback:**
- +30-60 min downtime extra în fereastra critică
- Pasul de upgrade dictionary nu a fost testat pe acest dataset
- Eventuale obiecte/PL-SQL incompatibile descoperite după upgrade — sub presiune
- Dacă upgrade-ul eșuează parțial, roll-back complicat (DR e încă opțiune, dar pierzi timp)
**Recomandare ferm:**
- **Failback acut** → instalează 19c. Identic cu DR. Drum testat săptămânal. Fără surprize.
- **Migrare la 21c** → operație separată, planificată, după ce producția e stabilă pe PRIMARY 19c. Două opțiuni:
- **DBUA in-place upgrade** 19c → 21c — păstrează DBID, downtime planificat
- **Data Pump** (expdp/impdp full) — mai curat, dar pierzi DBID + statistici
Scriptul `rman_restore_to_primary.ps1` are check explicit pe major version și abortează dacă găsește ≠ 19, ca să nu se pornească cu jumătate de plan în fereastra de criză.
---
## 1. Precondiții
| Cerință | Verificare |
|---------|------------|
| PRIMARY (10.0.20.36) accesibil pe rețea | `ping 10.0.20.36` |
| Oracle 19c instalat pe PRIMARY (versiune identică cu DR) | `sqlplus -V` pe PRIMARY |
| `ORACLE_SID=ROA`, `ORACLE_HOME` la aceeași cale ca pe DR | vezi `proxmox/lxc108-oracle/roa-windows-setup/` |
| Aplicațiile pot fi puse în mentenanță (downtime ~30 min) | window planificat |
| NFS share `oracle-backups` accesibil de pe PRIMARY (sau plan B: copy via SMB/SCP) | `mount -o ... 10.0.20.202:/mnt/pve/oracle-backups F:` |
| Cont SYSDBA disponibil pe PRIMARY (proaspăt instalat = `system/manager` sau parola setată la instalare) | `sqlplus / as sysdba` |
| Backup ZFS replica pveelite → pve1 a dataset-ului `oracle-backups` rulează | `zfs list -t snapshot \| grep oracle-backups` |
---
## 2. Pași — overview
```
┌──────────────────────────────────────────────────────────────┐
│ FAZA 1: PREPARE — DR în mentenanță, backup final │
│ 1. Anunț downtime aplicații │
│ 2. Read-only pe DR │
│ 3. RMAN full backup pe DR → NFS │
│ 4. Switch + archivelog pentru tranzacții finale │
├──────────────────────────────────────────────────────────────┤
│ FAZA 2: RESTORE — restore pe PRIMARY nou │
│ 5. Mount NFS pe PRIMARY (sau copy backup-uri) │
│ 6. Cleanup PRIMARY (dacă reinstalare a creat DB demo) │
│ 7. Rulare rman_restore_to_primary.ps1 │
│ 8. Verify DB OPEN + tabele │
├──────────────────────────────────────────────────────────────┤
│ FAZA 3: SWITCH — comutare aplicații, reset infra │
│ 9. Update connection strings: 10.0.20.37 → 10.0.20.36 │
│ 10. Test conectivitate aplicații │
│ 11. Reactivează scheduled tasks RMAN backup pe PRIMARY │
│ 12. Stop VM 109 (`qm stop 109`), readuce în `state=stopped`│
│ 13. Verifică ZFS replica + flow nou backup-uri pe NFS │
└──────────────────────────────────────────────────────────────┘
```
---
## FAZA 1 — Prepare
### Pas 1: Anunț downtime aplicații
Tot traficul de scriere trebuie oprit în timpul backup-ului final. Notifică utilizatorii și planifică un window de ~30 min.
### Pas 2: Read-only pe DR (10.0.20.37)
```sql
-- Conectare la DR
sqlplus / as sysdba
-- Verifică tranzacții active
SELECT username, status, count(*) FROM v$session WHERE type='USER' GROUP BY username,status;
-- Pune DB în restricted mode (doar SYSDBA poate scrie)
ALTER SYSTEM ENABLE RESTRICTED SESSION;
-- Sau, mai sigur: read-only mode (necesită shutdown + mount)
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER DATABASE OPEN READ ONLY;
```
> **Atenție**: read-only mode oprește scrierile complet, dar și aplicațiile vor primi erori la INSERT/UPDATE. Restricted session e mai blând dacă aplicațiile pot tolera disconectare scurtă.
### Pas 3: RMAN full backup pe DR
```cmd
REM Pe DR VM (10.0.20.37) - dacă e încă în restricted/read-only
D:\oracle\scripts\rman_backup.bat
```
Backup-ul este scris pe `F:\ROA\autobackup` (NFS mount din `10.0.20.202:/mnt/pve/oracle-backups`).
### Pas 4: Switch + archivelog pentru tranzacții finale
Dacă DB e încă în READ WRITE, capturează ultimele archivelogs:
```sql
ALTER SYSTEM SWITCH LOGFILE;
ALTER SYSTEM ARCHIVE LOG CURRENT;
-- Backup archivelog
-- în RMAN:
RMAN> BACKUP ARCHIVELOG ALL DELETE INPUT;
```
Notează **SCN-ul curent** — necesar pentru verificare ulterioară:
```sql
SELECT CURRENT_SCN FROM v$database;
-- Notează valoarea, ex: 12345678
```
### Pas 5: Verifică backup-urile pe NFS
```bash
ssh root@10.0.20.202 "ls -lt /mnt/pve/oracle-backups/ROA/autobackup/ | head -20"
```
Trebuie să vezi backup-urile recente (data/ora din pasul 3-4).
---
## FAZA 2 — Restore pe PRIMARY
### Pas 6: Mount NFS pe PRIMARY (sau copy backup-uri)
**Opțiunea A (recomandată): NFS mount direct pe PRIMARY**
Pe Windows PRIMARY:
```powershell
# Activare NFS Client (o singură dată, dacă nu e instalat)
Install-WindowsFeature -Name NFS-Client
# Mount NFS share ca F:
mount -o anon,nolock,mtype=hard,timeout=60 10.0.20.202:/mnt/pve/oracle-backups F:
# Verifică
dir F:\ROA\autobackup
```
**Opțiunea B (fallback): Copy via SMB/SCP**
Dacă NFS nu funcționează pe PRIMARY (rar):
```powershell
# Pe PRIMARY, copy de pe DR VM care are F:\ montat:
robocopy \\10.0.20.37\F$\ROA\autobackup F:\ROA\autobackup /MIR /Z
```
### Pas 7: Cleanup PRIMARY (dacă reinstalare a creat DB demo)
Dacă instalarea Oracle a creat o DB demo (ex: ORCL), șterge-o ca să eviți conflicte:
```cmd
REM Pe PRIMARY
sqlplus / as sysdba
SHUTDOWN ABORT;
EXIT;
oradim -delete -sid ORCL
```
Apoi rulează `cleanup_database.ps1` de pe DR (copiat în prealabil pe PRIMARY) sau doar șterge directoarele oradata/recovery_area existente pentru SID `ROA` (atenție: dacă PRIMARY are un `OracleServiceROA` rezidual de la instalare anterioară, oprește și șterge serviciul cu `oradim -delete -sid ROA`).
### Pas 8: Rulează scriptul de restore
```cmd
REM Pe PRIMARY (10.0.20.36)
powershell -ExecutionPolicy Bypass -File D:\oracle\scripts\rman_restore_to_primary.ps1
```
Scriptul `rman_restore_to_primary.ps1` (vezi `proxmox/vm109-windows-dr/scripts/`):
- Folosește același DBID `1363569330`
- Restore din `F:\ROA\autobackup`
- Configurează listener pe `10.0.20.36:1521`
- Setează SPFILE și service `OracleServiceROA` pe AUTOMATIC
### Pas 9: Verifică DB
```sql
sqlplus / as sysdba
SELECT name, open_mode, dbid FROM v$database;
-- Așteptat: ROA, READ WRITE, 1363569330
SELECT current_scn FROM v$database;
-- Trebuie să fie >= SCN-ul notat în pasul 4
SELECT count(*) FROM dba_tables WHERE owner NOT IN ('SYS','SYSTEM','XDB','GSMADMIN_INTERNAL','APPQOSSYS','OUTLN','DBSNMP','WMSYS','OLAPSYS','MDSYS','CTXSYS','EXFSYS','ORDSYS','LBACSYS');
-- Compară cu count-ul de pe DR (înainte de read-only)
-- Test scriere
CREATE TABLE test_failback_check (id NUMBER, ts DATE);
INSERT INTO test_failback_check VALUES (1, SYSDATE);
COMMIT;
SELECT * FROM test_failback_check;
DROP TABLE test_failback_check PURGE;
```
### Pas 10: Reset RMAN catalog
După `OPEN RESETLOGS`, marchează incarnation-ul nou:
```cmd
rman target /
RMAN> LIST INCARNATION;
RMAN> RESET DATABASE TO INCARNATION <număr_nouă_incarnation>;
RMAN> CROSSCHECK BACKUP;
RMAN> DELETE NOPROMPT EXPIRED BACKUP;
```
---
## FAZA 3 — Switch & cleanup
### Pas 11: Update connection strings aplicații
Schimbă în toate aplicațiile:
```
ÎNAINTE: 10.0.20.37:1521/ROA (DR)
DUPĂ: 10.0.20.36:1521/ROA (PRIMARY restaurat)
```
Locuri de modificat (conform `vm109-windows-dr/README.md`):
- Aplicații client (TNS_ADMIN sau connection strings hardcoded)
- Reverse proxy IIS (VM 201) — dacă rutează către Oracle
- Flowise (LXC 104) — variabile de mediu Oracle
- Scheduled tasks/cron-uri ce conectează la Oracle
### Pas 12: Test conectivitate
```bash
# De pe Claude Agent (10.0.20.171)
sqlplus user/pass@10.0.20.36:1521/ROA
# Test din aplicație principală — un read + un write minor
```
### Pas 13: Reactivează scheduled tasks RMAN pe PRIMARY
Pe PRIMARY (Windows Task Scheduler):
- `Oracle RMAN Full Backup` — săptămânal (rulează `D:\oracle\scripts\rman_backup.bat`)
- `Oracle RMAN Incremental` — zilnic (rulează `D:\oracle\scripts\rman_backup_incremental.bat`)
- `Oracle Backup Transfer` — după fiecare backup (rulează `D:\oracle\scripts\transfer_backups.ps1`)
Verifică că rulează corect:
```cmd
REM Forțează un transfer de test
powershell -File D:\oracle\scripts\transfer_backups.ps1
REM Verifică pe Proxmox că au ajuns
ssh root@10.0.20.202 "ls -lt /mnt/pve/oracle-backups/ROA/autobackup/ | head -5"
```
### Pas 14: Oprire VM 109, revenire la state normal
```bash
# Pe pveelite
ssh root@10.0.20.203 "qm stop 109"
# Verifică HA config: VM 109 trebuie să rămână state=stopped, nofailback=1
ssh root@10.0.20.203 "ha-manager config | grep -A2 vm:109"
# Așteptat:
# state stopped
# group ha-prefer-pveelite
# nofailback 1
```
### Pas 15: Verifică ZFS replicare backup-uri
```bash
# Snapshot-urile noi de pe pveelite trebuie să apară pe pve1
ssh root@10.0.20.201 "zfs list -t snapshot rpool/oracle-backups | tail -10"
# Verifică job-ul de replicare
ssh root@10.0.20.203 "cat /var/log/oracle-dr/replication.log | tail -20"
```
### Pas 16: Reactivează test săptămânal DR
Test-ul săptămânal din cron (Sâmbătă 06:00) va rula automat. Verifică prima rulare după failback ca să confirmi că backup-urile noi de pe PRIMARY sunt restaurabile pe VM 109:
```bash
# Sâmbăta următoare, după 06:00
ssh root@10.0.20.203 "ls -lt /var/log/oracle-dr/dr_test_*.log | head -1"
# Apoi tail pentru "PASSED"
```
---
## Roll-back (dacă failback eșuează)
Dacă restore pe PRIMARY eșuează sau verificarea găsește lipsuri de date:
1. **NU șterge** baza de pe DR — e încă fallback-ul tău
2. Pune aplicațiile înapoi pe `10.0.20.37:1521/ROA` (DR)
3. Repornește scrierile pe DR (`ALTER SYSTEM DISABLE RESTRICTED SESSION;` sau `STARTUP` normal dacă era read-only)
4. Investigare separată pe PRIMARY — doar după ce înțelegi cauza, încearcă din nou
---
## Anexă A — Diferențe între DR test și failback real
| Aspect | DR test săptămânal | Failback real |
|--------|---------------------|---------------|
| Sursă backup | NFS, ultimele backup-uri din `F:\` | NFS, **backup proaspăt** făcut de DR în pas 3 |
| TestMode flag | `-TestMode` (skip listener config) | **NU** TestMode (full config + listener) |
| Cleanup post-restore | DA — `cleanup_database.ps1 /AFTER` | **NU** — DB e producția acum |
| Stop VM/server după | DA — `qm stop 109` | **NU** — server rămâne up |
| Connection strings | nu se schimbă | se schimbă pe PRIMARY |
| Scheduled tasks RMAN | nu se ating | se reactivează pe PRIMARY |
## Anexă B — Estimări durată
| Pas | Durată estimată |
|-----|-----------------|
| Pas 2-4: Read-only + final backup pe DR | 5-10 min (depinde mărime DB) |
| Pas 6: NFS mount + verify | 2 min |
| Pas 7-8: Cleanup + restore script | 15-25 min (RMAN restore din 139 backup files) |
| Pas 9-10: Verify + RMAN catalog reset | 5 min |
| Pas 11-12: Switch aplicații + test | 5-10 min |
| **Total downtime** | **~30-50 min** |
---
**Last updated**: 2026-04-25
**Status**: Procedura nu a fost încă executată end-to-end — testează într-un environment de probă (vezi VM 302) înainte de un failback real.

View File

@@ -0,0 +1,452 @@
# RMAN Restore to PRIMARY (failback procedure)
# Restores ROA database on a freshly-installed/reinstalled PRIMARY server (10.0.20.36)
# from backups on F:\ (NFS mount from Proxmox host).
#
# This is the FAILBACK companion to rman_restore_from_zero.ps1:
# - rman_restore_from_zero.ps1: PRIMARY -> DR (during disaster activation)
# - rman_restore_to_primary.ps1 (this): DR -> PRIMARY (after PRIMARY repaired)
#
# See docs/FAILBACK_PROCEDURE.md for the full procedure.
#
# Run as: Administrator on PRIMARY (10.0.20.36)
# Location: D:\oracle\scripts\rman_restore_to_primary.ps1
#
# !!! IMPORTANT — ORACLE VERSION !!!
# This script REQUIRES Oracle Database 19c on PRIMARY and aborts otherwise.
# Backups are 19.3 with compatible=19.0.0. Restoring onto 19c is the path tested
# weekly on DR — same flow, no upgrade step.
#
# Technically 21c can RMAN-restore 19c backups, BUT the database then needs
# STARTUP UPGRADE + dbupgrade (catctl.pl) before OPEN — adds 30-60 min and an
# untested upgrade-during-failback risk. For a calm planned migration to 21c,
# do failback to 19c first, then upgrade in a separate window.
# Use installer WINDOWS.X64_193000_db_home.zip.
#
# Prerequisites:
# 1. Final RMAN backup taken on DR (10.0.20.37) and visible on F:\ROA\autobackup
# 2. Oracle 19c installed on PRIMARY at the same path as on DR (NOT 21c!)
# 3. ORACLE_SID=ROA, no demo DB present (if any, run cleanup_database.ps1 first)
# 4. NFS mount: mount -o anon,nolock,mtype=hard,timeout=60 10.0.20.202:/mnt/pve/oracle-backups F:
#
# Parameters:
# -SkipCleanup: Skip the destructive cleanup step (use only if PRIMARY is already clean)
# -DryRun: Print actions but do not execute (validate config before real run)
param(
[switch]$SkipCleanup,
[switch]$DryRun
)
$ErrorActionPreference = "Continue"
$env:ORACLE_HOME = "C:\Users\Administrator\Downloads\WINDOWS.X64_193000_db_home"
$env:ORACLE_SID = "ROA"
$env:PATH = "$env:ORACLE_HOME\bin;$env:PATH"
$DBID = "1363569330"
$LISTENER_IP = "10.0.20.36"
$LISTENER_PORT = "1521"
$SERVICE_NAME = "ROA"
Write-Host "============================================"
Write-Host "RMAN Restore TO PRIMARY (Failback)"
Write-Host "============================================"
Write-Host ""
Write-Host "Target: PRIMARY $LISTENER_IP"
Write-Host "Database: $SERVICE_NAME"
Write-Host "DBID: $DBID"
Write-Host "Backups: F:\ROA\autobackup (NFS from Proxmox)"
Write-Host "DryRun: $DryRun"
Write-Host ""
# Sanity: confirm we're running on PRIMARY, not on DR
$myIP = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -like "10.0.20.*" }).IPAddress
if ($myIP -eq "10.0.20.37") {
Write-Host "ERROR: This script is for PRIMARY (10.0.20.36), but I'm running on DR (10.0.20.37)" -ForegroundColor Red
Write-Host "Did you mean to run rman_restore_from_zero.ps1 instead?"
exit 1
}
if ($myIP -ne $LISTENER_IP) {
Write-Host "WARNING: My IP is $myIP, expected $LISTENER_IP" -ForegroundColor Yellow
Write-Host "Continue anyway? (Ctrl+C to abort, Enter to continue)"
if (-not $DryRun) { Read-Host }
}
# Verify Oracle version is 19c — RMAN backups are 19.3 / compatible=19.0.0 and
# CANNOT be restored on a 21c+ instance (datafile header version mismatch).
Write-Host "[CHECK] Verifying Oracle version on PRIMARY..."
$sqlplusBin = Join-Path $env:ORACLE_HOME "bin\sqlplus.exe"
if (-not (Test-Path $sqlplusBin)) {
Write-Host "ERROR: sqlplus.exe not found at $sqlplusBin" -ForegroundColor Red
Write-Host " Is Oracle Database 19c installed at ORACLE_HOME=$env:ORACLE_HOME ?"
exit 1
}
$versionOutput = & $sqlplusBin -V 2>&1 | Out-String
# Expected: "SQL*Plus: Release 19.0.0.0.0 ..."
if ($versionOutput -match "Release\s+(\d+)\.(\d+)") {
$majorVersion = [int]$Matches[1]
Write-Host "[CHECK] Detected Oracle major version: $majorVersion"
if ($majorVersion -ne 19) {
Write-Host ""
Write-Host "ERROR: Oracle major version is $majorVersion, this script supports only 19c." -ForegroundColor Red
Write-Host " Backups are 19.3 (compatible=19.0.0)." -ForegroundColor Red
Write-Host ""
Write-Host " 21c CAN technically restore 19c backups, but requires an extra" -ForegroundColor Yellow
Write-Host " STARTUP UPGRADE + dbupgrade step (~30-60 min) which this script" -ForegroundColor Yellow
Write-Host " does NOT perform. Doing a cross-version upgrade during a failback" -ForegroundColor Yellow
Write-Host " is risky — recommended path is: install 19c, failback, then upgrade" -ForegroundColor Yellow
Write-Host " to 21c later in a planned window (DBUA or Data Pump)." -ForegroundColor Yellow
Write-Host ""
Write-Host " Install Oracle Database 19c (WINDOWS.X64_193000_db_home.zip) and re-run." -ForegroundColor Yellow
exit 1
}
Write-Host "[OK] Oracle 19c confirmed"
} else {
Write-Host "WARNING: Could not parse Oracle version from sqlplus output:" -ForegroundColor Yellow
Write-Host $versionOutput
Write-Host "Continue anyway? (yes/no)"
$confirm = Read-Host
if ($confirm -ne "yes") { exit 1 }
}
# Verify NFS mount
if (-not (Test-Path "F:\ROA\autobackup")) {
Write-Host "ERROR: F:\ROA\autobackup not accessible!" -ForegroundColor Red
Write-Host ""
Write-Host "Mount NFS first:"
Write-Host " mount -o anon,nolock,mtype=hard,timeout=60 10.0.20.202:/mnt/pve/oracle-backups F:"
exit 1
}
Write-Host "[OK] F:\ROA\autobackup is accessible"
# Verify backup freshness — warn if newest backup is > 2 hours old
$newest = Get-ChildItem "F:\ROA\autobackup\*.BKP" -ErrorAction SilentlyContinue |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($newest) {
$ageHours = ((Get-Date) - $newest.LastWriteTime).TotalHours
Write-Host "[INFO] Newest backup: $($newest.Name) ($([math]::Round($ageHours,1))h old)"
if ($ageHours -gt 2) {
Write-Host "WARNING: Newest backup is more than 2 hours old." -ForegroundColor Yellow
Write-Host " Did you take a final backup on DR before starting failback?"
Write-Host " (See FAILBACK_PROCEDURE.md Pas 3-4)"
if (-not $DryRun) {
$confirm = Read-Host "Continue anyway? (yes/no)"
if ($confirm -ne "yes") { exit 1 }
}
}
} else {
Write-Host "ERROR: No .BKP files found in F:\ROA\autobackup" -ForegroundColor Red
exit 1
}
# Create local directories
New-Item -ItemType Directory -Path "D:\oracle\temp" -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -ItemType Directory -Path "D:\oracle\logs" -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -ItemType Directory -Path "C:\Users\oracle\oradata\ROA" -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -ItemType Directory -Path "C:\Users\oracle\recovery_area\ROA" -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -ItemType Directory -Path "C:\Users\oracle\admin\ROA\adump" -Force -ErrorAction SilentlyContinue | Out-Null
New-Item -ItemType Directory -Path "C:\Users\oracle\admin\ROA\pfile" -Force -ErrorAction SilentlyContinue | Out-Null
if ($DryRun) {
Write-Host ""
Write-Host "[DRYRUN] Would proceed to STEP 1 (cleanup), STEP 2 (restore), STEP 3 (configure listener)."
Write-Host "[DRYRUN] No changes made. Re-run without -DryRun to execute."
exit 0
}
# ============================================
# STEP 1: CLEANUP — delete any pre-existing DB
# ============================================
if (-not $SkipCleanup) {
Write-Host ""
Write-Host "============================================"
Write-Host "STEP 1: CLEANUP — remove any existing DB"
Write-Host "============================================"
if (Test-Path "D:\oracle\scripts\cleanup_database.ps1") {
& "D:\oracle\scripts\cleanup_database.ps1" /SILENT
if ($LASTEXITCODE -ne 0) {
Write-Host "ERROR: Cleanup failed!" -ForegroundColor Red
exit 1
}
} else {
Write-Host "WARNING: cleanup_database.ps1 not found, doing minimal cleanup..." -ForegroundColor Yellow
$svc = Get-Service -Name "OracleService$SERVICE_NAME" -ErrorAction SilentlyContinue
if ($svc) {
Stop-Service -Name "OracleService$SERVICE_NAME" -Force -ErrorAction SilentlyContinue
& oradim -delete -sid $SERVICE_NAME 2>&1 | Out-Null
}
Get-ChildItem "C:\Users\oracle\oradata\ROA" -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
Get-ChildItem "C:\Users\oracle\recovery_area\ROA" -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
}
Write-Host "[OK] Cleanup complete"
} else {
Write-Host "[SKIP] Cleanup skipped (-SkipCleanup)"
}
# ============================================
# STEP 2: RESTORE
# ============================================
Write-Host ""
Write-Host "============================================"
Write-Host "STEP 2: RESTORE from F:\ backups"
Write-Host "============================================"
# Step 2.1: Create PFILE
$pfilePath = "C:\Users\oracle\admin\ROA\pfile\initROA.ora"
$pfileContent = @"
# Initialization parameters for ROA PRIMARY (failback)
# Auto-generated by rman_restore_to_primary.ps1 $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
db_name=ROA
db_unique_name=ROA
memory_target=2048M
memory_max_target=2048M
control_files=('C:\Users\oracle\oradata\ROA\control01.ctl', 'C:\Users\oracle\recovery_area\ROA\control02.ctl')
db_recovery_file_dest='C:\Users\oracle\recovery_area'
db_recovery_file_dest_size=100G
audit_file_dest='C:\Users\oracle\admin\ROA\adump'
log_archive_format=%t_%s_%r.dbf
compatible=19.0.0
nls_language=AMERICAN
nls_territory=AMERICA
processes=300
sessions=472
diagnostic_dest='C:\Users\oracle'
"@
$pfileContent | Out-File -FilePath $pfilePath -Encoding ASCII
Write-Host "[OK] PFILE created at $pfilePath"
# Step 2.2: Create Oracle service
Write-Host "[2.2] Creating Oracle service $SERVICE_NAME..."
$svc = Get-Service -Name "OracleService$SERVICE_NAME" -ErrorAction SilentlyContinue
if (-not $svc) {
& oradim -new -sid $SERVICE_NAME -startmode auto -pfile $pfilePath 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Host "ERROR: oradim -new failed" -ForegroundColor Red
exit 1
}
Write-Host "[OK] Service OracleService$SERVICE_NAME created"
Start-Sleep -Seconds 3
} else {
Write-Host "[OK] Service OracleService$SERVICE_NAME already exists"
}
# Step 2.3: Startup NOMOUNT
Write-Host "[2.3] Starting database NOMOUNT..."
@"
WHENEVER SQLERROR CONTINUE
SHUTDOWN ABORT;
EXIT;
"@ | & sqlplus -S / as sysdba 2>&1 | Out-Null
@"
STARTUP NOMOUNT PFILE='$pfilePath';
EXIT;
"@ | & sqlplus -S / as sysdba 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Host "ERROR: STARTUP NOMOUNT failed" -ForegroundColor Red
exit 1
}
Write-Host "[OK] Database in NOMOUNT mode"
# Step 2.4: Copy ALL backups from F:\ to local recovery area (failback uses ALL, not test subset)
Write-Host "[2.4] Copying ALL backups from F:\ROA\autobackup to local recovery area..."
$backupFiles = Get-ChildItem "F:\ROA\autobackup\*.BKP" -ErrorAction Continue
if ($backupFiles.Count -lt 2) {
Write-Host "ERROR: Insufficient backups (found $($backupFiles.Count))" -ForegroundColor Red
exit 1
}
Write-Host "[INFO] Copying $($backupFiles.Count) files (~$([math]::Round(($backupFiles | Measure-Object -Property Length -Sum).Sum / 1GB, 2)) GB)"
$copyErrors = @()
foreach ($f in $backupFiles) {
try {
Copy-Item $f.FullName "C:\Users\oracle\recovery_area\ROA\autobackup\" -Force -ErrorAction Stop
} catch {
$copyErrors += "$($f.Name): $_"
}
}
if ($copyErrors.Count -gt 0) {
Write-Host "ERROR: $($copyErrors.Count) copy failures:" -ForegroundColor Red
$copyErrors | ForEach-Object { Write-Host " $_" -ForegroundColor Red }
exit 1
}
Write-Host "[OK] All backups copied"
# Step 2.5: RMAN restore
$rmanScript = "D:\oracle\temp\restore_to_primary.rman"
$logFile = "D:\oracle\logs\restore_to_primary.log"
# Note: RECOVER DATABASE (without NOREDO) — apply all archivelogs through final SCN.
# RECOVER DATABASE NOREDO is for the DR test path where archivelogs may be stale.
# For failback we want every committed transaction up to the final backup.
$rmanContent = @"
SET DBID $DBID;
RUN {
ALLOCATE CHANNEL ch1 DEVICE TYPE DISK;
RESTORE CONTROLFILE FROM AUTOBACKUP;
RELEASE CHANNEL ch1;
}
ALTER DATABASE MOUNT;
CATALOG START WITH 'C:/USERS/ORACLE/RECOVERY_AREA/ROA/AUTOBACKUP' NOPROMPT;
CROSSCHECK BACKUP;
CROSSCHECK ARCHIVELOG ALL;
DELETE NOPROMPT EXPIRED BACKUP;
RUN {
ALLOCATE CHANNEL ch1 DEVICE TYPE DISK;
ALLOCATE CHANNEL ch2 DEVICE TYPE DISK;
RESTORE DATABASE;
RECOVER DATABASE;
RELEASE CHANNEL ch1;
RELEASE CHANNEL ch2;
}
ALTER DATABASE OPEN RESETLOGS;
LIST INCARNATION;
DELETE NOPROMPT OBSOLETE;
EXIT;
"@
$rmanContent | Out-File -FilePath $rmanScript -Encoding ASCII
Write-Host "[2.5] Running RMAN restore (10-25 min)..."
Write-Host " Log: $logFile"
& rman target / cmdfile=$rmanScript log=$logFile
if ($LASTEXITCODE -ne 0) {
Write-Host "ERROR: RMAN restore failed. Last 40 lines of log:" -ForegroundColor Red
Get-Content $logFile -Tail 40
exit 1
}
Write-Host "[OK] RMAN restore complete"
# ============================================
# STEP 3: CONFIGURE — SPFILE, listener, register
# ============================================
Write-Host ""
Write-Host "============================================"
Write-Host "STEP 3: CONFIGURE listener and SPFILE"
Write-Host "============================================"
# Step 3.1: SPFILE
Write-Host "[3.1] Creating SPFILE..."
@"
CREATE SPFILE FROM PFILE='$pfilePath';
EXIT;
"@ | & sqlplus -S / as sysdba 2>&1 | Out-Null
# Step 3.2: Recreate service to use SPFILE
Write-Host "[3.2] Reconfiguring service to use SPFILE..."
@"
SHUTDOWN IMMEDIATE;
EXIT;
"@ | & sqlplus -S / as sysdba 2>&1 | Out-Null
Start-Sleep -Seconds 3
& oradim -delete -sid $SERVICE_NAME 2>&1 | Out-Null
Start-Sleep -Seconds 2
& oradim -new -sid $SERVICE_NAME -startmode auto -spfile 2>&1 | Out-Null
# Step 3.3: Startup with SPFILE
@"
STARTUP;
EXIT;
"@ | & sqlplus -S / as sysdba 2>&1 | Out-Null
Start-Sleep -Seconds 3
Write-Host "[OK] Database started with SPFILE"
# Step 3.4: Configure listener.ora to bind on PRIMARY IP
Write-Host "[3.4] Configuring listener for $LISTENER_IP`:$LISTENER_PORT..."
$listenerOra = "$env:ORACLE_HOME\network\admin\listener.ora"
$listenerContent = @"
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = $LISTENER_IP)(PORT = $LISTENER_PORT))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(GLOBAL_DBNAME = $SERVICE_NAME)
(ORACLE_HOME = $env:ORACLE_HOME)
(SID_NAME = $SERVICE_NAME)
)
)
"@
$listenerContent | Out-File -FilePath $listenerOra -Encoding ASCII
Set-Service -Name "OracleOraDB19Home1TNSListener" -StartupType Automatic -ErrorAction SilentlyContinue
Restart-Service -Name "OracleOraDB19Home1TNSListener" -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 3
# Step 3.5: Register DB with listener
@"
ALTER SYSTEM SET LOCAL_LISTENER='(ADDRESS=(PROTOCOL=TCP)(HOST=$LISTENER_IP)(PORT=$LISTENER_PORT))' SCOPE=BOTH;
ALTER SYSTEM REGISTER;
EXIT;
"@ | & sqlplus -S / as sysdba 2>&1 | Out-Null
Write-Host "[OK] Database registered with listener"
# ============================================
# STEP 4: VERIFY
# ============================================
Write-Host ""
Write-Host "============================================"
Write-Host "STEP 4: VERIFY"
Write-Host "============================================"
@"
SET PAGESIZE 100 LINESIZE 200
COLUMN info FORMAT A100
SELECT 'DB: ' || NAME || ' | OPEN_MODE: ' || OPEN_MODE || ' | DBID: ' || DBID || ' | SCN: ' || CURRENT_SCN AS info FROM V`$DATABASE;
SELECT 'INSTANCE: ' || INSTANCE_NAME || ' | STATUS: ' || STATUS AS info FROM V`$INSTANCE;
SELECT 'LISTENER_HOST: ' || NETWORK_NAME || ' | SERVICE: ' || NAME AS info FROM V`$ACTIVE_SERVICES WHERE NAME = '$SERVICE_NAME';
SELECT 'TABLESPACES: ' || COUNT(*) AS info FROM DBA_TABLESPACES;
SELECT 'DATAFILES: ' || COUNT(*) AS info FROM DBA_DATA_FILES;
SELECT 'USER_TABLES: ' || COUNT(*) AS info FROM DBA_TABLES
WHERE OWNER NOT IN ('SYS','SYSTEM','XDB','GSMADMIN_INTERNAL','APPQOSSYS','OUTLN','DBSNMP','WMSYS','OLAPSYS','MDSYS','CTXSYS','EXFSYS','ORDSYS','LBACSYS');
EXIT;
"@ | & sqlplus -S / as sysdba
# Listener status
Write-Host ""
Write-Host "[4.1] Listener status:"
& lsnrctl status
Write-Host ""
Write-Host "============================================"
Write-Host "Failback restore COMPLETE"
Write-Host "============================================"
Write-Host ""
Write-Host "Restore log: $logFile"
Write-Host ""
Write-Host "Verify SCN above is >= the SCN you noted on DR after final archive log switch."
Write-Host ""
Write-Host "Next steps (manual):"
Write-Host " 1. Test app connectivity: sqlplus user/pass@$LISTENER_IP`:$LISTENER_PORT/$SERVICE_NAME"
Write-Host " 2. Update app connection strings: 10.0.20.37 -> $LISTENER_IP"
Write-Host " 3. Re-enable scheduled tasks: rman_backup.bat, rman_backup_incremental.bat, transfer_backups.ps1"
Write-Host " 4. Stop DR VM: ssh root@10.0.20.203 'qm stop 109'"
Write-Host " 5. RMAN catalog: open 'rman target /' and run RESET DATABASE TO INCARNATION <new>"
Write-Host ""
exit 0

View File

@@ -8,7 +8,7 @@
- **Host Proxmox:** pvemini (10.0.20.201)
- **Storage:** local-zfs (ZFS pool)
- **Status:** Running (onboot: enabled)
- **Rol:** Client aplicații Windows, SQL*Plus client, Reverse proxy IIS, Monitorizare UPS
- **Rol:** Server update aplicații ROA + CONTAFIN, Reverse proxy IIS, Client aplicații Windows, SQL*Plus client, Monitorizare UPS, Scraper BT George (btgo-playwright)
---
@@ -57,16 +57,56 @@ ssh root@10.0.20.201 "qm config 201 | grep -E 'efidisk|virtio'"
- **SSL/TLS Termination** - Certificate Let's Encrypt pentru domenii externe
- **SNI (Server Name Indication)** - Multiple certificate pe același IP
- **Domenii gestionate:**
- roa.romfast.ro
- roa.romfast.ro (+ aplicațiile virtuale `/roaupdate` și `/contafinupdate`)
- roa2web.romfast.ro
- dokploy.romfast.ro
- gitea.romfast.ro
- roa-qr.romfast.ro**NOU** (proxy → LXC 103 Traefik → pdf-qr-app)
- *.roa.romfast.ro**NOU** wildcard (proxy → LXC 103 Traefik → Dokploy apps)
- roa-qr.romfast.ro (proxy → LXC 103 Traefik → pdf-qr-app)
- *.roa.romfast.ro wildcard (proxy → LXC 103 Traefik → Dokploy apps)
**Site-uri IIS active (verificat 2026-04-25):**
| Site | Binding | Path fizic | Rol |
|------|---------|------------|-----|
| Default Web Site | `roa.romfast.ro` :80/:443 + `*` :81 | `C:\inetpub\wwwroot` | Catch-all roa.romfast.ro → 10.0.20.36; conține `/roaupdate` și `/contafinupdate` |
| ROA2WEB | `roa2web.romfast.ro` :80/:443 | `C:\inetpub\roa2web` | Reverse proxy → 10.0.20.36 (web.config-only) |
| Dokploy | `dokploy.romfast.ro` :80/:443 | `C:\inetpub\dokploy` | Proxy → LXC 103 Traefik (Dokploy UI) |
| Gitea | `gitea.romfast.ro` :80/:443 | `C:\inetpub\gitea` | Proxy → LXC 106 Gitea |
| roa-qr | `roa-qr.romfast.ro` :80/:443 | `C:\inetpub\roa-qr` | Proxy → LXC 103 Traefik (pdf-qr-app) |
| roa-apps | `*.roa.romfast.ro` :80/:443 | `C:\inetpub\roa-apps` | Wildcard proxy → LXC 103 Traefik (Dokploy apps) |
**Documentație:** Vezi `vm201-certificat-letsencrypt-iis.md`
**Arhitectură Dokploy:** Vezi `vm201-dokploy-infrastructure.md`
**Server update ROA + CONTAFIN:** Vezi `vm201-roa-update-server.md`
#### 3. Monitorizare UPS
#### 3. Server Update Aplicații ROA + CONTAFIN
- **Sub Default Web Site (`roa.romfast.ro`):**
- `/roaupdate``D:\ROAUPDATE` — distribuie ZIP-urile de update pentru
modulele ROA (ROACONT, ROAFACTURARE, ROAGEST, ROAIMOB, ROARES, ROANOR,
ROASAL, etc. — peste 35 module) plus scripturi DB versionate în SVN.
- `/contafinupdate``D:\APPUPDATESERVERAVFP` — server ActiveVFP (AVFP)
pentru update-urile aplicației CONTAFIN (handler `*.avfp` mapat în IIS).
- **Mecanism update:** stația clientului citește
`https://roa.romfast.ro/roaupdate/<CLIENT>.xml` (manifest VFP cu versiuni
și `fileurl` către `_ARHIVE\<MODUL>\<MODUL>-x.y.z.ZIP`), compară cu
versiunile locale și descarcă diferențele.
- **Clienți configurați:** ROMFAST, ROMPETROL, ARGENTA, AUTOMOTIVE, CLEVER,
CONPRESS, EMS, EUROPEANMETALSERVICES, IMA, ROMCONSTRUCT, SIGMA, VADECO,
VENDING, ACN, AVIS, EDUARD, FRUVIMED, METACOM, METALICA, POLARIS,
PRINTCONCEPT, SOUTH, STEAUANORDULUI, UTMIDIA, VINRAI, VOICU + DEMOROA,
DEVROA, CUSTOMER_4859/4863/4880/4886/4995. Lista completă în
`D:\ROAUPDATE\*.xml`.
- **Build/publicare:** `xmlupdatecreator.exe` regenerează manifestele;
`tasks.bat` face `svn update` pe scripturile DB
(`D:\ROAUPDATE\DATABASE\SCRIPTURI` și `SCRIPTURI_CLAR`).
- **Raportare erori clienți:** endpoint extern
`romfast.dnsalias.com:3000/errors/create_xml` (configurat în
`D:\ROAUPDATE\settings.ini`).
**Documentație:** Vezi `docs/vm201-roa-update-server.md` (structură folder,
format manifest, workflow publicare, riscuri backup).
#### 4. Monitorizare UPS
- **WinNUT Client** - Monitorizare vizuală status UPS în timp real
- **Server NUT:** 10.0.20.201:3493 (pvemini)
- **UPS:** nutdev1 (INNO TECH USB UPS)
@@ -74,6 +114,18 @@ ssh root@10.0.20.201 "qm config 201 | grep -E 'efidisk|virtio'"
**Documentație:** Vezi `ups/docs/INSTALARE-WINNUT.md`
#### 5. Scraper Banca Transilvania George (btgo-playwright)
- **Repo:** `git@gitea.romfast.ro:romfast/btgo-playwright.git`
- **Stack:** Python + `playwright==1.48.0` (Python SDK direct, nu MCP/CLI)
- **Scop:** Extrage solduri conturi + descarcă CSV tranzacții din `go.bancatransilvania.ro`
- **Deploy:** Windows Service (scripturi PowerShell)
- **Notificări:** Telegram (2FA, succes/eroare)
- **Constraint critic:** `HEADLESS=false` obligatoriu — WAF-ul BT blochează headless / Docker.
De aceea rulează pe VM 201 cu sesiune Windows activă.
- **Flow:** `login()``handle_2fa_wait()``read_accounts()``download_transactions()``save_results()`
**Documentație:** Vezi `docs/vm201-btgo-playwright-service.md`
---
## 🔧 Servicii Instalate
@@ -98,14 +150,16 @@ ssh root@10.0.20.201 "qm config 201 | grep -E 'efidisk|virtio'"
- WebSockets Protocol
- HTTP Redirect
- URL Rewrite Module
- **Sites:**
- Default Web Site (roa.romfast.ro)
- Dokploy (dokploy.romfast.ro)
- Gitea (gitea.romfast.ro)
- **Sites (verificat 2026-04-25):**
- Default Web Site (roa.romfast.ro) — conține `/roaupdate` → `D:\ROAUPDATE` și `/contafinupdate` → `D:\APPUPDATESERVERAVFP`; restul proxy → 10.0.20.36
- ROA2WEB (roa2web.romfast.ro) → proxy 10.0.20.36
- Dokploy (dokploy.romfast.ro) → proxy LXC 103 Traefik
- Gitea (gitea.romfast.ro) → proxy LXC 106
- roa-qr (roa-qr.romfast.ro) → proxy LXC 103 Traefik
- roa-apps (*.roa.romfast.ro) → proxy wildcard LXC 103 Traefik
**Configurare SSL:** Vezi `vm201-certificat-letsencrypt-iis.md`
**Server update ROA + CONTAFIN:** Vezi `vm201-roa-update-server.md`
#### 3. Win-ACME
- **Versiune:** v2.2.9.1701
@@ -345,6 +399,8 @@ ssh root@10.0.20.201 "qm delsnapshot 201 pre-update-snapshot"
### Documentație VM 201 Specifică
- **SSL Certificates IIS:** `docs/vm201-certificat-letsencrypt-iis.md`
- **Arhitectură Dokploy + Domenii:** `docs/vm201-dokploy-infrastructure.md`
- **Server Update ROA + CONTAFIN:** `docs/vm201-roa-update-server.md`
- **Scraper BT George (btgo-playwright):** `docs/vm201-btgo-playwright-service.md`
- **Troubleshooting Incident 2025-10-08:** `docs/vm201-troubleshooting-backup-nfs.md`
- **Troubleshooting Pană Curent 2026-01-11:** `docs/vm201-troubleshooting-pana-curent-2026-01-11.md`

View File

@@ -0,0 +1,137 @@
# VM 201 — btgo-playwright (Scraper Banca Transilvania George)
## Obiectiv
Scraper automat pentru `go.bancatransilvania.ro` (Banca Transilvania):
extrage solduri conturi și descarcă CSV-uri de tranzacții. Rulează ca Windows
Service pe VM 201, cu notificări Telegram.
**Repo:** `git@gitea.romfast.ro:romfast/btgo-playwright.git`
---
## Stack Tehnic
| Componentă | Detaliu |
|------------|---------|
| Limbaj | Python (venv dedicat) |
| Browser automation | `playwright==1.48.0` (Python SDK) |
| Mod | API Python direct: `from playwright.sync_api import sync_playwright` |
| Notificări | Telegram Bot API |
| Deploy | Windows Service (PowerShell wrappers) |
| Headless | **`HEADLESS=false` obligatoriu** |
### De ce Playwright Python SDK (și nu MCP / CLI)
Trei variante de a folosi Playwright; aici se folosește **a treia**:
1. **Playwright MCP plugin** — pentru Claude Code (agent control). NU se aplică.
2. **Playwright CLI** — pentru proiecte Node.js. NU se aplică.
3. **Playwright Python SDK** — dependință Python instalată în venv, folosită
programatic din script. ✅ Folosită aici.
Concluzie: setup-ul actual e corect pentru acest use case. Funcționează
independent de Claude.
---
## Constrângere Critică: HEADLESS=false
WAF-ul Banca Transilvania detectează și blochează:
- Rularea în Docker
- Rularea headless
**De aceea:**
- Serviciul rulează direct pe VM 201 (Windows GUI prezent)
- Browser-ul Chromium pornește vizibil (`headless=False`)
- VM 201 trebuie să rămână pornit cu sesiune Windows activă
Orice migrare către container Linux / headless rupe scraper-ul la primul login.
---
## Flow Aplicație
```
login() → autentificare cu user/parolă
handle_2fa_wait() → așteaptă confirmare 2FA (notificare Telegram)
read_accounts() → parsează lista de conturi + solduri
download_transactions() → descarcă CSV per cont
save_results() → persistă date + notificare Telegram (succes/eroare)
```
---
## Deploy ca Windows Service
Serviciul este înregistrat ca Windows Service prin scripturi PowerShell din
repo. Lansează `python.exe` din venv-ul proiectului asupra entry-point-ului
scraper-ului.
Verificare rapidă pe VM 201:
```powershell
# Status serviciu
Get-Service -Name "btgo-playwright*"
# Restart
Restart-Service -Name "btgo-playwright"
# Loguri
Get-EventLog -LogName Application -Source "btgo-playwright" -Newest 20
```
(Numele exact al serviciului și calea instalării sunt în README-ul repo-ului
`btgo-playwright`.)
---
## Dependențe Operaționale
- **VM 201 pornit + sesiune Windows activă** (necesar pentru `HEADLESS=false`)
- **Acces internet** către `go.bancatransilvania.ro`
- **Acces internet** către `api.telegram.org`
- **Chromium instalat de Playwright** (`playwright install chromium` în venv)
---
## Troubleshooting
### Login eșuează / WAF block
1. Verifică că serviciul rulează cu sesiune Windows activă (NU doar RDP
deconectat — sesiunea trebuie să persiste). Vezi mai jos.
2. Confirmă `HEADLESS=false` în config / variabile mediu.
3. Verifică că nu rulează în paralel altă instanță Chromium pe profilul
Playwright (lock pe user data dir).
### 2FA nu primește notificare
Verifică tokenul Telegram și `chat_id` din config. Test rapid:
```powershell
curl "https://api.telegram.org/bot$TOKEN/getMe"
```
### Sesiune Windows se închide după RDP disconnect
Pentru ca browser-ul GUI să rămână activ după RDP disconnect, sesiunea
trebuie păstrată. Variante:
- `tscon` din alt RDP pentru a transfera sesiunea pe consola fizică
- Configurare auto-logon + serviciul lansat în sesiunea consolă
---
## Referințe
- Repo: http://gitea:3000/romfast/btgo-playwright
- Playwright Python docs: https://playwright.dev/python/
- README VM 201: `../README.md`
---
**Ultima actualizare:** 2026-04-25
**Autor:** Marius Mutu

View File

@@ -0,0 +1,295 @@
# VM 201 — Server Update Aplicații ROA + CONTAFIN
## Obiectiv
VM 201 găzduiește pe IIS două puncte de distribuție pentru update-urile
aplicațiilor ROMFAST către clienți:
- **`roa.romfast.ro/roaupdate`** — distribuție ZIP-uri + scripturi DB pentru
modulele ROA (peste 35 module: ROACONT, ROAFACTURARE, ROAGEST, etc.).
- **`roa.romfast.ro/contafinupdate`** — server ActiveVFP (AVFP) pentru
update-uri aplicație CONTAFIN.
Aceste două aplicații virtuale trăiesc sub site-ul **Default Web Site**
(`roa.romfast.ro`) și au path-uri fizice pe **D:\\** (separate de IIS root).
---
## Layout IIS pe VM 201 (recap)
```
Default Web Site (roa.romfast.ro) → C:\inetpub\wwwroot (gol, doar landing IIS)
├── /contafinupdate [Application] → D:\APPUPDATESERVERAVFP (AVFP)
├── /roaupdate [Application] → D:\ROAUPDATE (ZIP + XML)
└── /* (catch-all) → proxy → 10.0.20.36 (ROA Windows prod)
ROA2WEB (roa2web.romfast.ro) → C:\inetpub\roa2web (web.config-only proxy → 10.0.20.36)
Dokploy (dokploy.romfast.ro) → proxy LXC 103 Traefik
Gitea (gitea.romfast.ro) → proxy LXC 106
roa-qr (roa-qr.romfast.ro) → proxy LXC 103 Traefik (pdf-qr-app)
roa-apps (*.roa.romfast.ro) → proxy LXC 103 Traefik (Dokploy apps)
Default Web Site → port 81 (binding intern)
```
---
## /roaupdate — Distribuție Module ROA
**Path fizic:** `D:\ROAUPDATE`
**URL public:** `https://roa.romfast.ro/roaupdate/`
**Web.config:** Windows authentication + directory browse activat
### Mecanism Update
1. Aplicația ROA pe stația clientului (instalată din `ROASTART`) descarcă
`https://roa.romfast.ro/roaupdate/<CLIENT>.xml`.
2. XML-ul listează modulele și versiunile curente pentru clientul respectiv,
plus URL-ul ZIP în `_ARHIVE`.
3. Stația compară versiunile cu cele instalate local.
4. Pentru fiecare modul cu versiune nouă, descarcă
`https://roa.romfast.ro/roaupdate/_ARHIVE/<MODUL>/<MODUL>-x.y.z.ZIP`,
dezarhivează și înlocuiește binarele locale.
### Structura `D:\ROAUPDATE`
| Element | Conținut |
|---------|----------|
| `<CLIENT>.xml` | Manifest update per client (vezi mai jos) |
| `ROASTART_<CLIENT>.xml` | Manifest pentru bootstrap-ul `ROASTART` (COMUNROA, ROAPRINT, USERREPORTS) |
| `_ARHIVE/<MODUL>/` | ZIP-urile efective per versiune (ex: `_ARHIVE\ROACONT\ROACONT-2.11.49.ZIP`) |
| `_UPDATE/` | Buffer de pregătire build-uri noi (LastWrite recent = build activ) |
| `<MODUL>/` | Sursele/proiectele VFP per modul (ex: `ROACONT`, `ROAFACTURARE`, `ROARES`) |
| `DATABASE/SCRIPTURI/`, `DATABASE/SCRIPTURI_CLAR/` | Scripturi SQL versiunate în SVN — pull cu TortoiseSVN |
| `xmlupdatecreator.exe` | Tool VFP de generare a XML-urilor de manifest |
| `tasks.bat` | Job orchestrare: `svn update` pe `SCRIPTURI` + `SCRIPTURI_CLAR`, lansare `tasks\tasks.exe` |
| `settings.ini` | Endpoint raportare erori (`romfast.dnsalias.com:3000/errors/create_xml`) |
| `who9.exe`, `romfast_suport.exe` | Utilitare auxiliare (suport remote + diagnostic VFP9) |
| `firmanoua.zip`, `ROAREGISTRATURA.zip` | Pachete inițializare clienți noi |
### Format Manifest Client
Exemplu fragment din `ROMPETROL.xml`:
```xml
<crsxmloutnew>
<item>ROACONT</item>
<version>2.11.49</version>
<fileurl>\_ARHIVE\ROACONT\ROACONT-2.11.49.ZIP</fileurl>
<usermsg/>
</crsxmloutnew>
```
`<usermsg>` — mesaj opțional afișat user-ului în timpul update-ului
(ex: instrucțiuni manuale, restart obligatoriu).
### Module ROA Distribuite (extras din `ROMFAST.xml`)
```
ROAAPROV ROAAUTO ROACOMENZI ROACONT ROACONTRACTE
ROADECL ROADEF ROADEFSALARII ROADEVIZE ROAFACTURARE
ROAFURNIZORI ROAGEST ROAGRESTAURANT ROAHOTEL ROAHOTELCONFIG
ROAIMOB ROAINCHIDSAL ROAJURIDIC ROALUCRARI ROAMANAGER
ROAMASINI ROANOR ROAOBINV ROAOFERTA ROAOFERTARE
ROAPRETURI ROAPRODUCTIE ROAREGISTRATURA ROARES ROARESTAURANT
ROARETAIL ROASAL ROASALSPEC ROASITFIN ROASITOP
ROASUPORT ROAVIN
```
Modulul `ROASTART` (bootstrap) este publicat separat prin
`ROASTART_<CLIENT>.xml` și include: `COMUNROA`, `ROAPRINT`,
`<CLIENT>_USERREPORTS`.
### Clienți Configurați (extras manifeste)
Manifeste per client găsite în `D:\ROAUPDATE`:
```
ABCVAL ACN ARGENTA AUTOHAUS AUTOMOTIVE
AVIS CAMBRIDGE CLEVER CONPRESS CONPRESSHOLDING
EDUARD EMS EUROPEANMETALSERVICES FRUVIMED HANULPIRATILOR
IDEEA IMA METACOM METACOMBUSINESSSRL METALICA
METALICAD.G.SRL POLARIS PRINTCONCEPT ROMCONSTRUCT ROMFAST
ROMPETROL SIGMA SOUTH STEAUANORDULUI UTMIDIA
VADECO VENDING VENDINGMASTERSRL VINRAI VOICU
DEMOROA DEVROA DEVROA2
CUSTOMER_4859 CUSTOMER_4863 CUSTOMER_4880 CUSTOMER_4886 CUSTOMER_4995
```
### Scripturi DB (SVN)
`tasks.bat` apelează TortoiseSVN pentru a aduce ultimele scripturi:
```bat
TortoiseProc.exe /command:update /path:D:\ROAUPDATE\DATABASE\SCRIPTURI\
TortoiseProc.exe /command:update /path:D:\ROAUPDATE\DATABASE\SCRIPTURI_CLAR\
START D:\ROAUPDATE\DATABASE\SCRIPTURI_CLAR\2026
START D:\ROAUPDATE\tasks\tasks.exe
```
Scripturile sunt versionate într-un repo SVN extern (vezi configul
TortoiseSVN local pentru URL).
### Workflow Publicare Versiune Nouă
1. Build modul VFP în `D:\ROAUPDATE\<MODUL>\`.
2. Generează ZIP în `_ARHIVE\<MODUL>\<MODUL>-x.y.z.ZIP`.
3. Rulează `xmlupdatecreator.exe` pentru regenerarea manifestului
`<CLIENT>.xml` cu noua versiune.
4. Pentru update-uri DB: commit scripturi în SVN (la SCRIPTURI sau
SCRIPTURI_CLAR), apoi `tasks.bat` la următoarea rulare aduce update-ul
pe server.
5. Clienții văd noua versiune la următorul check (la pornire ROA sau
manual din meniu).
---
## /contafinupdate — Server ActiveVFP pentru CONTAFIN
**Path fizic:** `D:\APPUPDATESERVERAVFP`
**URL public:** `https://roa.romfast.ro/contafinupdate/`
**Stack:** ActiveVFP (Visual FoxPro server-side) + IIS handler `AVFPHandler`
### Configurare AVFP
`Web.Config` mapează toate request-urile `*.avfp` (și catch-all `*`) către
`AVFPHandler`, plus modulul `MazeComputer.AspManifestHelpers` pentru
procesarea manifestelor:
```xml
<handlers>
<add verb="*" path="*.avfp" name="AVFPHandler" type="AVFPHandler" />
<add verb="*" path="*" name="AVFPRESTHandler" type="AVFPHandler" />
</handlers>
<defaultDocument>
<files>
<clear />
<add value="default.avfp" />
</files>
</defaultDocument>
<system.web>
<identity impersonate="true" />
</system.web>
```
### `appupdateserver.ini`
Configurarea conexiunilor către sursa de update:
```ini
[general]
host=ROA_CENTRAL
user=soft_serii
password=***
downloadpath=d:\_CONTAFINUPDATE
roadownloadpath=d:\ROAUPDATE\_UPDATE
host_clienti=roa_romfast
user_clienti=romfast
password_clienti=***
host_soft=ROA_CENTRAL
user_soft=soft
password_soft=***
```
(Parolele reale sunt în fișierul de pe VM; nu sunt incluse aici.)
### Componente Cheie
| Fișier | Rol |
|--------|-----|
| `default.avfp` | Entry-point AVFP (default document) |
| `activevfp.dll` (+ `.manifest`) | Handler AVFP nativ |
| `vfp9t.dll`, `VFP9RENU.DLL`, `vfp2c32.fll`, `json.fll` | Runtime VFP9 + extensii |
| `msvcr71.dll` | Runtime VC necesar VFP9 |
| `prg/`, `bin/`, `data/`, `reports/` | Cod, binare, date, rapoarte AVFP |
| `Web.Config` | Mapare handler AVFP |
| `setup603.cmd` | Setup AVFP 6.0.3 (instalare runtime + handler) |
| `log.txt` | Log activitate (rotated manual) |
---
## Operațiuni Curente
### Verificare Stare Update Server (din Proxmox)
```bash
# Status IIS + applicații
ssh root@10.0.20.201 "qm guest exec 201 --timeout 30 -- powershell -Command \
\"Import-Module WebAdministration; Get-WebApplication\""
# Modulele ROA cu update recent (ultima săptămână)
ssh root@10.0.20.201 "qm guest exec 201 --timeout 30 -- powershell -Command \
\"Get-ChildItem 'D:\\ROAUPDATE' | Where-Object { \$_.LastWriteTime -gt (Get-Date).AddDays(-7) } | \
Select-Object Name, LastWriteTime\""
# Verificare manifest client (din browser sau curl)
curl -s https://roa.romfast.ro/roaupdate/ROMFAST.xml | head -50
```
### Test Conectivitate Client
De pe stația clientului (sau VM 201 însăși):
```powershell
# Test acces manifest
Invoke-WebRequest -Uri "https://roa.romfast.ro/roaupdate/ROMFAST.xml" -UseBasicParsing |
Select-Object StatusCode, @{n="Length";e={$_.Content.Length}}
# Test descărcare ZIP
Invoke-WebRequest -Uri "https://roa.romfast.ro/roaupdate/_ARHIVE/ROACONT/ROACONT-2.11.49.ZIP" `
-OutFile "$env:TEMP\test.zip" -UseBasicParsing
```
### Restart IIS (după modificări majore)
```bash
ssh root@10.0.20.201 "qm guest exec 201 --timeout 30 -- cmd /c iisreset"
```
---
## Securitate și Acces
- **/roaupdate** rulează cu `authentication mode="Windows"` în web.config.
Dacă se decide accesul anonim pentru clienți (caz uzual), trebuie
verificat că IIS Anonymous Authentication este activ pe folder.
- **/contafinupdate** folosește `identity impersonate=true` — handler-ul AVFP
rulează cu identitatea utilizatorului IIS curent.
- **TLS:** terminat la nivel de IIS pe `roa.romfast.ro` (certificat Let's
Encrypt — vezi `vm201-certificat-letsencrypt-iis.md`).
- **Endpoint raportare erori:** `romfast.dnsalias.com:3000/errors/create_xml`
(din `D:\ROAUPDATE\settings.ini`) — primește XML-uri de eroare de la
clienți. Nu e găzduit pe VM 201; verifică separat dacă serviciul rulează.
---
## Riscuri și Atenționări
- **Backup `D:\ROAUPDATE` și `D:\APPUPDATESERVERAVFP`:** ambele sunt pe
discul `D:`. Backup-ul Proxmox VZDump al VM 201 le acoperă (snapshot
întreg disk virtio0). Dar pentru recovery rapid al unei versiuni
individuale (`_ARHIVE\<MODUL>\<MODUL>-x.y.z.ZIP` șters accidental) e
util un backup separat al folderului.
- **SVN dependency:** scripturile DB sunt în SVN extern. Dacă serverul SVN
cade, `tasks.bat` eșuează la `svn update`. Verifică URL-ul SVN configurat
în TortoiseSVN local.
- **VFP9 runtime:** `D:\APPUPDATESERVERAVFP` depinde de `vfp9t.dll` și
`msvcr71.dll`. Nu redenumi/șterge.
- **Manifest XML cu encoding `Windows-1252`** — la editare manuală păstrează
encoding-ul (nu salva ca UTF-8) altfel parser-ul VFP de pe stația
clientului poate ceda.
---
## Referințe
- README VM 201: `../README.md`
- IIS SSL / Let's Encrypt: `vm201-certificat-letsencrypt-iis.md`
- Arhitectură domenii Dokploy: `vm201-dokploy-infrastructure.md`
- Aplicație CONTAFIN AVFP: documentație externă (ActiveVFP framework)
---
**Ultima actualizare:** 2026-04-25
**Autor:** Marius Mutu