merge: fix alias TNS pentru actualizarea ROA + lectia in docs
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X9Sa54oFKpE2XhD6A7NTch
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -22,6 +22,7 @@ cpanel-dns.config.json
|
|||||||
|
|
||||||
# Handoff-uri: stare de lucru, nu documentatie de proiect - raman doar pe disc
|
# Handoff-uri: stare de lucru, nu documentatie de proiect - raman doar pe disc
|
||||||
docs/handoff_*.md
|
docs/handoff_*.md
|
||||||
|
docs/handoff_*.sql
|
||||||
|
|
||||||
# Stare runtime salvata de cluster-shutdown.sh (nu e documentatie)
|
# Stare runtime salvata de cluster-shutdown.sh (nu e documentatie)
|
||||||
proxmox/cluster/scripts/.cluster-state.txt
|
proxmox/cluster/scripts/.cluster-state.txt
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ input/ # Oracle DMP files for import
|
|||||||
- **Instalare/migrare Oracle — care director se folosește**: `proxmox/lxc108-oracle/docs/instalare-si-migrare-oracle.md`
|
- **Instalare/migrare Oracle — care director se folosește**: `proxmox/lxc108-oracle/docs/instalare-si-migrare-oracle.md`
|
||||||
- **ROA Windows setup scripts (XE/SE 21c)**: `proxmox/lxc108-oracle/roa-windows-setup/README.md`
|
- **ROA Windows setup scripts (XE/SE 21c)**: `proxmox/lxc108-oracle/roa-windows-setup/README.md`
|
||||||
- **Conectarea clienților vechi (Instant Client 10/11) la 21c — ORA-28040 / ORA-01017 / ORA-12514**: `docs/lectii-conectare-client-oracle.md`
|
- **Conectarea clienților vechi (Instant Client 10/11) la 21c — ORA-28040 / ORA-01017 / ORA-12514**: `docs/lectii-conectare-client-oracle.md`
|
||||||
|
- **Actualizarea ROA eșuează tăcut fără aliasul TNS pe server (jobul zice SUCCEEDED, dar nu aplică nimic)**: `docs/lectii-actualizare-roa-alias-tns.md`
|
||||||
- **Kit de instalare pentru client (DMP-uri șablon + scripturi, gata de dus la client)**: `proxmox/lxc108-oracle/scripts/build-client-kit.ps1`
|
- **Kit de instalare pentru client (DMP-uri șablon + scripturi, gata de dus la client)**: `proxmox/lxc108-oracle/scripts/build-client-kit.ps1`
|
||||||
- **VM 302 test environment for ROA setup**: `proxmox/vm302-oracle-test/README.md`
|
- **VM 302 test environment for ROA setup**: `proxmox/vm302-oracle-test/README.md`
|
||||||
- **Diagnostic spațiu Oracle la clienți (job zilnic + emailuri)**: `docs/diagnostic-spatiu-clienti.md`
|
- **Diagnostic spațiu Oracle la clienți (job zilnic + emailuri)**: `docs/diagnostic-spatiu-clienti.md`
|
||||||
|
|||||||
158
docs/lectii-actualizare-roa-alias-tns.md
Normal file
158
docs/lectii-actualizare-roa-alias-tns.md
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
# Actualizarea ROA eșuează tăcut fără aliasul TNS pe server
|
||||||
|
|
||||||
|
**Constatat la VADECO, 2026-08-28.** Pe serverul acela actualizarea ROA **nu aplicase niciodată un
|
||||||
|
script**, deși jobul raporta succes de la instalare. Aceeași defecțiune apare la orice client
|
||||||
|
instalat cu kitul înainte de corecția din `01-setup-database.ps1`.
|
||||||
|
|
||||||
|
## Simptomul
|
||||||
|
|
||||||
|
`DBMS_SCHEDULER.RUN_JOB('CONTAFIN_ORACLE.UPDATEROA_ZILNIC')` se termină în ~5-7 secunde și
|
||||||
|
`dba_scheduler_job_run_details` arată **`SUCCEEDED`, `error#=0`**. Dar:
|
||||||
|
|
||||||
|
- nicio schemă nu primește scripturi noi;
|
||||||
|
- `CONTAFIN_ORACLE.UPD_ISTORIC` rămâne cu un rând `stare=2` deschis (fără `dataora_end`), care
|
||||||
|
blochează rularea următoare;
|
||||||
|
- `SCHEMA.versiune` nu capătă rânduri noi.
|
||||||
|
|
||||||
|
## De ce jobul minte
|
||||||
|
|
||||||
|
`PACK_UPDATE` **nu aplică el scripturile**. El generează `D:\DMPDIR\script_master.sql` și
|
||||||
|
**lansează un `sqlplus.exe` extern**, apoi se termină. Jobul raportează starea *lansării*, nu a
|
||||||
|
actualizării. Scriptul generat începe așa:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SET AUTOPRINT OFF
|
||||||
|
WHENEVER SQLERROR EXIT SQL.SQLCODE
|
||||||
|
SPOOL D:\DMPDIR\script_master.log
|
||||||
|
CONNECT CONTAFIN_ORACLE/<parola>@ROA
|
||||||
|
```
|
||||||
|
|
||||||
|
Aliasul (`ROA`) vine din **`CONTAFIN_ORACLE.NOM_FIRME.NUME_SERVER`**. Cu `WHENEVER SQLERROR EXIT`,
|
||||||
|
dacă aliasul nu se rezolvă scriptul **iese la prima linie** și nu face absolut nimic — tăcut, pentru
|
||||||
|
că singura urmă e în spool.
|
||||||
|
|
||||||
|
Eșecul e mascat dublu: jobul zice `SUCCEEDED`, iar raportarea pe email e oricum nefuncțională
|
||||||
|
(`ORA-29279: 503 AUTH command used when not advertised` — vezi `docs/handoff_vadeco-update-roa.md`).
|
||||||
|
|
||||||
|
## De ce nu se rezolvă aliasul
|
||||||
|
|
||||||
|
`sqlplus`-ul lansat de bază **moștenește mediul serviciului Oracle**, nu pe al utilizatorului conectat.
|
||||||
|
Lanțul, la o instalare nouă:
|
||||||
|
|
||||||
|
1. Instalarea pornește instanța. În acel moment `TNS_ADMIN` **nu există** încă la nivel de mașină.
|
||||||
|
2. `01-setup-database.ps1` scrie apoi `TNS_ADMIN` (spre `D:\ROA\instantclient_11_2_0_2`) și pune
|
||||||
|
aliasul `ROA` acolo.
|
||||||
|
3. Serviciul Oracle rulează în continuare cu mediul de la pasul 1 — **fără `TNS_ADMIN`**. Efectul
|
||||||
|
variabilei apare abia la primul restart al serviciului.
|
||||||
|
4. Deci `sqlplus`-ul lansat de bază caută `tnsnames.ora` în **Oracle Home**.
|
||||||
|
5. Oracle 21c XE folosește **read-only Oracle Home**: fișierul real e în
|
||||||
|
`...\product\21c\homes\OraDB21Home1\network\admin\`, nu în `dbhomeXE\network\admin\`
|
||||||
|
(acolo e doar `sqlnet.ora.rooh`).
|
||||||
|
6. Fișierul acela e generat de Oracle și conține `XE`, `LISTENER_XE`, `ORACLR_CONNECTION_DATA` —
|
||||||
|
**dar nu `ROA`**. → `ORA-12154`.
|
||||||
|
|
||||||
|
Capcana perfidă: `tnsping ROA` **reușește** dintr-o sesiune interactivă, pentru că sesiunea ta *are*
|
||||||
|
`TNS_ADMIN`. Nimic nu pare greșit până nu te uiți în spool.
|
||||||
|
|
||||||
|
## Diagnostic în 30 de secunde
|
||||||
|
|
||||||
|
Citește spool-ul — el are adevărul, nu jobul:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Get-Content D:\DMPDIR\script_master.log
|
||||||
|
```
|
||||||
|
|
||||||
|
Un eșec arată exact așa (fișier de ~100 de octeți):
|
||||||
|
|
||||||
|
```
|
||||||
|
28/08/2026 14:26:59
|
||||||
|
ERROR:
|
||||||
|
ORA-12154: TNS:could not resolve the connect identifier specified
|
||||||
|
```
|
||||||
|
|
||||||
|
Reproducere deterministă, în mediul în care rulează baza (fără `TNS_ADMIN`):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Remove-Item Env:TNS_ADMIN -ErrorAction SilentlyContinue
|
||||||
|
"exit" | & "$oraHome\bin\sqlplus.exe" -L -S "CONTAFIN_ORACLE/<parola>@ROA"
|
||||||
|
```
|
||||||
|
|
||||||
|
`ORA-12154` ⇒ actualizarea ROA nu a funcționat niciodată pe serverul acela.
|
||||||
|
|
||||||
|
## Reparația
|
||||||
|
|
||||||
|
Aliasul trebuie să existe **și** în `tnsnames.ora` al Oracle Home-ului, nu doar în cel din
|
||||||
|
`TNS_ADMIN`. Din 2026-08-28, `01-setup-database.ps1` îl scrie în ambele locuri, cu același IP din LAN.
|
||||||
|
|
||||||
|
Manual, pe un server deja instalat:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$f = 'D:\app\Administrator\product\21c\homes\OraDB21Home1\network\admin\tnsnames.ora'
|
||||||
|
Copy-Item $f "$f.bak_$(Get-Date -Format yyyyMMdd_HHmmss)"
|
||||||
|
Add-Content -Path $f -Encoding ASCII -Value @"
|
||||||
|
|
||||||
|
ROA =
|
||||||
|
(DESCRIPTION =
|
||||||
|
(ADDRESS = (PROTOCOL = TCP)(HOST = <IP_LAN_SERVER>)(PORT = 1521))
|
||||||
|
(CONNECT_DATA =
|
||||||
|
(SERVER = DEDICATED)
|
||||||
|
(SERVICE_NAME = XEPDB1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"@
|
||||||
|
```
|
||||||
|
|
||||||
|
Nu rescrie fișierul întreg: `ORACLR_CONNECTION_DATA` e folosit de extproc, iar `LISTENER_XE` de
|
||||||
|
înregistrarea instanței la listener. Adaugă doar aliasul.
|
||||||
|
|
||||||
|
Nu e nevoie de restart — următorul `sqlplus` lansat de bază citește fișierul la conectare.
|
||||||
|
|
||||||
|
### După reparație
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 1. Deblochează rularea rămasă agățată, daca e cazul
|
||||||
|
exec CONTAFIN_ORACLE.PACK_UPDATE.IncheiereActualizare;
|
||||||
|
commit;
|
||||||
|
|
||||||
|
-- 2. Rulează
|
||||||
|
exec DBMS_SCHEDULER.RUN_JOB('CONTAFIN_ORACLE.UPDATEROA_ZILNIC', use_current_session => FALSE);
|
||||||
|
exec DBMS_SCHEDULER.RUN_JOB('CONTAFIN_ORACLE.UPDATERTVAI_ZILNIC', use_current_session => FALSE);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cum verifici că actualizarea chiar s-a aplicat
|
||||||
|
|
||||||
|
**Nu te uita la statusul jobului.** Dovada reală e în două locuri:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Spool-ul trebuie sa aiba zeci de linii si zero ORA-
|
||||||
|
(Select-String -Path D:\DMPDIR\script_master.log -Pattern 'ORA-|ERROR' | Measure-Object).Count
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Fiecare schema de firma trebuie sa aiba scriptul zilei
|
||||||
|
select max(data_script) from VADECO.versiune;
|
||||||
|
select count(*) from VADECO.versiune where script_final like '%2026_08_28%';
|
||||||
|
|
||||||
|
-- Si nicio rulare agatata
|
||||||
|
select count(*) from CONTAFIN_ORACLE.UPD_ISTORIC where stare = 2; -- trebuie 0
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Atenție la o iluzie:** rândurile din `SCHEMA.versiune` vin **cu dump-ul** la un import. O schemă
|
||||||
|
> proaspăt importată pare „la zi" fără ca actualizarea să fi rulat vreodată local. Compară cu data
|
||||||
|
> scriptului efectiv aplicat azi, nu cu `max(data_script)` în absolut.
|
||||||
|
|
||||||
|
## Capcane conexe, plătite deja
|
||||||
|
|
||||||
|
- `UPD_ISTORIC` are coloanele `DATAORA_START` / `DATAORA_END`, nu `DATA_START`.
|
||||||
|
- `VERSIUNE` are `SCRIPT_FINAL` / `DATA_SCRIPT`, nu `NUME_SCRIPT`.
|
||||||
|
- `UPD_LOG.EXPLICATIE` e `CLOB` și sparge `to_char()` cu `ORA-22835` peste 4000 de caractere.
|
||||||
|
Folosește `dbms_lob.substr(explicatie, 180, 1)`.
|
||||||
|
- Un `stare=2` rămas deschis blochează rularea următoare — de aceea `IncheiereActualizare` e primul
|
||||||
|
pas după orice eșec.
|
||||||
|
|
||||||
|
## Legături
|
||||||
|
|
||||||
|
- Lecții de conectare a clienților vechi (`ORA-28040` / `ORA-01017` / `ORA-12514`):
|
||||||
|
`docs/lectii-conectare-client-oracle.md`
|
||||||
|
- Instalarea și configurarea: `proxmox/lxc108-oracle/roa-windows-setup/README.md`
|
||||||
|
- SMTP-ul nefuncțional care maschează erorile: `docs/handoff_vadeco-update-roa.md`
|
||||||
@@ -353,6 +353,16 @@ EXEC DBMS_SCHEDULER.ENABLE('CONTAFIN_ORACLE.UPDATEROA_ZILNIC');
|
|||||||
EXEC DBMS_SCHEDULER.ENABLE('CONTAFIN_ORACLE.UPDATERTVAI_ZILNIC');
|
EXEC DBMS_SCHEDULER.ENABLE('CONTAFIN_ORACLE.UPDATERTVAI_ZILNIC');
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **`SUCCEEDED` la jobul de update NU înseamnă că s-a aplicat ceva.** Jobul doar
|
||||||
|
> lansează un `sqlplus` extern și se termină în ~5 secunde. Dacă aliasul TNS din
|
||||||
|
> `NOM_FIRME.NUME_SERVER` (de regulă `ROA`) nu se rezolvă **în mediul serviciului
|
||||||
|
> Oracle**, scriptul generat iese la prima linie cu `ORA-12154` și actualizarea nu
|
||||||
|
> rulează niciodată — tăcut, pentru că jobul raportează succes, iar emailul de
|
||||||
|
> eroare nu pleacă. `01-setup-database.ps1` scrie aliasul și în `tnsnames.ora` al
|
||||||
|
> Oracle Home-ului tocmai pentru asta. Verifică `D:\DMPDIR\script_master.log` și
|
||||||
|
> `SCHEMA.versiune`, nu statusul jobului. Ghidul complet:
|
||||||
|
> [`../../../docs/lectii-actualizare-roa-alias-tns.md`](../../../docs/lectii-actualizare-roa-alias-tns.md).
|
||||||
|
|
||||||
Serverul ROMFAST de update e documentat în
|
Serverul ROMFAST de update e documentat în
|
||||||
[`../../vm201-windows/docs/vm201-roa-update-server.md`](../../vm201-windows/docs/vm201-roa-update-server.md).
|
[`../../vm201-windows/docs/vm201-roa-update-server.md`](../../vm201-windows/docs/vm201-roa-update-server.md).
|
||||||
|
|
||||||
|
|||||||
@@ -364,6 +364,69 @@ NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT)
|
|||||||
Write-LogSuccess "sqlnet.ora configured at $sqlnetOra"
|
Write-LogSuccess "sqlnet.ora configured at $sqlnetOra"
|
||||||
Write-Log "Old client compatibility enabled (SQLNET.ALLOWED_LOGON_VERSION=8)"
|
Write-Log "Old client compatibility enabled (SQLNET.ALLOWED_LOGON_VERSION=8)"
|
||||||
|
|
||||||
|
# Gazda pentru aliasurile TNS: IP-ul din LAN, nu localhost, ca acelasi
|
||||||
|
# fisier sa functioneze si copiat pe statiile de lucru.
|
||||||
|
$gazdaTns = Get-ServerLanIPv4
|
||||||
|
if (-not $gazdaTns) {
|
||||||
|
$gazdaTns = $env:COMPUTERNAME
|
||||||
|
Write-LogWarning "Nu am putut determina IP-ul din LAN; folosesc numele masinii ($gazdaTns) in tnsnames.ora."
|
||||||
|
}
|
||||||
|
|
||||||
|
$roaAliasBlock = @"
|
||||||
|
# Aliasul ROA - necesar si serverului, nu doar statiilor. Vezi comentariul din
|
||||||
|
# 01-setup-database.ps1 si docs/lectii-actualizare-roa-alias-tns.md.
|
||||||
|
ROA =
|
||||||
|
(DESCRIPTION =
|
||||||
|
(ADDRESS = (PROTOCOL = TCP)(HOST = $gazdaTns)(PORT = $Port))
|
||||||
|
(CONNECT_DATA =
|
||||||
|
(SERVER = DEDICATED)
|
||||||
|
(SERVICE_NAME = $ServiceName)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"@
|
||||||
|
|
||||||
|
# Aliasul ROA trebuie sa existe SI in tnsnames.ora al Oracle Home-ului,
|
||||||
|
# nu doar in cel din TNS_ADMIN (instantclient).
|
||||||
|
#
|
||||||
|
# PACK_UPDATE (actualizarea ROA) genereaza D:\DMPDIR\script_master.sql si
|
||||||
|
# lanseaza un sqlplus EXTERN care incepe cu
|
||||||
|
# CONNECT CONTAFIN_ORACLE/...@<NOM_FIRME.NUME_SERVER>
|
||||||
|
# adica, in practica, @ROA. Scriptul are WHENEVER SQLERROR EXIT, deci
|
||||||
|
# iese la prima linie daca aliasul nu se rezolva - iar jobul
|
||||||
|
# UPDATEROA_ZILNIC raporteaza TOTUSI SUCCEEDED, pentru ca el doar
|
||||||
|
# lanseaza procesul si se termina in ~5 secunde.
|
||||||
|
#
|
||||||
|
# sqlplus-ul lansat de baza mosteneste mediul serviciului Oracle. Daca
|
||||||
|
# instanta a pornit INAINTE ca TNS_ADMIN de masina sa existe - cazul
|
||||||
|
# normal la o instalare noua, unde variabila o scriem noi mai jos -
|
||||||
|
# serviciul nu are TNS_ADMIN si cade pe tnsnames.ora de aici. Fara
|
||||||
|
# aliasul de mai jos: ORA-12154, si actualizarea ROA nu se aplica
|
||||||
|
# niciodata, complet tacut.
|
||||||
|
# Constatat la VADECO pe 2026-08-28, dupa migrare: actualizarea nu
|
||||||
|
# rulase niciodata pe serverul acela. Detalii in
|
||||||
|
# docs/lectii-actualizare-roa-alias-tns.md.
|
||||||
|
$homeTnsNames = Join-Path $networkAdmin "tnsnames.ora"
|
||||||
|
if (Test-Path $homeTnsNames) {
|
||||||
|
$stampHomeTns = Get-Date -Format 'yyyyMMdd_HHmmss'
|
||||||
|
Copy-Item $homeTnsNames "$homeTnsNames.bak_$stampHomeTns" -Force
|
||||||
|
# Scot un eventual alias ROA existent (rulare anterioara, alt IP) si
|
||||||
|
# il rescriu, ca operatia sa fie idempotenta. Restul fisierului -
|
||||||
|
# XE, LISTENER_XE, ORACLR_CONNECTION_DATA - ramane neatins: sunt
|
||||||
|
# generate de Oracle si folosite de extproc si de inregistrarea la
|
||||||
|
# listener.
|
||||||
|
# Sterg si comentariile lipite imediat deasupra lui "ROA =" (fara
|
||||||
|
# rand gol intre): sunt antetul blocului nostru si, altfel, s-ar
|
||||||
|
# acumula cate o copie la fiecare rulare. Un rand gol opreste
|
||||||
|
# potrivirea, deci antetul fisierului ramane intact.
|
||||||
|
$continutTns = [regex]::Replace((Get-Content $homeTnsNames -Raw),
|
||||||
|
'(?ms)(^[ \t]*#[^\r\n]*\r?\n)*^[ \t]*ROA[ \t]*=.*?(?=^[ \t]*[A-Za-z0-9_\.]+[ \t]*=|\z)', '')
|
||||||
|
$continutTns = $continutTns.TrimEnd() + "`r`n`r`n" + $roaAliasBlock
|
||||||
|
} else {
|
||||||
|
$continutTns = "# tnsnames.ora - generat de 01-setup-database.ps1`r`n`r`n" + $roaAliasBlock
|
||||||
|
}
|
||||||
|
Set-Content -Path $homeTnsNames -Value $continutTns -Encoding ASCII
|
||||||
|
Write-LogSuccess "tnsnames.ora (Oracle Home): alias ROA -> ${gazdaTns}:$Port/$ServiceName"
|
||||||
|
|
||||||
# Daca exista TNS_ADMIN la nivel de masina, ACELA castiga - si pentru
|
# Daca exista TNS_ADMIN la nivel de masina, ACELA castiga - si pentru
|
||||||
# clienti, si pentru procesele bazei, care mostenesc variabilele de
|
# clienti, si pentru procesele bazei, care mostenesc variabilele de
|
||||||
# masina la pornirea serviciului. Instalarea ROAClient il pune sa arate
|
# masina la pornirea serviciului. Instalarea ROAClient il pune sa arate
|
||||||
@@ -404,12 +467,8 @@ NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT)
|
|||||||
# instantclient-ului, aliasul nu se mai rezolva, instanta
|
# instantclient-ului, aliasul nu se mai rezolva, instanta
|
||||||
# nu se inregistreaza la listener si TOTI clientii iau
|
# nu se inregistreaza la listener si TOTI clientii iau
|
||||||
# ORA-12514 - cu baza sus si listenerul pornit.
|
# ORA-12514 - cu baza sus si listenerul pornit.
|
||||||
$gazdaTns = Get-ServerLanIPv4
|
# $gazdaTns e calculat mai sus, o singura data, ca aliasul ROA
|
||||||
if (-not $gazdaTns) {
|
# sa fie identic in ambele fisiere.
|
||||||
$gazdaTns = $env:COMPUTERNAME
|
|
||||||
Write-LogWarning "Nu am putut determina IP-ul din LAN; folosesc numele masinii ($gazdaTns) in tnsnames.ora."
|
|
||||||
}
|
|
||||||
|
|
||||||
$tnsNames = Join-Path $tnsAdminFull "tnsnames.ora"
|
$tnsNames = Join-Path $tnsAdminFull "tnsnames.ora"
|
||||||
if (Test-Path $tnsNames) {
|
if (Test-Path $tnsNames) {
|
||||||
$aliasuriVechi = @([regex]::Matches((Get-Content $tnsNames -Raw),
|
$aliasuriVechi = @([regex]::Matches((Get-Content $tnsNames -Raw),
|
||||||
|
|||||||
Reference in New Issue
Block a user