feat: implement 6-DC active binding detection, targeted sync, and Task.Run async batch engine with comprehensive guide

This commit is contained in:
2026-10-20 21:34:57 +09:00
parent b2e1b8c1d0
commit 5978de5924
7 changed files with 835 additions and 23 deletions
+195
View File
@@ -72,6 +72,70 @@ function Test-NetAppConnection {
}
}
function Get-NetAppActiveDc {
param(
[string]$ClusterEndpoint = "",
[string]$SvmName = "svm_cifs_prod01",
[string]$Username = "",
[string]$Password = "",
[bool]$IgnoreSsl = $true,
[object]$Config = $null
)
if ($Config -and $Config.NetApp) {
if (-not $ClusterEndpoint) { $ClusterEndpoint = $Config.NetApp.ClusterEndpoint }
if (-not $SvmName) { $SvmName = $Config.NetApp.DefaultSvm }
if (-not $Username) { $Username = $Config.NetApp.Username }
if (-not $Password) { $Password = $Config.NetApp.Password }
$IgnoreSsl = [bool]$Config.NetApp.IgnoreSslErrors
}
$useLive = if ($Config -and $Config.NetApp) { [bool]$Config.NetApp.UseLive } else { $false }
if ($useLive -and $ClusterEndpoint) {
try {
# 1. ONTAP REST API CIFS Domain Discovered Servers 질의
$path = "/api/protocols/cifs/domains?svm.name=$SvmName&fields=discovered_servers"
$res = Invoke-NetAppRestRequest -ClusterEndpoint $ClusterEndpoint -UriPath $path -Method "GET" -Username $Username -Password $Password -IgnoreSsl $IgnoreSsl
if ($res.records) {
foreach ($rec in $res.records) {
if ($rec.discovered_servers) {
# 상태가 "ok"인 Active DC 검색
$matched = $rec.discovered_servers | Where-Object {
($_.state -eq "ok" -or $_.status -eq "ok") -and ($_.type -like "*dc*" -or $_.server_type -like "*dc*")
} | Select-Object -First 1
if ($matched -and $matched.name) {
return [PSCustomObject]@{
ActiveDC = $matched.name
Node = if ($matched.node) { $matched.node.name } else { "node-01" }
SvmName = $SvmName
Status = "OK (Active Connected)"
IsLive = $true
DiscoveryMethod = "ONTAP REST API (/api/protocols/cifs/domains)"
}
}
}
}
}
} catch {
Write-Warning "NetApp Active DC 조회 실패 (기본값 폴백): $($_.Exception.Message)"
}
}
# 6개 다중 DC 환경을 모사한 시뮬레이션 / 데모 Active DC 반환
# (현업 시뮬레이션: 6대 DC 중 NetApp이 현재 바라보고 있는 DC04 반환)
return [PSCustomObject]@{
ActiveDC = "dc04.corp.local"
Node = "ontap-node-02"
SvmName = $SvmName
Status = "OK (Active Binding)"
IsLive = $false
DiscoveryMethod = "ONTAP Domain Discovery (Simulated)"
}
}
function Get-NetAppQtrees {
param(
[string]$Filter = "",
@@ -313,6 +377,137 @@ function New-NetAppShareAction {
}
}
function Set-NetAppShareAcl {
param(
[string]$ShareName,
[string]$UserOrGroup,
[string]$Permission = "change", # "full_control", "change", "read", "no_access"
[string]$ActionType = "grant", # "grant", "revoke"
[int]$MaxRetries = 3,
[int]$RetryDelayMs = 1000,
[object]$Config = $null
)
$useLive = if ($Config -and $Config.NetApp) { [bool]$Config.NetApp.UseLive } else { $false }
if ($useLive) {
$endpoint = $Config.NetApp.ClusterEndpoint
$user = $Config.NetApp.Username
$pass = $Config.NetApp.Password
$svm = $Config.NetApp.DefaultSvm
$ignoreSsl = [bool]$Config.NetApp.IgnoreSslErrors
$attempt = 0
$lastError = ""
while ($attempt -lt $MaxRetries) {
$attempt++
try {
if ($ActionType -eq "grant") {
$body = @{
user_or_group = $UserOrGroup
permission = $Permission
type = "allow"
}
$path = "/api/protocols/cifs/shares/$svm/$ShareName/acls"
$null = Invoke-NetAppRestRequest -ClusterEndpoint $endpoint -UriPath $path -Method "POST" -Body $body -Username $user -Password $pass -IgnoreSsl $ignoreSsl
} else {
$path = "/api/protocols/cifs/shares/$svm/$ShareName/acls/$UserOrGroup"
$null = Invoke-NetAppRestRequest -ClusterEndpoint $endpoint -UriPath $path -Method "DELETE" -Username $user -Password $pass -IgnoreSsl $ignoreSsl
}
return [PSCustomObject]@{
Success = $true
Message = "NetApp Share [$ShareName]에 [$UserOrGroup] ($Permission) 권한이 반영되었습니다 (시도 횟수: $attempt)."
Attempts = $attempt
IsLive = $true
}
} catch {
$lastError = $_.Exception.Message
# AD DC 동기화 지연(객체를 찾을 수 없음) 또는 네트워크 지연인 경우 재시도
if ($attempt -lt $MaxRetries) {
Start-Sleep -Milliseconds $RetryDelayMs
}
}
}
return [PSCustomObject]@{
Success = $false
Message = "NetApp Share ACL 반영 실패 ($MaxRetries회 재시도 초과): $lastError"
Attempts = $attempt
IsLive = $true
}
}
# Mock / Fallback
return [PSCustomObject]@{
Success = $true
Message = "[데모 모드] NetApp Share [$ShareName]에 [$UserOrGroup] 권한 ($Permission) 등록 완료 (즉시 바인딩 성공)"
Attempts = 1
IsLive = $false
}
}
function Set-NetAppQuotaRule {
param(
[string]$Volume,
[string]$Qtree = "",
[string]$Target = "",
[string]$QuotaType = "user",
[int64]$SoftLimitGb = 450,
[int64]$HardLimitGb = 500,
[object]$Config = $null
)
$useLive = if ($Config -and $Config.NetApp) { [bool]$Config.NetApp.UseLive } else { $false }
if ($useLive) {
try {
$endpoint = $Config.NetApp.ClusterEndpoint
$user = $Config.NetApp.Username
$pass = $Config.NetApp.Password
$svm = $Config.NetApp.DefaultSvm
$ignoreSsl = [bool]$Config.NetApp.IgnoreSslErrors
$body = @{
svm = @{ name = $svm }
volume = @{ name = $Volume }
type = $QuotaType
space = @{
hard_limit = $HardLimitGb * 1GB
soft_limit = $SoftLimitGb * 1GB
}
}
if ($Qtree) { $body["qtree"] = @{ name = $Qtree } }
if ($Target) {
if ($QuotaType -eq "user") { $body["users"] = @(@{ name = $Target }) }
elseif ($QuotaType -eq "group") { $body["group"] = @{ name = $Target } }
}
$res = Invoke-NetAppRestRequest -ClusterEndpoint $endpoint -UriPath "/api/storage/quota/rules" -Method "POST" -Body $body -Username $user -Password $pass -IgnoreSsl $ignoreSsl
return [PSCustomObject]@{
Success = $true
Message = "NetApp 볼륨 [$Volume] Quota 규칙 (Soft: ${SoftLimitGb}GB, Hard: ${HardLimitGb}GB) 생성/적용 완료"
IsLive = $true
}
} catch {
return [PSCustomObject]@{
Success = $false
Message = "NetApp Quota 설정 실패: $($_.Exception.Message)"
IsLive = $true
}
}
}
# Mock / Fallback
return [PSCustomObject]@{
Success = $true
Message = "[데모 모드] 볼륨 [$Volume] (Qtree: $Qtree) Quota 정책 (Soft: ${SoftLimitGb}GB / Hard: ${HardLimitGb}GB) 반영 완료"
IsLive = $false
}
}
function Get-NetAppSampleQtrees {
param([string]$Filter = "")