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
This commit is contained in:
247
docs/lectii-conectare-client-oracle.md
Normal file
247
docs/lectii-conectare-client-oracle.md
Normal file
@@ -0,0 +1,247 @@
|
||||
# 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:`
|
||||
Reference in New Issue
Block a user