fix(oracle): calea DMPDIR devine parametru; sqlnet.ora ajunge unde e citit

Gasite la instalarea de productie VADECO (Oracle 21c XE, Windows Server 2019).

1. Pe serverul VADECO procesul Oracle nu poate atinge nicio cale de pe C:,
   nici macar C:\Windows\Temp, desi ACL-urile sunt corecte si serviciul ruleaza
   ca NT SERVICE\OracleServiceXE. D: merge cu exact acelasi grant. Calea DMP
   era insa hardcodata "C:\DMPDIR" in 01, 02, 05, 06 si in biblioteca, deci
   instalarea nu se putea muta. Acum e parametrul -DmpDir, expus ca /dmpdest:
   in FAZA1.cmd si FAZA2.cmd si transmis tuturor pasilor.

   Cel mai perfid era pasul 02: recrea DIRECTORY DMPDIR pe 'C:\DMPDIR' peste
   valoarea pusa de 01. Chiar cu restul instalarii mutata, SYS.NEWSCHEMA ar fi
   cautat FIRMANOUA.dmp in alta parte, iar adaugarea unei firme noi ar fi picat
   peste luni, fara legatura vizibila cu instalarea.

2. New-OracleDirectory compara doar siruri de caractere: verifica ce scrie in
   dba_directories, nu daca baza chiar poate scrie acolo. Acum face un
   UTL_FILE round-trip si esueaza pe loc, cu explicatia cauzei. Inainte,
   directorul inutilizabil trecea drept bun si importul cadea abia in impdp cu
   ORA-29283, la zeci de linii distanta. Valoarea de retur nici nu era
   verificata in 01/03/06 - de aici si "True" ratacit in log.

3. Instalarea ROAClient seteaza TNS_ADMIN de masina spre instantclient-ul ei.
   Serviciul Oracle mosteneste variabilele de masina, deci citea sqlnet.ora de
   acolo - unde nu exista niciunul - si nu din Oracle Home, unde il scria pasul
   01. Compatibilitatea pentru clienti vechi nu se aplica, iar statiile ar fi
   primit ORA-28040 cu fisierul scris corect, in locul gresit. Pasul 01 scrie
   acum sqlnet.ora si in TNS_ADMIN cand difera.

4. Pasul 05 lega schemele de DMP-uri cu "^$schema[_\.]", deci schema DANUBE
   putea primi DANUBE_20200914.dmp - datele altei firme, fara avertisment.
   Numele exact are acum intaietate, prefixul se accepta doar daca e unic, iar
   ambiguitatea se raporteaza.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SzF1hf4aFS1tmJWpPMiwGp
This commit is contained in:
Marius
2026-08-25 21:18:43 +03:00
parent 5a746990ce
commit ec66377e0f
9 changed files with 2787 additions and 2673 deletions

3
.gitignore vendored
View File

@@ -16,3 +16,6 @@ input/
# Secrets - real cPanel DNS hook config holds an API token (template is committed)
cpanel-dns.config.json
**/cpanel-dns.config.json
# Cygwin/Git-Bash crash dumps
*.stackdump

View File

@@ -34,6 +34,11 @@ REM /parolavechi:<parola> parola SYS de pe serverul vechi
REM /licente:<fisier.sql> licente dintr-un fisier, in loc de retea
REM /roaupdate:<cale> radacina oglinzii (implicit D:\ROAUPDATE)
REM /export:<cale> director export (implicit D:\ROA\EXPORT_ORADMP)
REM /dmpdest:<cale> de unde citeste baza DMP-urile (implicit C:\DMPDIR)
REM Pe unele masini procesul Oracle nu ajunge la C:\ deloc
REM (ORA-29283 la orice cale de pe C:, inclusiv C:\Windows\Temp,
REM desi ACL-urile sunt corecte). Atunci pune-l pe discul unde
REM e Oracle Home: /dmpdest:D:\DMPDIR
REM /faralicente sari peste pasul 09
REM /faraiis sari peste pasul 10
REM /farabackup sari peste pasul 11
@@ -89,6 +94,7 @@ if /i "!OPT!"=="/parolavechi" set "PAROLAVECHI=!VAL!"
if /i "!OPT!"=="/licente" set "LICENTEFIS=!VAL!"
if /i "!OPT!"=="/roaupdate" set "ROAUPDATE=!VAL!"
if /i "!OPT!"=="/export" set "EXPORTDIR=!VAL!"
if /i "!OPT!"=="/dmpdest" set "DMPDEST=!VAL!"
shift
goto :parsare
@@ -102,6 +108,7 @@ echo.
echo Kit: %KIT%
echo Id client: %IDCLIENT%
echo SMTP: %SMTP%
echo DMP: %DMPDEST%
echo ROAUPDATE: %ROAUPDATE%
echo Export: %EXPORTDIR%
if not "%VECHI%"=="" echo Server vechi: %VECHI% / %SERVICIUVECHI%
@@ -139,7 +146,7 @@ REM [2/9] 01 - baza si userul
REM ---------------------------------------------------------------------------
echo.
echo [2/9] 01-setup-database.ps1
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\01-setup-database.ps1"
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\01-setup-database.ps1" -DmpDir "%DMPDEST%"
if errorlevel 1 goto :esec_01
REM ---------------------------------------------------------------------------
@@ -147,7 +154,7 @@ REM [3/9] 02 - obiectele SYS
REM ---------------------------------------------------------------------------
echo.
echo [3/9] 02-create-sys-objects.ps1
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\02-create-sys-objects.ps1"
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\02-create-sys-objects.ps1" -DmpDir "%DMPDEST%"
if errorlevel 1 goto :esec_02
REM ---------------------------------------------------------------------------
@@ -155,7 +162,7 @@ REM [4/9] 03 - CONTAFIN_ORACLE
REM ---------------------------------------------------------------------------
echo.
echo [4/9] 03-import-contafin.ps1
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\03-import-contafin.ps1"
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\03-import-contafin.ps1" -DmpDir "%DMPDEST%"
set RC=!ERRORLEVEL!
REM Codul 5 e normal: Data Pump raporteaza "completed with errors" pentru
REM ORA-31684 (userul e creat deja de pasul 01) si ORA-39082 (warning-uri de

View File

@@ -28,6 +28,8 @@ REM /smtp:<server> server SMTP (implicit mail.romfast.ro)
REM /roaupdate:<cale> radacina oglinzii (implicit D:\ROAUPDATE)
REM /export:<cale> director export (implicit D:\ROA\EXPORT_ORADMP)
REM /dmp:<cale> de unde se copiaza DMP-urile (implicit <kit>\DMPDIR)
REM /dmpdest:<cale> de unde le citeste baza (implicit C:\DMPDIR)
REM Trebuie sa fie aceeasi valoare ca la FAZA1.
REM /faraschema nu regenera schema.txt
REM
REM Exemple:
@@ -72,6 +74,7 @@ if /i "!OPT!"=="/smtp" set "SMTP=!VAL!"
if /i "!OPT!"=="/roaupdate" set "ROAUPDATE=!VAL!"
if /i "!OPT!"=="/export" set "EXPORTDIR=!VAL!"
if /i "!OPT!"=="/dmp" set "DMPSURSA=!VAL!"
if /i "!OPT!"=="/dmpdest" set "DMPDEST=!VAL!"
shift
goto :parsare
@@ -150,12 +153,12 @@ if errorlevel 1 goto :esec_drop
echo.
echo 01-setup-database.ps1 (recreare user)
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\01-setup-database.ps1"
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\01-setup-database.ps1" -DmpDir "%DMPDEST%"
if errorlevel 1 goto :esec_01
echo.
echo 03-import-contafin.ps1
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\03-import-contafin.ps1"
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\03-import-contafin.ps1" -DmpDir "%DMPDEST%"
set RC=!ERRORLEVEL!
if "!RC!"=="0" goto :dupa_03
if "!RC!"=="5" (
@@ -177,7 +180,7 @@ REM [3/6] Schemele de firma
REM ---------------------------------------------------------------------------
echo.
echo [3/6] 05-import-companies.ps1
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\05-import-companies.ps1"
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "%KIT%scripts\05-import-companies.ps1" -DumpDirectory "%DMPDEST%" -DmpDir "%DMPDEST%"
if errorlevel 1 goto :esec_05
REM ---------------------------------------------------------------------------

View File

@@ -87,7 +87,13 @@ param(
[switch]$SkipSqlnetConfig,
[Parameter(Mandatory = $false)]
[switch]$ResetSystemPassword
[switch]$ResetSystemPassword,
# Calea fizica a directorului Oracle DMPDIR. Aceeasi valoare trebuie data
# tuturor pasilor care ating DMPDIR (01, 02, 03, 05, 06), altfel ultimul
# care ruleaza repozitioneaza obiectul si ceilalti citesc din alta parte.
[Parameter(Mandatory = $false)]
[string]$DmpDir = "C:\DMPDIR"
)
$ErrorActionPreference = 'Stop'
@@ -355,6 +361,31 @@ NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT)
Write-LogSuccess "sqlnet.ora configured at $sqlnetOra"
Write-Log "Old client compatibility enabled (SQLNET.ALLOWED_LOGON_VERSION=8)"
# Daca exista TNS_ADMIN la nivel de masina, ACELA castiga - si pentru
# clienti, si pentru serviciul Oracle, care mosteneste variabilele de
# masina. Instalarea ROAClient il pune sa arate spre instantclient-ul
# ei (D:\ROA\instantclient_11_2_0_2), unde de obicei nu exista niciun
# sqlnet.ora: atunci serverul cade pe valorile implicite, adica
# ALLOWED_LOGON_VERSION_SERVER=12, si clientii vechi primesc ORA-28040
# desi fisierul de mai sus a fost scris corect. Scriem acelasi continut
# si acolo, altfel toata configurarea de compatibilitate e degeaba.
$tnsAdmin = [Environment]::GetEnvironmentVariable('TNS_ADMIN', 'Machine')
if ($tnsAdmin) {
$tnsAdminFull = [IO.Path]::GetFullPath($tnsAdmin.TrimEnd('\'))
if ($tnsAdminFull -ne [IO.Path]::GetFullPath($networkAdmin.TrimEnd('\'))) {
Write-LogWarning "TNS_ADMIN de masina arata spre $tnsAdminFull - acolo se citeste sqlnet.ora, nu din Oracle Home."
if (-not (Test-Path $tnsAdminFull)) {
New-Item -ItemType Directory -Path $tnsAdminFull -Force | Out-Null
}
$tnsSqlnet = Join-Path $tnsAdminFull "sqlnet.ora"
if (Test-Path $tnsSqlnet) {
Copy-Item $tnsSqlnet "$tnsSqlnet.bak_$(Get-Date -Format 'yyyyMMdd_HHmmss')" -Force
}
Set-Content -Path $tnsSqlnet -Value $sqlnetContent -Encoding ASCII
Write-LogSuccess "sqlnet.ora scris si in TNS_ADMIN: $tnsSqlnet"
}
}
# Restart listener to apply changes
Write-Log "Restarting listener to apply sqlnet.ora changes..."
$lsnrctl = Join-Path $oraHome "bin\lsnrctl.exe"
@@ -536,11 +567,12 @@ EXIT;
# Step 9: Create DMPDIR directory for Data Pump
Write-LogSection "Creating Data Pump Directory"
$dmpDir = "C:\DMPDIR"
New-OracleDirectory -OracleHome $oraHome -ServiceName $ServiceName `
-Password $SystemPassword -DirectoryName "DMPDIR" -DirectoryPath $dmpDir
if (-not (New-OracleDirectory -OracleHome $oraHome -ServiceName $ServiceName `
-Password $SystemPassword -DirectoryName "DMPDIR" -DirectoryPath $DmpDir)) {
throw "Directorul Data Pump DMPDIR ($DmpDir) nu e utilizabil de catre baza. Vezi mesajele de mai sus."
}
Write-LogSuccess "Data Pump directory DMPDIR created: $dmpDir"
Write-LogSuccess "Data Pump directory DMPDIR created: $DmpDir"
# Step 10: Reset passwords with 10G verifier (required for old client auth)
# After sqlnet.ora is configured, passwords must be reset to generate 10G hash

View File

@@ -49,7 +49,13 @@ param(
[string]$SystemPassword = "romfastsoft",
[Parameter(Mandatory = $false)]
[string]$SqlScriptsDir
[string]$SqlScriptsDir,
# Calea fizica pe care o primeste obiectul Oracle DIRECTORY DMPDIR.
# Trebuie sa fie aceeasi in toti pasii, altfel unul dintre ei repozitioneaza
# tacut directorul si SYS.NEWSCHEMA nu-si mai gaseste FIRMANOUA.dmp.
[Parameter(Mandatory = $false)]
[string]$DmpDir = "C:\DMPDIR"
)
$ErrorActionPreference = 'Stop'
@@ -109,7 +115,7 @@ PROMPT
-- Create DMPDIR if not exists
PROMPT Creating directory DMPDIR...
CREATE OR REPLACE DIRECTORY DMPDIR AS 'C:\DMPDIR';
CREATE OR REPLACE DIRECTORY DMPDIR AS '$DmpDir';
GRANT READ, WRITE ON DIRECTORY DMPDIR TO PUBLIC;
-- AUTH_DETALII table

View File

@@ -127,8 +127,13 @@ try {
Write-Log "Created directory: $DmpDir"
}
New-OracleDirectory -OracleHome $oraHome -ServiceName $ServiceName `
-Password $SystemPassword -DirectoryName "DMPDIR" -DirectoryPath $DmpDir
# Valoarea de retur nu era verificata - de aici si "True" ratacit in log.
# Mai rau: cand directorul nu era utilizabil, importul mergea mai departe si
# cadea abia in impdp cu ORA-29283, la zeci de linii distanta de cauza.
if (-not (New-OracleDirectory -OracleHome $oraHome -ServiceName $ServiceName `
-Password $SystemPassword -DirectoryName "DMPDIR" -DirectoryPath $DmpDir)) {
throw "Directorul Data Pump DMPDIR ($DmpDir) nu e utilizabil de catre baza. Vezi mesajele de mai sus."
}
# Copy dump file to DMPDIR if not already there
$dumpFileName = Split-Path -Path $DumpFile -Leaf

View File

@@ -56,6 +56,12 @@ param(
[Parameter(Mandatory = $false)]
[string]$DumpDirectory = "C:\DMPDIR",
# Calea fizica a directorului Oracle DMPDIR - de acolo citeste baza.
# Implicit e aceeasi cu DumpDirectory, deci nu trebuie data decat cand
# DMP-urile stau in alta parte decat directorul pe care il vede baza.
[Parameter(Mandatory = $false)]
[string]$DmpDir,
[Parameter(Mandatory = $false)]
[string]$OracleHome,
@@ -173,12 +179,22 @@ EXIT;
$notFoundList = @()
foreach ($schema in $companyData.Keys) {
# Try to find matching dump file (case-insensitive)
$matchingFile = $dumpFiles | Where-Object {
$_.BaseName -ieq $schema -or
$_.BaseName -imatch "^$schema[_\.]" -or
$_.BaseName -imatch "^${schema}$"
} | Select-Object -First 1
# Numele exact are intaietate. Fara asta, schema DANUBE putea primi
# DANUBE_20200914.dmp - datele altei firme, fara niciun avertisment.
$matchingFile = $dumpFiles | Where-Object { $_.BaseName -ieq $schema } | Select-Object -First 1
if (-not $matchingFile) {
$escaped = [regex]::Escape($schema)
$prefixed = @($dumpFiles | Where-Object { $_.BaseName -imatch "^$escaped[_\.]" })
if ($prefixed.Count -eq 1) {
$matchingFile = $prefixed[0]
}
elseif ($prefixed.Count -gt 1) {
$nume = ($prefixed | ForEach-Object { $_.Name }) -join ', '
Write-LogWarning " - ${schema}: $($prefixed.Count) DMP-uri ambigue ($nume) - redenumeste-l pe cel bun in $schema.dmp"
}
}
if ($matchingFile) {
$importList += [PSCustomObject]@{
@@ -226,7 +242,7 @@ EXIT;
}
# Ensure DMPDIR exists
$dmpDir = "C:\DMPDIR"
$dmpDir = if ($DmpDir) { $DmpDir } else { $DumpDirectory }
if (-not (Test-Path -Path $dmpDir)) {
New-Item -ItemType Directory -Path $dmpDir -Force | Out-Null
}

View File

@@ -74,7 +74,11 @@ param(
[string]$TemplateSchema,
[Parameter(Mandatory = $false)]
[switch]$Force
[switch]$Force,
# Calea fizica a directorului Oracle DMPDIR, asa cum a fost pusa la instalare.
[Parameter(Mandatory = $false)]
[string]$DmpDir = "C:\DMPDIR"
)
$ErrorActionPreference = 'Stop'
@@ -194,13 +198,15 @@ EXIT;
}
# Setup DMPDIR
$dmpDir = "C:\DMPDIR"
$dmpDir = $DmpDir
if (-not (Test-Path -Path $dmpDir)) {
New-Item -ItemType Directory -Path $dmpDir -Force | Out-Null
}
New-OracleDirectory -OracleHome $oraHome -ServiceName $ServiceName `
-Password $SystemPassword -DirectoryName "DMPDIR" -DirectoryPath $dmpDir
if (-not (New-OracleDirectory -OracleHome $oraHome -ServiceName $ServiceName `
-Password $SystemPassword -DirectoryName "DMPDIR" -DirectoryPath $dmpDir)) {
throw "Directorul Data Pump DMPDIR ($dmpDir) nu e utilizabil de catre baza."
}
# Copy dump to DMPDIR
$dumpFileName = Split-Path -Path $TemplateDump -Leaf

View File

@@ -742,6 +742,42 @@ EXIT;
$verifiedPath = $Matches[1].Trim()
if ($verifiedPath.ToUpper() -eq $DirectoryPath.ToUpper()) {
Write-Log "Oracle directory $DirectoryName created pointing to $DirectoryPath"
# Pana aici s-au comparat doar siruri de caractere. Adevarata intrebare
# e daca procesul Oracle poate scrie efectiv acolo, si raspunsul poate fi
# nu chiar cu ACL-uri corecte pe folder: contul virtual al serviciului
# (NT SERVICE\OracleServiceXE) nu are traversare pe radacina lui C:, asa
# ca un DMPDIR pe C:\ pica abia in mijlocul importului, cu un
# ORA-29283 "nonexistent file or path" care nu arata spre cauza.
$testSql = @"
SET PAGESIZE 0 FEEDBACK OFF HEADING OFF VERIFY OFF ECHO OFF SERVEROUTPUT ON
DECLARE
f UTL_FILE.FILE_TYPE;
BEGIN
f := UTL_FILE.FOPEN('$DirectoryName', 'roa_write_test.tmp', 'w');
UTL_FILE.PUT_LINE(f, 'ok');
UTL_FILE.FCLOSE(f);
UTL_FILE.FREMOVE('$DirectoryName', 'roa_write_test.tmp');
DBMS_OUTPUT.PUT_LINE('WRITE_OK');
EXCEPTION
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('WRITE_FAIL:' || SQLERRM);
END;
/
EXIT;
"@
$testResult = Invoke-SqlPlus -OracleHome $OracleHome -ServiceName $ServiceName `
-Username "SYS" -Password $Password -SqlCommand $testSql -AsSysdba -Silent
if ($testResult -notmatch "WRITE_OK") {
Write-LogError "Baza NU poate scrie in $DirectoryPath (directorul Oracle $DirectoryName)."
Write-LogError " $(($testResult -split "`n" | Where-Object { $_ -match 'ORA-|WRITE_FAIL' } | Select-Object -First 2) -join ' ')"
Write-LogError " Serviciul Oracle ruleaza ca NT SERVICE\OracleServiceXE si nu ajunge la calea asta"
Write-LogError " chiar daca ACL-ul pe folder pare corect - de obicei lipseste traversarea pe"
Write-LogError " radacina discului. Pune DMP-urile pe discul unde e Oracle Home si reia cu"
Write-LogError " optiunea /dmpdest:<cale> (ex. /dmpdest:D:\DMPDIR)."
return $false
}
Write-Log "Verificat: baza poate scrie in $DirectoryPath"
return $true
}
else {