QumuloShift.ps1
<#
=========================================================================== Created by: berat.ulualan@qumulo.com Organization: Qumulo, Inc. Filename: QumuloShift.ps1 Module Name: Qumulo Description: PowerShell Script (.ps1) for Qumulo object replication (SHIFT) configurations and operations ------------------------------------------------------------------------- MIT License Copyright (c) 2022 Qumulo, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =========================================================================== #> function List-QQObjectRelationships { <# .SYNOPSIS List existing object replication relationships. .DESCRIPTION List existing object replication relationships. .EXAMPLE List-QQObjectRelationships [-Json] #> # CmdletBinding parameters [CmdletBinding()] param( [Parameter(Mandatory = $False)] [switch]$json ) if ($SkipCertificateCheck -eq 'true') { $PSDefaultParameterValues = @("Invoke-RestMethod:SkipCertificateCheck",$true) } try { # Existing BearerToken check if (!$global:Credentials) { Login-QQCluster } else { if (!$global:Credentials.BearerToken.StartsWith("session-v1")) { Login-QQCluster } } $bearerToken = $global:Credentials.BearerToken $clusterName = $global:Credentials.ClusterName $portNumber = $global:Credentials.PortNumber $TokenHeader = @{ Authorization = "Bearer $bearerToken" } # API url definition $url = "/v3/replication/object-relationships/" # API call run try { $response = Invoke-RestMethod -SkipCertificateCheck -Method 'GET' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" -TimeoutSec 60 -ErrorAction:Stop # Response if ($json) { return @($response) | ConvertTo-Json -Depth 10 } else { return $response } } catch { $_.Exception.Response } } catch { $_.Exception.Response } } function List-QQObjectRelationshipStatuses { <# .SYNOPSIS List statuses for all existing object replication relationships. .DESCRIPTION List statuses for all existing object replication relationships. .EXAMPLE List-QQObjectRelationshipStatuses [-Json] #> # CmdletBinding parameters [CmdletBinding()] param( [Parameter(Mandatory = $False)] [switch]$json ) if ($SkipCertificateCheck -eq 'true') { $PSDefaultParameterValues = @("Invoke-RestMethod:SkipCertificateCheck",$true) } try { # Existing BearerToken check if (!$global:Credentials) { Login-QQCluster } else { if (!$global:Credentials.BearerToken.StartsWith("session-v1")) { Login-QQCluster } } $bearerToken = $global:Credentials.BearerToken $clusterName = $global:Credentials.ClusterName $portNumber = $global:Credentials.PortNumber $TokenHeader = @{ Authorization = "Bearer $bearerToken" } # API url definition $url = "/v3/replication/object-relationships/status/" # API call run try { $response = Invoke-RestMethod -SkipCertificateCheck -Method 'GET' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" # Response if ($json) { return @($response) | ConvertTo-Json -Depth 10 } else { return $response } } catch { $_.Exception.Response } } catch { $_.Exception.Response } } function Get-QQObjectRelationship { <# .SYNOPSIS Get information about the specified object replication relationship. .DESCRIPTION Get information about the specified object replication relationship. .PARAMETER Id [ID] Relationship Id .EXAMPLE Get-QQObjectRelationship -Id [ID] [-Json] #> # CmdletBinding parameters [CmdletBinding()] param( [Parameter(Mandatory = $True)] [string]$id, [Parameter(Mandatory = $False)] [switch]$json ) if ($SkipCertificateCheck -eq 'true') { $PSDefaultParameterValues = @("Invoke-RestMethod:SkipCertificateCheck",$true) } try { # Existing BearerToken check if (!$global:Credentials) { Login-QQCluster } else { if (!$global:Credentials.BearerToken.StartsWith("session-v1")) { Login-QQCluster } } $bearerToken = $global:Credentials.BearerToken $clusterName = $global:Credentials.ClusterName $portNumber = $global:Credentials.PortNumber $TokenHeader = @{ Authorization = "Bearer $bearerToken" } # API url definition $url = "/v3/replication/object-relationships/$id" try { # API call run $response = Invoke-RestMethod -SkipCertificateCheck -Method 'GET' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" -TimeoutSec 60 -ErrorAction:Stop # Response if ($json) { return @($response) | ConvertTo-Json -Depth 10 } else { return $response } } catch { $_.Exception.Response } } catch { $_.Exception.Response } } function Get-QQObjectRelationshipStatus { <# .SYNOPSIS Get the status of an existing object replication relationship. .DESCRIPTION Get the status of an existing object replication relationship. .PARAMETER Id [ID] Relationship Id .EXAMPLE Get-QQObjectRelationshipStatus -Id [ID] [-Json] #> # CmdletBinding parameters [CmdletBinding()] param( [Parameter(Mandatory = $True)] [string]$id, [Parameter(Mandatory = $False)] [switch]$json ) if ($SkipCertificateCheck -eq 'true') { $PSDefaultParameterValues = @("Invoke-RestMethod:SkipCertificateCheck",$true) } try { # Existing BearerToken check if (!$global:Credentials) { Login-QQCluster } else { if (!$global:Credentials.BearerToken.StartsWith("session-v1")) { Login-QQCluster } } $bearerToken = $global:Credentials.BearerToken $clusterName = $global:Credentials.ClusterName $portNumber = $global:Credentials.PortNumber $TokenHeader = @{ Authorization = "Bearer $bearerToken" } # API url definition $url = "/v3/replication/object-relationships/$id/status" # API call run try { $response = Invoke-RestMethod -SkipCertificateCheck -Method 'GET' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" -TimeoutSec 60 -ErrorAction:Stop if ($json) { return @($response) | ConvertTo-Json -Depth 10 } else { return $response } } catch { $_.Exception.Response } } catch { $_.Exception.Response } } function Create-QQObjectRelationship { <# .SYNOPSIS Create a new object replication relationship. Replication will automatically start after the relationship is created. .DESCRIPTION Create a new object replication relationship. Replication will automatically start after the relationship is created. .PARAMETER LocalDirectoryId [LOCAL_DIRECTORY_ID] File ID of the qumulo directory if local_directory_path is not provided .PARAMETER LocalDirectoryPath [LOCAL_DIRECTORY_PATH] Path of the qumulo directory if local_directory_id is not provided .PARAMETER Direction [COPY_TO_OBJECT|COPY_FROM_OBJECT] Whether data is to be copied to, or from, the object store COPY_FROM_OBJECT or COPY_TO_OBJECT .PARAMETER ObjectFolder [OBJECT_FOLDER] Folder to use in the object store bucket. A slash separator is automatically used to specify a 'folder' in a bucket. .PARAMETER Bucket [BUCKET] Bucket in the object store to use for this relationship .PARAMETER Region [REGION] Region the bucket is located in .PARAMETER AccessKeyId [ACCESS_KEY_ID] Access key ID to use when communicating with the object store .PARAMETER SecretAccessKey [SECRET_ACCESS_KEY] Secret access key to use when communicating with the object store .PARAMETER ObjectStoreAddress [OBJECT_STORE_ADDRESS] S3-compatible server address. For Amazon S3, use s3.<region>.amazonaws.com (e.g., s3.us-west-2.amazonaws.com). .PARAMETER UsePort [USE_PORT] HTTPS port to use when communicating with the object store (default: 443) .PARAMETER CACertificate [CA_CERTIFICATE] Public certificate of the certificate authority to trust for connections to the object store, in PEM format (defaults to built-in trusted public CAs) .PARAMETER BucketAddressingStyle [BUCKET_STYLE_PATH|BUCKET_STYLE_VIRTUAL_HOSTED] Addressing style for requests to the bucket. Set to BUCKET_STYLE_PATH for path-style addressing or BUCKET_STYLE_VIRTUAL_HOSTED for virtual hosted-style (the default). #> # CmdletBinding parameters [CmdletBinding()] param( [Parameter(Mandatory = $True,ParameterSetName = "LocalDirectoryId")] [string]$LocalId, [Parameter(Mandatory = $True,ParameterSetName = "LocalDirectoryPath")] [string]$LocalPath, [Parameter(Mandatory = $True)][ValidateSet("Copy_From_Object","Copy_To_Object")][string]$Direction, [Parameter(Mandatory = $True)] [string]$ObjectFolder, [Parameter(Mandatory = $True)] [string]$Bucket, [Parameter(Mandatory = $True)] [string]$Region, [Parameter(Mandatory = $True)] [string]$AccessKeyId, [Parameter(Mandatory = $True)] [string]$SecretAccessKey, [Parameter(Mandatory = $False)] [string]$ObjectStoreAddress, [Parameter(Mandatory = $False)] [int32]$UsePort=443, [Parameter(Mandatory = $False)] [string]$CACertificate, [Parameter(Mandatory = $False)][ValidateSet("Bucket_Style_Path","Bucket_Style_Virtual_Hosted")][string]$BucketAddressingStyle= "BUCKET_STYLE_VIRTUAL_HOSTED", [Parameter(Mandatory = $False)] [switch]$Json ) if ($SkipCertificateCheck -eq 'true') { $PSDefaultParameterValues = @("Invoke-RestMethod:SkipCertificateCheck",$true) } try { # Existing BearerToken check if (!$global:Credentials) { Login-QQCluster } else { if (!$global:Credentials.BearerToken.StartsWith("session-v1")) { Login-QQCluster } } $bearerToken = $global:Credentials.BearerToken $clusterName = $global:Credentials.ClusterName $portNumber = $global:Credentials.PortNumber $TokenHeader = @{ Authorization = "Bearer $bearerToken" } # API Request body # Local file path -> Local file Id conversion if ($localpath) { $htmlPath = ([uri]::EscapeDataString($localpath)) # API url definition $url = "/v1/files/$htmlPath/info/attributes" # API call run try { $response = Invoke-RestMethod -SkipCertificateCheck -Method 'GET' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" -TimeoutSec 60 -ErrorAction:Stop $localid = $($response.id) } catch { $_.Exception.Response } } if (!$bucketaddressingstyle) { $bucketaddressingstyle = "BUCKET_STYLE_VIRTUAL_HOSTED" } if (!$useport) { $useport = 443 } if (!$objectstoreaddress) { $objectstoreaddress = "s3.$region.amazonaws.com" } $body = @{ "access_key_id" = $AccessKeyId "secret_access_key" = $SecretAccessKey "bucket" = $Bucket "port" = $UsePort "region" = $Region "direction" = $Direction.ToUpper() "local_directory_id" = $LocalId "object_folder" = $ObjectFolder "object_store_address" = $ObjectStoreAddress "bucket_style" = $BucketAddressingStyle } if ($CACertificate) { $body += @{ "ca_certificate" = $CACertificate } } Write-Debug($body| ConvertTo-Json -Depth 10) # API url definition $url = "/v3/replication/object-relationships/" # API call run try { $response = Invoke-RestMethod -SkipCertificateCheck -Method 'POST' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" -Body ($body | ConvertTo-Json -Depth 10) -TimeoutSec 60 -ErrorAction:Stop if ($json) { return @($response) | ConvertTo-Json -Depth 10 } else { return $response } } catch { $_.Exception.Response } } catch { $_.Exception.Response } } function Delete-QQObjectRelationship { <# .SYNOPSIS Delete the specified object replication relationship, which must not be running a job. .DESCRIPTION Delete the specified object replication relationship, which must not be running a job. .PARAMETER Id [ID] Relationship Id .EXAMPLE Delete-QQObjectRelationship -Id [ID] #> # CmdletBinding parameters [CmdletBinding()] param( [Parameter(Mandatory = $True)] [string]$Id ) if ($SkipCertificateCheck -eq 'true') { $PSDefaultParameterValues = @("Invoke-RestMethod:SkipCertificateCheck",$true) } try { # Existing BearerToken check if (!$global:Credentials) { Login-QQCluster } else { if (!$global:Credentials.BearerToken.StartsWith("session-v1")) { Login-QQCluster } } $bearerToken = $global:Credentials.BearerToken $clusterName = $global:Credentials.ClusterName $portNumber = $global:Credentials.PortNumber $TokenHeader = @{ Authorization = "Bearer $bearerToken" } # API url definition $url = "/v3/replication/object-relationships/$id" # API call run try { $response = Invoke-RestMethod -SkipCertificateCheck -Method 'DELETE' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" -TimeoutSec 60 -ErrorAction:Stop # Response return ("$id was deleted successfully.") } catch { $_.Exception.Response } } catch { $_.Exception.Response } } function Start-QQObjectRelationship { <# .SYNOPSIS Start a new replication job for the specified object relationship .DESCRIPTION Start a new replication job for the specified object relationship .PARAMETER Id [ID] Relationship Id .EXAMPLE Start-QQObjectRelationship -Id [ID] #> # CmdletBinding parameters [CmdletBinding()] param( [Parameter(Mandatory = $True)] [string]$Id, [Parameter(Mandatory = $False)] [switch]$json ) if ($SkipCertificateCheck -eq 'true') { $PSDefaultParameterValues = @("Invoke-RestMethod:SkipCertificateCheck",$true) } try { # Existing BearerToken check if (!$global:Credentials) { Login-QQCluster } else { if (!$global:Credentials.BearerToken.StartsWith("session-v1")) { Login-QQCluster } } $bearerToken = $global:Credentials.BearerToken $clusterName = $global:Credentials.ClusterName $portNumber = $global:Credentials.PortNumber $TokenHeader = @{ Authorization = "Bearer $bearerToken" } # API url definition $url = "/v3/replication/object-relationships/$id/replicate" # API call run try { $response = Invoke-RestMethod -SkipCertificateCheck -Method 'POST' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" -TimeoutSec 60 -ErrorAction:Stop # API url definition $url = "/v3/replication/object-relationships/$id/status" # API call run try { $response = Invoke-RestMethod -SkipCertificateCheck -Method 'GET' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" -TimeoutSec 60 -ErrorAction:Stop if ($json) { return @($response) | ConvertTo-Json -Depth 10 } else { return $response } } catch { $_.Exception.Response } } catch { $_.Exception.Response } } catch { $_.Exception.Response } } function Abort-QQObjectRelationship { <# .SYNOPSIS Abort any ongoing replication job for the specified object replication relationship. .DESCRIPTION Abort any ongoing replication job for the specified object replication relationship. .PARAMETER Id [ID] Relationship Id .EXAMPLE Abort-QQObjectRelationship -Id [ID] #> # CmdletBinding parameters [CmdletBinding()] param( [Parameter(Mandatory = $True)] [string]$Id, [Parameter(Mandatory = $False)] [switch]$json ) if ($SkipCertificateCheck -eq 'true') { $PSDefaultParameterValues = @("Invoke-RestMethod:SkipCertificateCheck",$true) } try { # Existing BearerToken check if (!$global:Credentials) { Login-QQCluster } else { if (!$global:Credentials.BearerToken.StartsWith("session-v1")) { Login-QQCluster } } $bearerToken = $global:Credentials.BearerToken $clusterName = $global:Credentials.ClusterName $portNumber = $global:Credentials.PortNumber $TokenHeader = @{ Authorization = "Bearer $bearerToken" } # API url definition $url = "/v3/replication/object-relationships/$id/abort-replication" # API call run try { $response = Invoke-RestMethod -SkipCertificateCheck -Method 'POST' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" -TimeoutSec 60 -ErrorAction:Stop # API url definition $url = "/v3/replication/object-relationships/$id/status" # API call run try { $response = Invoke-RestMethod -SkipCertificateCheck -Method 'GET' -Uri "https://${clusterName}:$portNumber$url" -Headers $TokenHeader -ContentType "application/json" -TimeoutSec 60 -ErrorAction:Stop if ($json) { return @($response) | ConvertTo-Json -Depth 10 } else { return $response } } catch { $_.Exception.Response } } catch { $_.Exception.Response } } catch { $_.Exception.Response } } |