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:
@@ -67,7 +67,17 @@ param(
|
||||
[string]$RoaUpdatePath = "D:\ROAUPDATE",
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$ExportPath = "D:\ROA\EXPORT_ORADMP"
|
||||
[string]$ExportPath = "D:\ROA\EXPORT_ORADMP",
|
||||
|
||||
# Parola CONTAFIN_ORACLE, folosita pentru proba de conectare cu Instant
|
||||
# Client-ul vechi. Daca e gresita, proba raporteaza esec - nu instalarea.
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$ContafinPassword = "ROMFASTSOFT",
|
||||
|
||||
# Folderul Instant Client-ului vechi (cel al ROAClient). Implicit se
|
||||
# deduce din TNS_ADMIN sau se cauta sub D:\ROA si C:\ROA.
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$InstantClientDir
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
@@ -835,6 +845,225 @@ EXIT;
|
||||
$extraIssues += "Scheduled task 'ROA Export Oracle' missing"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Conectivitate pentru clientii vechi (Instant Client 10/11)
|
||||
# ------------------------------------------------------------------------
|
||||
# Sectiunea asta exista pentru ca toate esecurile de aici arata, la prima
|
||||
# vedere, ca altceva: ORA-01017 pare parola gresita, ORA-12514 pare baza
|
||||
# oprita. Vezi docs/lectii-conectare-client-oracle.md.
|
||||
Add-ReportSection "Conectivitate client vechi (Instant Client)"
|
||||
|
||||
# --- unde se citeste, de fapt, sqlnet.ora
|
||||
$oraBaseRoot = Split-Path (Split-Path (Split-Path $oraHome -Parent) -Parent) -Parent
|
||||
$homesRoot = Join-Path $oraBaseRoot "product\21c\homes"
|
||||
$adminOh = $null
|
||||
if (Test-Path $homesRoot) {
|
||||
$bh = Get-ChildItem -Path $homesRoot -Directory -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.Name -match "OraDB" } | Select-Object -First 1
|
||||
if ($bh) { $adminOh = Join-Path $bh.FullName "network\admin" }
|
||||
}
|
||||
if (-not $adminOh) { $adminOh = Join-Path $oraHome "network\admin" }
|
||||
|
||||
$sqlnetOh = Join-Path $adminOh "sqlnet.ora"
|
||||
if (Test-Path $sqlnetOh) {
|
||||
$continutOh = Get-Content $sqlnetOh -Raw
|
||||
$verOh = if ($continutOh -match '(?im)^\s*SQLNET\.ALLOWED_LOGON_VERSION_SERVER\s*=\s*(\d+)') { $Matches[1] } else { $null }
|
||||
Add-ReportLine "sqlnet.ora (Oracle Home): $sqlnetOh"
|
||||
if ($verOh) {
|
||||
Add-ReportLine " ALLOWED_LOGON_VERSION_SERVER = $verOh"
|
||||
if ([int]$verOh -gt 11) {
|
||||
Add-ReportLine "[WARNING] Valoare peste 11: clientii 10/11 vor primi ORA-28040."
|
||||
$extraIssues += "ALLOWED_LOGON_VERSION_SERVER=$verOh in $sqlnetOh"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Add-ReportLine "[WARNING] Nu contine ALLOWED_LOGON_VERSION_SERVER."
|
||||
$extraIssues += "ALLOWED_LOGON_VERSION_SERVER missing from $sqlnetOh"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Add-ReportLine "sqlnet.ora (Oracle Home): LIPSA ($sqlnetOh)"
|
||||
$extraIssues += "sqlnet.ora missing from $adminOh"
|
||||
}
|
||||
|
||||
# --- TNS_ADMIN de masina: castiga in fata Oracle Home, si pentru clienti,
|
||||
# si pentru instanta - dar abia de la urmatoarea pornire a serviciului.
|
||||
$tnsAdminM = [Environment]::GetEnvironmentVariable('TNS_ADMIN', 'Machine')
|
||||
Add-ReportLine ""
|
||||
if ($tnsAdminM) {
|
||||
$tnsAdminM = [IO.Path]::GetFullPath($tnsAdminM.TrimEnd('\'))
|
||||
Add-ReportLine "TNS_ADMIN (masina): $tnsAdminM"
|
||||
|
||||
if ($tnsAdminM -ne [IO.Path]::GetFullPath($adminOh.TrimEnd('\'))) {
|
||||
$sqlnetTns = Join-Path $tnsAdminM "sqlnet.ora"
|
||||
if (Test-Path $sqlnetTns) {
|
||||
Add-ReportLine " sqlnet.ora acolo: OK"
|
||||
}
|
||||
else {
|
||||
Add-ReportLine " sqlnet.ora acolo: LIPSA"
|
||||
Add-ReportLine "[WARNING] Instanta citeste TNS_ADMIN-ul de masina de la urmatorul restart."
|
||||
Add-ReportLine " Fara sqlnet.ora acolo, dupa primul reboot toti clientii vechi"
|
||||
Add-ReportLine " iau ORA-28040. Ruleaza din nou 01-setup-database.ps1."
|
||||
$extraIssues += "sqlnet.ora missing from TNS_ADMIN ($tnsAdminM)"
|
||||
}
|
||||
|
||||
$tnsFile = Join-Path $tnsAdminM "tnsnames.ora"
|
||||
if (Test-Path $tnsFile) {
|
||||
$tnsTxt = Get-Content $tnsFile -Raw
|
||||
$areRoa = $tnsTxt -match '(?im)^\s*ROA\s*='
|
||||
$areLsn = $tnsTxt -match '(?im)^\s*LISTENER_XE\s*='
|
||||
$areSablon = $tnsTxt -match 'SERVER_ROA'
|
||||
Add-ReportLine (" tnsnames.ora acolo: alias ROA={0}, LISTENER_XE={1}" -f `
|
||||
$(if ($areRoa) { 'da' } else { 'NU' }), $(if ($areLsn) { 'da' } else { 'NU' }))
|
||||
if ($areSablon) {
|
||||
Add-ReportLine "[WARNING] tnsnames.ora e inca sablonul (HOST=SERVER_ROA). Statiile nu se pot conecta."
|
||||
$extraIssues += "tnsnames.ora still template (SERVER_ROA) in $tnsAdminM"
|
||||
}
|
||||
elseif (-not $areRoa) {
|
||||
Add-ReportLine "[WARNING] Lipseste aliasul ROA. ROAClient nu stie unde e baza."
|
||||
$extraIssues += "TNS alias ROA missing from $tnsFile"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Add-ReportLine " tnsnames.ora acolo: LIPSA"
|
||||
$extraIssues += "tnsnames.ora missing from TNS_ADMIN ($tnsAdminM)"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Add-ReportLine " (coincide cu Oracle Home - nimic de dublat)"
|
||||
}
|
||||
}
|
||||
else {
|
||||
Add-ReportLine "TNS_ADMIN (masina): nesetat (se citeste din Oracle Home)"
|
||||
Add-ReportLine "[NOTA] Daca se instaleaza ROAClient dupa asta, TNS_ADMIN va aparea si"
|
||||
Add-ReportLine " va trebui rulat din nou 01-setup-database.ps1."
|
||||
}
|
||||
|
||||
# --- LOCAL_LISTENER: alias sau adresa literala
|
||||
$llSql = @"
|
||||
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF LINESIZE 300
|
||||
SELECT 'LL:' || value FROM v`$parameter WHERE name = 'local_listener';
|
||||
EXIT;
|
||||
"@
|
||||
$llOut = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName `
|
||||
-Username "SYSTEM" -Password $SystemPassword -SqlCommand $llSql -Silent
|
||||
|
||||
Add-ReportLine ""
|
||||
if ($llOut -match 'LL:(.*)') {
|
||||
$llVal = $Matches[1].Trim()
|
||||
Add-ReportLine "LOCAL_LISTENER: $(if ($llVal) { $llVal } else { '(gol - implicit)' })"
|
||||
if ($llVal -and $llVal -notmatch '\(ADDRESS') {
|
||||
Add-ReportLine "[WARNING] LOCAL_LISTENER e un alias ($llVal), deci depinde de tnsnames.ora."
|
||||
Add-ReportLine " Daca aliasul nu se rezolva la urmatoarea pornire a instantei, aceasta"
|
||||
Add-ReportLine " nu se mai inregistreaza la listener si toti clientii iau ORA-12514."
|
||||
Add-ReportLine " Ruleaza din nou 01-setup-database.ps1 ca sa il fixeze pe adresa literala."
|
||||
$extraIssues += "LOCAL_LISTENER is an alias ($llVal), not a literal address"
|
||||
}
|
||||
}
|
||||
|
||||
# --- verificatoare de parola: fara 10G, clientii vechi iau ORA-01017
|
||||
# SYSTEM lipseste intentionat din lista: fiind utilizator comun, randul lui
|
||||
# din DBA_USERS al PDB-ului ramane cu vechile PASSWORD_VERSIONS chiar dupa
|
||||
# ce parola a fost rescrisa din root, iar autentificarea foloseste oricum
|
||||
# definitia din root. Verificarea care conteaza pentru el e proba de
|
||||
# conectare de mai jos, nu coloana asta.
|
||||
$pvSql = @"
|
||||
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF LINESIZE 300
|
||||
SELECT 'PV:' || username || '|' || password_versions
|
||||
FROM dba_users
|
||||
WHERE username = 'CONTAFIN_ORACLE'
|
||||
OR username IN (SELECT UPPER(schema) FROM CONTAFIN_ORACLE.NOM_FIRME
|
||||
WHERE sters = 0 AND schema IS NOT NULL)
|
||||
ORDER BY username;
|
||||
EXIT;
|
||||
"@
|
||||
$pvOut = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName `
|
||||
-Username "SYSTEM" -Password $SystemPassword -SqlCommand $pvSql -Silent
|
||||
|
||||
Add-ReportLine ""
|
||||
Add-ReportLine "Verificatoare de parola (10G e obligatoriu pentru Instant Client 10/11):"
|
||||
$fara10G = @()
|
||||
foreach ($line in $pvOut -split "`n") {
|
||||
if ($line -match '^PV:([^|]+)\|(.*)$') {
|
||||
$u = $Matches[1].Trim(); $v = $Matches[2].Trim()
|
||||
$are = $v -match '10G'
|
||||
Add-ReportLine (" {0,-24} {1,-16} {2}" -f $u, $v, $(if ($are) { 'OK' } else { 'FARA 10G' }))
|
||||
if (-not $are) { $fara10G += $u }
|
||||
}
|
||||
}
|
||||
if ($fara10G.Count -gt 0) {
|
||||
Add-ReportLine "[WARNING] Conturi fara verificator 10G: $($fara10G -join ', ')"
|
||||
Add-ReportLine " Din Instant Client 10/11 vor da ORA-01017, care pare parola gresita."
|
||||
Add-ReportLine " Se repara rescriind aceeasi parola: ALTER USER <nume> IDENTIFIED BY <parola>;"
|
||||
$extraIssues += "Accounts without 10G password verifier: $($fara10G -join ', ')"
|
||||
}
|
||||
|
||||
# --- proba adevarata: o conectare cu Instant Client-ul vechi
|
||||
Add-ReportLine ""
|
||||
$icDir = $InstantClientDir
|
||||
if (-not $icDir -and $tnsAdminM -and (Test-Path (Join-Path $tnsAdminM "sqlplus.exe"))) {
|
||||
$icDir = $tnsAdminM
|
||||
}
|
||||
if (-not $icDir) {
|
||||
foreach ($radacina in @('D:\ROA', 'C:\ROA', 'D:\', 'C:\')) {
|
||||
if (-not (Test-Path $radacina)) { continue }
|
||||
$g = Get-ChildItem -Path $radacina -Directory -Filter 'instantclient*' -ErrorAction SilentlyContinue |
|
||||
Where-Object { Test-Path (Join-Path $_.FullName 'sqlplus.exe') } | Select-Object -First 1
|
||||
if ($g) { $icDir = $g.FullName; break }
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $icDir) {
|
||||
Add-ReportLine "Proba de conectare: nu am gasit Instant Client pe masina (sarita)"
|
||||
Add-ReportLine "[NOTA] Fara ROAClient instalat aici, proba se face de pe o statie."
|
||||
}
|
||||
else {
|
||||
$icSqlplus = Join-Path $icDir "sqlplus.exe"
|
||||
Add-ReportLine "Instant Client: $icSqlplus"
|
||||
|
||||
$probaSql = Join-Path $env:TEMP "roa_proba_client.sql"
|
||||
Set-Content -Path $probaSql -Encoding ASCII -Value @(
|
||||
'SET FEEDBACK OFF PAGESIZE 0 LINESIZE 200',
|
||||
"SELECT 'PROBA_OK ' || USER FROM DUAL;",
|
||||
'EXIT')
|
||||
|
||||
$ipLan = Get-ServerLanIPv4
|
||||
$tinte = @()
|
||||
$areAliasRoa = $tnsAdminM -and (Test-Path (Join-Path $tnsAdminM 'tnsnames.ora')) -and
|
||||
((Get-Content (Join-Path $tnsAdminM 'tnsnames.ora') -Raw) -match '(?im)^\s*ROA\s*=')
|
||||
if ($areAliasRoa) {
|
||||
$tinte += @{ Nume = 'CONTAFIN_ORACLE / alias ROA'; Sir = "CONTAFIN_ORACLE/$ContafinPassword@ROA" }
|
||||
}
|
||||
if ($ipLan) {
|
||||
$tinte += @{ Nume = "CONTAFIN_ORACLE / $ipLan"; Sir = "CONTAFIN_ORACLE/$ContafinPassword@//${ipLan}:1521/$ServiceName" }
|
||||
}
|
||||
if ($tinte.Count -eq 0) {
|
||||
$tinte += @{ Nume = 'CONTAFIN_ORACLE / localhost'; Sir = "CONTAFIN_ORACLE/$ContafinPassword@//localhost:1521/$ServiceName" }
|
||||
}
|
||||
# SYSTEM: singura verificare valida a verificatorului lui de parola.
|
||||
$gazdaSys = if ($ipLan) { $ipLan } else { 'localhost' }
|
||||
$tinte += @{ Nume = "SYSTEM / $gazdaSys"; Sir = "SYSTEM/$SystemPassword@//${gazdaSys}:1521/$ServiceName" }
|
||||
|
||||
foreach ($t in $tinte) {
|
||||
$iesire = (& $icSqlplus -S -L $t.Sir "@$probaSql" 2>&1 | Where-Object { $_ -match '\S' }) -join ' '
|
||||
if ($iesire -match 'PROBA_OK') {
|
||||
Add-ReportLine (" {0,-32} OK" -f $t.Nume)
|
||||
}
|
||||
else {
|
||||
$eroare = if ($iesire -match '(ORA-\d+|TNS-\d+|SP2-\d+)') { $Matches[1] } else { 'esec' }
|
||||
Add-ReportLine (" {0,-32} ESEC ({1})" -f $t.Nume, $eroare)
|
||||
Add-ReportLine " $iesire"
|
||||
switch ($eroare) {
|
||||
'ORA-01017' { Add-ReportLine " Verifica intai verificatorul 10G, nu parola: ALTER USER ... IDENTIFIED BY <aceeasi parola>;" }
|
||||
'ORA-28040' { Add-ReportLine " sqlnet.ora nu e citit de unde crezi. Verifica TNS_ADMIN de mai sus." }
|
||||
'ORA-12514' { Add-ReportLine " Instanta nu e inregistrata la listener. Verifica LOCAL_LISTENER de mai sus." }
|
||||
}
|
||||
$extraIssues += "Instant Client connect test failed via $($t.Nume): $eroare"
|
||||
}
|
||||
}
|
||||
Remove-Item $probaSql -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
# Final Summary
|
||||
Add-ReportSection "Verification Summary"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user