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:
@@ -17,6 +17,65 @@
|
||||
# Source logging functions
|
||||
. "$PSScriptRoot\logging-functions.ps1"
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
IP-ul din LAN al serverului - cel pe care il vad statiile de lucru.
|
||||
|
||||
.DESCRIPTION
|
||||
Alege adresa IPv4 a interfetei care are ruta implicita, sarind peste:
|
||||
- loopback (127.x) si APIPA (169.254.x);
|
||||
- intervalul Tailscale (100.64.0.0/10). Pe serverele la care intram prin
|
||||
Tailscale, adresa 100.x exista si e perfect functionala pentru noi, dar
|
||||
e inutila intr-un tnsnames.ora dus pe statii: statia nu e in tailnet.
|
||||
Daca nu gaseste nimic potrivit, intoarce sirul gol - apelantul decide.
|
||||
|
||||
.OUTPUTS
|
||||
String. Adresa IPv4 din LAN, sau "" daca nu poate fi determinata.
|
||||
|
||||
.EXAMPLE
|
||||
$ip = Get-ServerLanIPv4
|
||||
#>
|
||||
function Get-ServerLanIPv4 {
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
|
||||
$eTailscale = { param($ip) $ip -match '^100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\.' }
|
||||
|
||||
$adrese = @()
|
||||
try {
|
||||
$adrese = @(Get-NetIPAddress -AddressFamily IPv4 -ErrorAction Stop |
|
||||
Where-Object {
|
||||
$_.IPAddress -notmatch '^(127\.|169\.254\.)' -and
|
||||
-not (& $eTailscale $_.IPAddress)
|
||||
})
|
||||
}
|
||||
catch {
|
||||
# Masini fara modulul NetTCPIP: cadem pe rezolvarea numelui propriu.
|
||||
$ipuri = @([Net.Dns]::GetHostAddresses([Net.Dns]::GetHostName()) |
|
||||
Where-Object { $_.AddressFamily -eq 'InterNetwork' } |
|
||||
ForEach-Object { $_.IPAddressToString } |
|
||||
Where-Object { $_ -notmatch '^(127\.|169\.254\.)' -and -not (& $eTailscale $_) })
|
||||
if ($ipuri.Count -gt 0) { return $ipuri[0] }
|
||||
return ""
|
||||
}
|
||||
|
||||
if ($adrese.Count -eq 0) { return "" }
|
||||
if ($adrese.Count -eq 1) { return $adrese[0].IPAddress }
|
||||
|
||||
# Mai multe placi: o alegem pe cea cu ruta implicita.
|
||||
try {
|
||||
$rute = @(Get-NetRoute -DestinationPrefix '0.0.0.0/0' -ErrorAction Stop |
|
||||
Sort-Object RouteMetric, ifMetric)
|
||||
foreach ($r in $rute) {
|
||||
$potrivire = $adrese | Where-Object { $_.InterfaceIndex -eq $r.ifIndex } | Select-Object -First 1
|
||||
if ($potrivire) { return $potrivire.IPAddress }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return $adrese[0].IPAddress
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get the listener host address.
|
||||
@@ -64,9 +123,7 @@ function Get-ListenerHost {
|
||||
|
||||
# If listener is bound to 0.0.0.0, try to get actual IP
|
||||
if ($listenerHost -eq "0.0.0.0") {
|
||||
$ip = (Get-NetIPAddress -AddressFamily IPv4 |
|
||||
Where-Object { $_.IPAddress -notmatch "^127\." -and $_.PrefixOrigin -ne "WellKnown" } |
|
||||
Select-Object -First 1).IPAddress
|
||||
$ip = Get-ServerLanIPv4
|
||||
if ($ip) { return $ip }
|
||||
return "localhost"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user