Public/Export-PCOciSnapshot.ps1
|
function Export-PCOciSnapshot { <# .SYNOPSIS Reads the tenancy's compartments, instances, volumes, backups, backup policies, networks and Cloud Guard problems into one snapshot file. .DESCRIPTION Every family in scope, or the ones named with -Include, from every subscribed region or the ones named with -Region, below the tenancy root or the compartment named with -CompartmentId. Records are joined by id. Cloud Guard is read once, from its reporting region, for every region at once: the active problems below the root and the tenancy's security and risk scores (0.2.0). Networks (0.3.0) are the VCNs, subnets, security lists and network security groups with their rules, route tables, gateways, dynamic routing gateways with their attachments, site-to-site VPN connections with their tunnels' state (never a shared secret) and the reserved public addresses, per region. A family that cannot be read in a compartment is recorded in the run report and the run continues; the snapshot is then marked complete: false and a warning is written. No field exists for instance metadata. The run report is written beside the snapshot. .PARAMETER Path The snapshot file. Default: .\snapshot.json. .PARAMETER Include Families to read: Compartments, Instances, Volumes, Backups, BackupPolicies, CloudGuard, Networks. Default: all. .PARAMETER Parts The folder where each region's records are written as soon as the region has been read, so a run interrupted or refused in its last minute keeps what it had. Default: <snapshot>.parts beside the snapshot. .PARAMETER NoParts Write no part files. .PARAMETER Resume Reuse a region's part from the folder instead of reading the region again, when the part is younger than -ResumeHours, complete, and holds every family asked for. The report names the parts reused. .PARAMETER ResumeHours How old a part may be and still be reused. Default 24. .PARAMETER Parallel How many regions are read at once. Default 4; 1 reads them in turn. .PARAMETER Deterministic Omit the generation time, so two reads of the same state are byte-identical. .PARAMETER PassThru Return the snapshot object instead of the summary. .EXAMPLE Connect-PCOci -ProfileName READONLY; Export-PCOciSnapshot -Path .\data\snapshot.json -Deterministic #> [CmdletBinding(SupportsShouldProcess)] [OutputType([pscustomobject], [PowerCraft.OCI.Core.Snapshot.TenancySnapshot])] param( [PowerCraft.OCI.Core.Identity.OciContext]$Context, [string]$Path = (Join-Path (Get-Location).Path 'snapshot.json'), [string[]]$Region, [string]$CompartmentId, [ValidateSet('Compartments', 'Instances', 'Volumes', 'Backups', 'BackupPolicies', 'CloudGuard', 'Networks')][string[]]$Include, [switch]$IncludeDeleted, [string]$Parts, [switch]$NoParts, [switch]$Resume, [ValidateRange(1, 8760)][double]$ResumeHours = 24, [ValidateRange(1, 16)][int]$Parallel = 4, [switch]$Deterministic, [string]$ReportPath, [switch]$PassThru, [switch]$Force ) $ctx = Get-PCOciContextOrThrow -Context $Context if ((Test-Path -LiteralPath $Path) -and -not $Force -and -not $Resume) { throw "A file already exists at '$Path'. Use -Force to overwrite it, or -Resume to finish an earlier run into it." } if (-not $ReportPath) { $ReportPath = [IO.Path]::ChangeExtension($Path, '.report.json') } if (-not $Parts -and -not $NoParts) { $Parts = [IO.Path]::ChangeExtension($Path, '.parts') } if (-not $PSCmdlet.ShouldProcess($Path, "Read tenancy '$($ctx.TenancyName)' into a snapshot")) { return } $options = [PowerCraft.OCI.Core.Snapshot.SnapshotOptions]::new() if ($Region) { $options.Regions.AddRange([string[]]$Region) } if ($CompartmentId) { $options.RootCompartmentId = $CompartmentId } $options.IncludeDeleted = [bool]$IncludeDeleted $options.Families = [PowerCraft.OCI.Core.Snapshot.SnapshotOptions]::ParseFamilies([string[]]$Include) if ($Parts -and -not $NoParts) { $options.PartsFolder = $Parts } $options.Resume = [bool]$Resume -and -not $NoParts $options.ResumeMaxAge = [TimeSpan]::FromHours($ResumeHours) $options.Parallelism = $Parallel $report = [PowerCraft.OCI.Core.Report.RunReport]::new() $report.Verb = 'Export-PCOciSnapshot' $started = [DateTimeOffset]::UtcNow $report.StartedAt = $started Write-Verbose "Reading $($options.Families) from $(if ($Region) { $Region -join ', ' } else { 'every subscribed region' })" $snapshot = [PowerCraft.OCI.Core.Gateways.OciSession]::ExportSnapshot($ctx, $options, $report) $duration = [long]([DateTimeOffset]::UtcNow - $started).TotalMilliseconds $report.DurationMs = $duration [PowerCraft.OCI.Core.Snapshot.SnapshotWriter]::Write($snapshot, $Path, [bool]$Deterministic) $report.Write($ReportPath, [bool]$Deterministic) foreach ($w in $report.Warnings) { Write-Warning $w } if (-not $snapshot.Complete) { Write-Warning ("The snapshot is incomplete: {0} failure(s). See the report at '{1}'." -f $report.Failures.Count, $ReportPath) } if ($PassThru) { return $snapshot } [pscustomobject]@{ SnapshotPath = (Resolve-Path -LiteralPath $Path).Path ReportPath = (Resolve-Path -LiteralPath $ReportPath).Path Complete = $snapshot.Complete Regions = @($snapshot.Regions) Compartments = $snapshot.Compartments.Count Instances = $snapshot.Instances.Count Volumes = $snapshot.Volumes.Count Backups = $snapshot.Backups.Count BackupPolicies = $snapshot.BackupPolicies.Count PartsReused = @($report.PartsReused) Vcns = $(if ($snapshot.Networks) { $snapshot.Networks.Vcns.Count } else { $null }) Subnets = $(if ($snapshot.Networks) { $snapshot.Networks.Subnets.Count } else { $null }) CloudGuardProblems = $snapshot.CloudGuardProblems.Count SecurityScore = $(if ($snapshot.CloudGuard) { $snapshot.CloudGuard.SecurityScore } else { $null }) Failures = $report.Failures.Count DurationMs = $duration } } |