Files
ROMFASTSQL/docs/lectii-conectare-client-oracle.md
Marius a5ea8c7ffa fix(oracle): instanta citeste TNS_ADMIN-ul de masina, nu Oracle Home
Continuarea corectiei 3 din ec66377. Aceea rezolva doar jumatatea vizibila a
problemei; jumatatea ascunsa ar fi lovit la primul reboot al serverului, dupa
plecarea de la client. Gasit la VADECO, verificat pe loc.

1. ORA-12514 la toti clientii, cu baza perfect sanatoasa.

   TNS_ADMIN de masina nu decide doar de unde se citeste sqlnet.ora: instanta
   rezolva de acolo si aliasurile din tnsnames.ora. La Oracle XE LOCAL_LISTENER
   e implicit aliasul LISTENER_XE, definit doar in tnsnames.ora din Oracle Home.
   Cand serviciul reporneste dupa ce ROAClient a pus TNS_ADMIN pe folderul
   instantclient-ului, aliasul nu se mai rezolva, instanta nu se mai
   inregistreaza la listener, si atunci: v$instance OPEN, v$pdbs READ WRITE,
   listener pornit pe 0.0.0.0:1521, lsnrctl arata doar CLRExtProc, si absolut
   orice client primeste ORA-12514.

   Capcana e de timp, nu de continut: o instanta pornita inainte ca TNS_ADMIN
   sa existe nu il vede, deci instalarea pare impecabila si cade la primul
   reboot. Reprodus la VADECO cu un simplu Restart-Service OracleServiceXE.

   Pasul 01 scrie acum si tnsnames.ora in TNS_ADMIN (aliasul ROA pentru
   ROAClient - sablonul livrat cu el arata spre HOST=SERVER_ROA, inexistent -
   plus LISTENER_XE pentru instanta) si, mai important, fixeaza LOCAL_LISTENER
   pe adresa literala. Doar asta din urma rezista si daca ROAClient se
   instaleaza dupa kit, sau daca folderul instantclient se muta.

2. ORA-01017 desi parola e corecta.

   Cu SQLNET.ALLOWED_LOGON_VERSION_SERVER=8 serverul autentifica orice client
   pre-12c pe baza verificatorului 10G. Un cont fara 10G in PASSWORD_VERSIONS
   nu se mai poate conecta din Instant Client 10/11, si eroarea nu e ORA-28040,
   ci ORA-01017 - fix cea care trimite pe pista parolei. Dupa o instalare 21c,
   SYSTEM are doar 11G 12C; CONTAFIN_ORACLE scapa doar pentru ca pasul 01 ii
   rescrie parola dupa ce a scris sqlnet.ora. Pasul 01 rescrie acum si parola
   lui SYSTEM, din CDB$ROOT, cu aceeasi valoare.

   Subtilitate: interogat din PDB, PASSWORD_VERSIONS al unui utilizator comun
   ramane cel vechi si dupa reparatie, desi autentificarea foloseste definitia
   din root si functioneaza. Coloana nu e o dovada pentru SYSTEM; conectarea e.

3. Pasul 07 verifica acum ce nu se vede pe hartie.

   Toate cele trei erori trec de verificarile de pana acum: fisierul exista,
   parametrul e setat, contul e OPEN, obiectele sunt valide. Sectiunea noua
   "Conectivitate client vechi (Instant Client)" verifica unde se citeste
   efectiv sqlnet.ora, daca tnsnames.ora din TNS_ADMIN mai e sablonul, daca
   LOCAL_LISTENER e alias sau adresa, ce verificatoare de parola au conturile,
   si - singurul lucru care le prinde pe toate - face o conectare adevarata cu
   Instant Client-ul gasit pe masina. La esec, raportul spune si unde sa te
   uiti. Parametri noi: -ContafinPassword, -InstantClientDir.

4. Get-ServerLanIPv4, in biblioteca.

   Pe serverele la care intram prin Tailscale, un tnsnames.ora cu 100.x nu duce
   nicaieri de pe o statie. Functia alege IP-ul din LAN sarind peste Tailscale
   (100.64.0.0/10) si APIPA, dupa ruta implicita cand sunt mai multe placi.
   Get-ListenerHost o foloseste si el la fallback-ul pe 0.0.0.0, unde inainte
   lua prima adresa nefiltrata.

La VADECO a mai fost nevoie de o corectie manuala, in afara kitului: listener.ora
avea HOST = <nume>.ts.net, deci pornirea listenerului depindea de Tailscale.
Regula generala e in documentatie.

Detaliile, cu dovezi si comenzi de diagnostic: docs/lectii-conectare-client-oracle.md

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SzF1hf4aFS1tmJWpPMiwGp
2026-08-25 22:14:45 +03:00

248 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Lecții — conectarea clienților vechi (Instant Client 10/11) la Oracle 21c
Scris pe 2026-08-25, după migrarea VADECO pe server nou. Toate lucrurile de mai
jos au fost **observate direct**, nu deduse din documentație, iar fiecare a fost
verificat pe serverul clientului (`WIN-16COB435C1E`, `192.168.101.111`,
Oracle XE 21.3, CDB `XE` + PDB `XEPDB1`).
Numitorul comun al tuturor: **niciuna dintre erori nu arată spre cauza ei.**
`ORA-01017` pare parolă greșită, `ORA-12514` pare baza oprită, `ORA-28040` pare o
problemă de client. De aceea au ajuns aici, într-un fișier separat.
---
## 1. `TNS_ADMIN` de mașină bate Oracle Home — și pentru instanță, nu doar pentru clienți
ROAClient își pune `TNS_ADMIN` de mașină pe folderul propriului Instant Client
(la VADECO: `d:\roa\instantclient_11_2_0_2`). Variabila nu e citită doar de
`sqlplus`-ul din folderul acela: **serviciul Oracle o moștenește la pornire**,
iar procesele bazei citesc de acolo și `sqlnet.ora`, și `tnsnames.ora`.
Capcana e de timp, nu de conținut. O instanță pornită **înainte** ca `TNS_ADMIN`
să existe nu o vede, deci continuă să citească din Oracle Home și totul pare în
regulă. Efectul apare **abia la primul restart al serviciului** — adică la primul
reboot al serverului, de obicei după ce am plecat de la client.
### 1a. Fără `sqlnet.ora` acolo → `ORA-28040` la toți clienții vechi
`SQLNET.ALLOWED_LOGON_VERSION_SERVER=8` scris frumos în
`ORACLE_BASE_HOME\network\admin\sqlnet.ora` devine irelevant: instanța citește din
`TNS_ADMIN`, nu găsește nimic, cade pe implicitul 21c (`12`) și refuză orice
client pre-12c.
### 1b. Fără `tnsnames.ora` acolo → `ORA-12514` la **toți** clienții
Asta e cea gravă, și e cea pe care am prins-o efectiv. La Oracle XE,
`LOCAL_LISTENER` e implicit **aliasul** `LISTENER_XE`, definit numai în
`tnsnames.ora` din Oracle Home. După restart, instanța încearcă să rezolve
aliasul din `TNS_ADMIN`-ul nou, nu-l găsește, **nu se mai înregistrează la
listener** — și atunci:
- baza e sus (`v$instance` = `OPEN`, `v$pdbs` = `READ WRITE`);
- serviciul Windows e `Running`;
- listenerul e `Running` și ascultă pe `0.0.0.0:1521`;
- `lsnrctl status` arată **doar** `CLRExtProc`;
- **absolut orice** client primește `ORA-12514`.
Adică: server aparent perfect, aplicație complet moartă. Exact ce s-ar fi
întâmplat la VADECO la primul reboot.
### Reparația
Trei lucruri, toate făcute acum de `01-setup-database.ps1`:
1. `sqlnet.ora` scris **și** în `TNS_ADMIN`, identic cu cel din Oracle Home;
2. `tnsnames.ora` scris în `TNS_ADMIN`, cu aliasul `ROA` (pentru ROAClient) **și**
`LISTENER_XE` (pentru instanță);
3. `LOCAL_LISTENER` fixat pe **adresă literală**, ca să nu mai depindă de niciun
fișier de rețea:
```sql
ALTER SYSTEM SET LOCAL_LISTENER='(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.101.111)(PORT=1521))' SCOPE=BOTH;
ALTER SYSTEM REGISTER;
```
Punctul 3 e singurul care rezistă și dacă ROAClient se instalează **după** kit,
sau dacă cineva mută folderul Instant Client. Punctele 1 și 2 rămân necesare
pentru `sqlnet.ora` și pentru aliasul `ROA`, dar au aceeași fragilitate: sunt
corecte doar față de valoarea lui `TNS_ADMIN` din momentul rulării. De asta pasul
07 le reverifică.
### Diagnostic rapid
```powershell
[Environment]::GetEnvironmentVariable('TNS_ADMIN','Machine')
Test-Path "$([Environment]::GetEnvironmentVariable('TNS_ADMIN','Machine'))\sqlnet.ora"
& "$env:ORACLE_HOME\bin\lsnrctl.exe" status | Select-String 'Service "'
```
Dacă `lsnrctl status` nu listează serviciul PDB-ului dar baza e `OPEN`, e exact
cazul 1b. Confirmarea:
```sql
SELECT value FROM v$parameter WHERE name = 'local_listener';
```
Un alias (`LISTENER_XE`) în loc de un `(ADDRESS=...)` = bombă cu ceas.
---
## 2. `ALLOWED_LOGON_VERSION_SERVER=8` cere verificator **10G**, altfel `ORA-01017`
Cu setarea asta, serverul autentifică orice client pre-12c pe baza
verificatorului **10G**. Un cont care nu are `10G` în `PASSWORD_VERSIONS` nu se
mai poate conecta din Instant Client 10/11 — și eroarea **nu** e `ORA-28040`, e:
```
ORA-01017: invalid username/password; logon denied
```
Adică fix eroarea care te trimite să verifici parola. Parola e corectă: același
cont, aceeași parolă, se conectează perfect din `sqlplus`-ul 21c de pe server.
După o instalare curată de 21c, `SYSTEM` are doar `11G 12C`. `CONTAFIN_ORACLE`
are `10G 11G 12C` **doar pentru că** pasul 01 îi rescrie parola *după* ce a scris
`sqlnet.ora` — verificatoarele se generează după setarea activă în momentul
`CREATE`/`ALTER USER`, nu retroactiv.
### Reparația
Rescrierea **aceleiași** parole. Nu se schimbă nimic pentru nimeni, doar se
regenerează verificatoarele:
```sql
-- utilizator local (schemele de firmă, CONTAFIN_ORACLE) — din PDB
ALTER USER CONTAFIN_ORACLE IDENTIFIED BY "ROMFASTSOFT";
-- utilizator comun (SYSTEM) — obligatoriu din CDB$ROOT
ALTER USER SYSTEM IDENTIFIED BY "romfastsoft" CONTAINER=ALL;
```
Pasul 01 face acum ambele.
### Sub-capcană: `PASSWORD_VERSIONS` minte pentru utilizatorii comuni
Interogat **din PDB**, `DBA_USERS.PASSWORD_VERSIONS` pentru `SYSTEM` rămâne
`11G 12C` și după `ALTER USER ... CONTAINER=ALL` din root. Rândul local nu se
împrospătează, dar autentificarea folosește definiția din root — și funcționează.
Măsurat la VADECO, în aceeași secundă:
| | `PASSWORD_VERSIONS` |
|---|---|
| `CDB$ROOT` | `10G 11G 12C` |
| `XEPDB1` | `11G 12C` |
| conectare reală din Instant Client 11.2 | **merge** |
Concluzie: pentru utilizatorii comuni, coloana nu e o dovadă. Singura verificare
validă e o conectare adevărată. De asta pasul 07 nu se mai uită la coloană pentru
`SYSTEM`, ci îl probează.
---
## 3. `listener.ora` legat de un nume care depinde de Tailscale
Instalarea de Oracle a pus în `listener.ora` și `tnsnames.ora`:
```
(ADDRESS = (PROTOCOL = TCP)(HOST = vadeco-server.tailf7372d.ts.net)(PORT = 1521))
```
Adică numele MagicDNS al mașinii în tailnet. Ascultarea în sine e corectă
(listenerul se leagă tot pe `0.0.0.0:1521`, deci LAN-ul e servit), dar **pornirea
listenerului ajunge să depindă de Tailscale**: la boot, dacă `tailscaled` nu a
ridicat încă resolverul, numele nu se rezolvă.
Înlocuit cu numele mașinii, care se rezolvă local întotdeauna:
```
(ADDRESS = (PROTOCOL = TCP)(HOST = WIN-16COB435C1E)(PORT = 1521))
```
Verificat după restartul listenerului: tot `0.0.0.0:1521`, toate serviciile
înregistrate, clienții se conectează.
**Regulă:** pe serverele la care intrăm prin Tailscale, niciun fișier de
configurare Oracle nu are voie să conțină un nume `*.ts.net` sau o adresă
`100.64.0.0/10`. Din același motiv, `Get-ServerLanIPv4` (în
`scripts/lib/oracle-functions.ps1`) sare peste intervalul Tailscale când alege
IP-ul pentru `tnsnames.ora` și `LOCAL_LISTENER` — un `tnsnames.ora` cu `100.x`
copiat pe o stație nu duce nicăieri, stația nu e în tailnet.
---
## 4. Proba de conectare cu clientul vechi e obligatorie
Toate cele trei probleme de mai sus trec de verificările „pe hârtie": fișierul
există, parametrul e setat, contul e `OPEN`, obiectele sunt valide. Singurul
lucru care le prinde pe toate e o conectare adevărată, cu **clientul vechi**, nu
cu `sqlplus`-ul 21c de pe server.
```powershell
$ic = 'D:\ROA\instantclient_11_2_0_2'
'select ''PROBA_OK '' || user from dual;' , 'exit' | Set-Content -Encoding ascii C:\Windows\Temp\t.sql
# prin aliasul din tnsnames.ora — asa se conecteaza ROAClient
& "$ic\sqlplus.exe" -S -L "CONTAFIN_ORACLE/ROMFASTSOFT@ROA" '@C:\Windows\Temp\t.sql'
# prin EZConnect, pe IP-ul din LAN — ocoleste tnsnames.ora, izoleaza cauza
& "$ic\sqlplus.exe" -S -L "CONTAFIN_ORACLE/ROMFASTSOFT@//192.168.101.111:1521/XEPDB1" '@C:\Windows\Temp\t.sql'
```
`-L` (o singură încercare) nu e opțional: fără el, la o parolă refuzată `sqlplus`
cere parola de la tastatură și **agață** o sesiune neinteractivă până la timeout.
Diferența dintre cele două forme e utilă la diagnostic: dacă EZConnect merge și
aliasul nu, problema e în `tnsnames.ora`; dacă niciuna nu merge, problema e la
server (verificator de parolă, `sqlnet.ora` sau înregistrarea la listener).
---
## 5. Ce verifică acum pasul 07
`07-verify-installation.ps1` a primit secțiunea **„Conectivitate client vechi
(Instant Client)"**, care acoperă toate lecțiile de mai sus:
| Verificare | Prinde |
|---|---|
| `ALLOWED_LOGON_VERSION_SERVER` din `sqlnet.ora` de Oracle Home | valoare > 11 |
| `sqlnet.ora` există în `TNS_ADMIN` de mașină | 1a — `ORA-28040` la primul reboot |
| `tnsnames.ora` din `TNS_ADMIN`: alias `ROA`, `LISTENER_XE`, urme de șablon (`SERVER_ROA`) | 1b — `ORA-12514` la primul reboot; stații care nu găsesc baza |
| `LOCAL_LISTENER` e adresă literală, nu alias | 1b, cazul de fond |
| `PASSWORD_VERSIONS` conține `10G` pentru `CONTAFIN_ORACLE` și schemele de firmă | 2 — `ORA-01017` |
| conectare reală cu Instant Client-ul găsit pe mașină: `CONTAFIN_ORACLE` prin alias și prin EZConnect, `SYSTEM` prin EZConnect | tot ce a scăpat |
La eșec, raportul spune și unde să te uiți: `ORA-01017` → verificatorul 10G,
`ORA-28040` → `TNS_ADMIN`, `ORA-12514` → `LOCAL_LISTENER`.
Parametri noi: `-ContafinPassword` (implicit `ROMFASTSOFT`) și
`-InstantClientDir` (implicit: din `TNS_ADMIN`, altfel căutat sub `D:\ROA`,
`C:\ROA`, `D:\`, `C:\`). Dacă nu există Instant Client pe server, proba se
raportează ca sărită, nu ca eșec.
---
## 6. Capcane de mediu, plătite deja
- **`powershell -Command -` prin SSH trunchiază scriptul.** Un script cu blocuri
pe mai multe linii trimis pe stdin se execută parțial: comenzile de după primul
bloc multi-linie pur și simplu nu rulează, fără nicio eroare. Se pierde timp
crezând că o comandă a eșuat. Soluția: `scp` fișierul `.ps1` și
`ssh ... powershell -NoProfile -ExecutionPolicy Bypass -File C:\Windows\Temp\x.ps1`.
- **`sqlplus / as sysdba` nu merge într-o sesiune SSH** pe serverul ăsta
(`ORA-01017`) — autentificarea pe sistem de operare nu primește token-ul de
grup. Se folosește `sys/<parola>@//localhost:1521/XE as sysdba`, sau bequeath
cu `ORACLE_SID` setat și parolă explicită.
- **Un `Restart-Service OracleServiceXE` durează 2–4 minute** (oprire + pornire +
înregistrare). Comenzile de la distanță au nevoie de timeout pe măsură;
altfel timeout-ul taie sesiunea în mijlocul unui restart.
---
## Legături
- Kit și flux complet: `proxmox/lxc108-oracle/roa-windows-setup/README.md`
- Migrarea VADECO: `docs/handoff_vadeco-migrare.md` (nu intră în git)
- Capcana cu discul `C:` de pe același server: aceeași migrare, secțiune separată
în handoff — procesul Oracle nu ajunge la nicio cale de pe `C:`