Public/image-store.ps1

# Secondary storage / image stores: NFS and S3 image stores, Swift, secondary
# staging stores, the object-browsing commands, secondary storage selectors
# (heuristics), and the data-migration commands.

function Get-CSImageStore {
    <#
    .SYNOPSIS
        Lists image stores (secondary storage).

    .DESCRIPTION
        Wraps listImageStores. Filter by id, name, provider, protocol, or zone.

    .PARAMETER Id
        Filter by image store ID

    .PARAMETER Name
        Filter by name

    .PARAMETER Provider
        Filter by provider (for example NFS, S3, Swift)

    .PARAMETER Protocol
        Filter by protocol

    .PARAMETER ZoneId
        Filter by zone ID

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .EXAMPLE
        Get-CSImageStore -ZoneId $zoneId
        Lists the image stores in a zone.
    #>

    [CmdletBinding()]
    param(
        [string]$Id,

        [string]$Name,

        [string]$Provider,

        [string]$Protocol,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string]$ZoneId,

        [string]$Keyword,

        [int]$Page,

        [int]$PageSize
    )

    process {
        $apiParams = @{}
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            Id = 'id'; Name = 'name'; Provider = 'provider'; Protocol = 'protocol'; ZoneId = 'zoneid'; Keyword = 'keyword'; Page = 'page'; PageSize = 'pagesize'
        })
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'listImageStores' -Parameters $apiParams) -Command 'listImageStores'
    }
}

function Add-CSImageStore {
    <#
    .SYNOPSIS
        Adds an image store (secondary storage).

    .DESCRIPTION
        Wraps addImageStore. -Url and -Provider are provider-specific (for example an
        NFS export with provider NFS); extra settings go in -Details.

    .PARAMETER Url
        The image store URL (for example nfs://server/export/secondary)

    .PARAMETER Provider
        The image store provider (for example NFS, S3, Swift)

    .PARAMETER Name
        A name for the image store

    .PARAMETER ZoneId
        The zone the store serves (omit for a region-wide store)

    .PARAMETER Details
        Extra provider settings as a hashtable

    .EXAMPLE
        Add-CSImageStore -Url 'nfs://10.0.0.5/export/secondary' -Provider NFS -ZoneId $zoneId
        Adds an NFS secondary storage to a zone.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Url,

        [Parameter(Mandatory = $true)]
        [string]$Provider,

        [string]$Name,

        [string]$ZoneId,

        [hashtable]$Details
    )

    $apiParams = @{ url = $Url; provider = $Provider }
    Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
        Name = 'name'; ZoneId = 'zoneid'
    })
    Add-CSMapParameter -ApiParameters $apiParams -Name 'details' -Map $Details
    if ($PSCmdlet.ShouldProcess("image store $Url", 'Add')) {
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'addImageStore' -Parameters $apiParams) -Command 'addImageStore'
    }
}

function Add-CSImageStoreS3 {
    <#
    .SYNOPSIS
        Adds an S3 image store.

    .DESCRIPTION
        Wraps addImageStoreS3, registering an S3-compatible bucket as secondary
        storage.

    .PARAMETER Bucket
        The S3 bucket name

    .PARAMETER AccessKey
        The S3 access key

    .PARAMETER SecretKey
        The S3 secret key

    .PARAMETER EndPoint
        The S3 endpoint

    .PARAMETER UseHttps
        Connect over HTTPS

    .PARAMETER Region
        The S3 region

    .PARAMETER S3Signer
        The S3 signer algorithm (for example S3SignerType, AWSS3V4SignerType)

    .PARAMETER ConnectionTimeout
        Connection timeout in milliseconds

    .PARAMETER SocketTimeout
        Socket timeout in milliseconds

    .PARAMETER MaxErrorRetry
        Maximum number of retries on error

    .EXAMPLE
        Add-CSImageStoreS3 -Bucket 'cs-secondary' -AccessKey $ak -SecretKey $sk -EndPoint 's3.us-east-1.amazonaws.com' -UseHttps -Region us-east-1
        Registers an S3 bucket as secondary storage.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Bucket,

        [Parameter(Mandatory = $true)]
        [string]$AccessKey,

        [Parameter(Mandatory = $true)]
        [string]$SecretKey,

        [Parameter(Mandatory = $true)]
        [string]$EndPoint,

        [switch]$UseHttps,

        [string]$Region,

        [string]$S3Signer,

        [int]$ConnectionTimeout,

        [int]$SocketTimeout,

        [int]$MaxErrorRetry
    )

    $apiParams = @{ bucket = $Bucket; accesskey = $AccessKey; secretkey = $SecretKey; endpoint = $EndPoint }
    Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
        UseHttps = 'usehttps'; Region = 'region'; S3Signer = 's3signer'; ConnectionTimeout = 'connectiontimeout'; SocketTimeout = 'sockettimeout'; MaxErrorRetry = 'maxerrorretry'
    })
    if ($PSCmdlet.ShouldProcess("S3 image store $Bucket", 'Add')) {
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'addImageStoreS3' -Parameters $apiParams) -Command 'addImageStoreS3'
    }
}

function Add-CSSecondaryStorage {
    <#
    .SYNOPSIS
        Adds secondary storage to a zone.

    .DESCRIPTION
        Wraps addSecondaryStorage, the older command to attach an NFS secondary
        storage. New deployments usually prefer Add-CSImageStore.

    .PARAMETER Url
        The secondary storage URL

    .PARAMETER ZoneId
        The zone to add the storage to

    .PARAMETER Details
        Extra settings as a hashtable

    .EXAMPLE
        Add-CSSecondaryStorage -Url 'nfs://10.0.0.5/export/secondary' -ZoneId $zoneId
        Adds NFS secondary storage to a zone.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Url,

        [string]$ZoneId,

        [hashtable]$Details
    )

    $apiParams = @{ url = $Url }
    if ($PSBoundParameters.ContainsKey('ZoneId')) { $apiParams['zoneid'] = $ZoneId }
    Add-CSMapParameter -ApiParameters $apiParams -Name 'details' -Map $Details
    if ($PSCmdlet.ShouldProcess("secondary storage $Url", 'Add')) {
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'addSecondaryStorage' -Parameters $apiParams) -Command 'addSecondaryStorage'
    }
}

function Add-CSSwift {
    <#
    .SYNOPSIS
        Adds a Swift image store.

    .DESCRIPTION
        Wraps addSwift, registering an OpenStack Swift store as region-wide secondary
        storage.

    .PARAMETER Url
        The Swift endpoint URL

    .PARAMETER Account
        The Swift account

    .PARAMETER Username
        The Swift username

    .PARAMETER Key
        The Swift key

    .PARAMETER StoragePolicy
        The Swift storage policy

    .EXAMPLE
        Add-CSSwift -Url 'https://swift.example.com/auth/v1.0' -Account 'cloudstack:admin' -Username 'admin' -Key $key
        Registers a Swift secondary storage.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Url,

        [string]$Account,

        [string]$Username,

        [string]$Key,

        [string]$StoragePolicy
    )

    $apiParams = @{ url = $Url }
    Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
        Account = 'account'; Username = 'username'; Key = 'key'; StoragePolicy = 'storagepolicy'
    })
    if ($PSCmdlet.ShouldProcess("Swift store $Url", 'Add')) {
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'addSwift' -Parameters $apiParams) -Command 'addSwift'
    }
}

function Get-CSSwift {
    <#
    .SYNOPSIS
        Lists Swift image stores.

    .DESCRIPTION
        Wraps listSwifts.

    .PARAMETER Id
        Filter by Swift store ID

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .EXAMPLE
        Get-CSSwift
        Lists the registered Swift stores.
    #>

    [CmdletBinding()]
    param(
        [string]$Id,

        [string]$Keyword,

        [int]$Page,

        [int]$PageSize
    )

    $apiParams = @{}
    Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
        Id = 'id'; Keyword = 'keyword'; Page = 'page'; PageSize = 'pagesize'
    })
    ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'listSwifts' -Parameters $apiParams) -Command 'listSwifts'
}

function Set-CSImageStore {
    <#
    .SYNOPSIS
        Updates an image store.

    .DESCRIPTION
        Wraps updateImageStore, mainly to toggle an image store's read-only status
        (for example while migrating off it) or adjust its recorded capacity. Accepts
        image store objects on the pipeline.

    .PARAMETER Id
        The image store to update. Binds from a piped store's id.

    .PARAMETER ReadOnly
        Whether the image store is read-only

    .PARAMETER Name
        New name

    .PARAMETER CapacityBytes
        Recorded capacity in bytes

    .EXAMPLE
        Set-CSImageStore -Id $storeId -ReadOnly $true
        Marks an image store read-only ahead of migration.

    .EXAMPLE
        Get-CSImageStore -Name 'nfs-sec-1' | Set-CSImageStore -ReadOnly $false
        Returns a store to read-write.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('ImageStoreId')]
        [string]$Id,

        [Nullable[bool]]$ReadOnly,

        [string]$Name,

        [long]$CapacityBytes
    )

    process {
        $apiParams = @{ id = $Id }
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            Name = 'name'; CapacityBytes = 'capacitybytes'
        })
        if ($PSBoundParameters.ContainsKey('ReadOnly')) { $apiParams['readonly'] = ([bool]$ReadOnly).ToString().ToLowerInvariant() }
        if ($PSCmdlet.ShouldProcess("image store $Id", 'Update')) {
            ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'updateImageStore' -Parameters $apiParams) -Command 'updateImageStore'
        }
    }
}

function Remove-CSImageStore {
    <#
    .SYNOPSIS
        Deletes an image store.

    .DESCRIPTION
        Wraps deleteImageStore. Accepts image store objects on the pipeline.

    .PARAMETER Id
        The image store to delete. Binds from a piped store's id.

    .EXAMPLE
        Remove-CSImageStore -Id $storeId
        Deletes an image store after confirmation.

    .EXAMPLE
        Get-CSImageStore -Name 'old-nfs-sec' | Remove-CSImageStore
        Deletes a store located by name.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('ImageStoreId')]
        [string]$Id
    )

    process {
        if ($PSCmdlet.ShouldProcess("image store $Id", 'Delete')) {
            ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'deleteImageStore' -Parameters @{ id = $Id }) -Command 'deleteImageStore'
        }
    }
}

function Get-CSImageStoreObject {
    <#
    .SYNOPSIS
        Lists objects at a path on an image store.

    .DESCRIPTION
        Wraps listImageStoreObjects, browsing the contents of an image store at -Path.
        Accepts image store objects on the pipeline.

    .PARAMETER Id
        The image store to browse. Binds from a piped store's id.

    .PARAMETER Path
        The path within the store to list

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .EXAMPLE
        Get-CSImageStoreObject -Id $storeId -Path '/template'
        Lists the objects under a path on an image store.

    .EXAMPLE
        Get-CSImageStore -Name 'nfs-sec-1' | Get-CSImageStoreObject -Path '/snapshots'
        Browses a store piped in by object.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('ImageStoreId')]
        [string]$Id,

        [string]$Path,

        [string]$Keyword,

        [int]$Page,

        [int]$PageSize
    )

    process {
        $apiParams = @{ id = $Id }
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            Path = 'path'; Keyword = 'keyword'; Page = 'page'; PageSize = 'pagesize'
        })
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'listImageStoreObjects' -Parameters $apiParams) -Command 'listImageStoreObjects'
    }
}

function Export-CSImageStoreObject {
    <#
    .SYNOPSIS
        Produces a download link for an object on an image store.

    .DESCRIPTION
        Wraps downloadImageStoreObject, which prepares the object at -Path for
        download and returns a URL. This is an asynchronous job; use -Wait to block
        and return the download URL. Accepts image store objects on the pipeline.

    .PARAMETER Id
        The image store holding the object. Binds from a piped store's id.

    .PARAMETER Path
        The path of the object to download

    .PARAMETER Wait
        Wait for the async job to finish and return the download URL

    .EXAMPLE
        Export-CSImageStoreObject -Id $storeId -Path '/template/tmpl/2/234/tmpl.qcow2' -Wait
        Prepares a download URL for one object and waits for it.

    .EXAMPLE
        Get-CSImageStore -Name 'nfs-sec-1' | Export-CSImageStoreObject -Path '/snapshots/abc.vhd' -Wait
        Produces a download link from a store piped in by object.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('ImageStoreId')]
        [string]$Id,

        [Parameter(Mandatory = $true)]
        [string]$Path,

        [switch]$Wait
    )

    process {
        if ($PSCmdlet.ShouldProcess("object $Path on image store $Id", 'Prepare download')) {
            Invoke-CSAsyncApiRequest -Command 'downloadImageStoreObject' -Parameters @{ id = $Id; path = $Path } -Wait:$Wait
        }
    }
}

function Get-CSSecondaryStagingStore {
    <#
    .SYNOPSIS
        Lists secondary staging stores.

    .DESCRIPTION
        Wraps listSecondaryStagingStores, the NFS staging caches used in front of an
        object-store secondary storage.

    .PARAMETER Id
        Filter by staging store ID

    .PARAMETER Name
        Filter by name

    .PARAMETER Provider
        Filter by provider

    .PARAMETER Protocol
        Filter by protocol

    .PARAMETER ZoneId
        Filter by zone ID

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .EXAMPLE
        Get-CSSecondaryStagingStore -ZoneId $zoneId
        Lists the staging stores in a zone.
    #>

    [CmdletBinding()]
    param(
        [string]$Id,

        [string]$Name,

        [string]$Provider,

        [string]$Protocol,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string]$ZoneId,

        [string]$Keyword,

        [int]$Page,

        [int]$PageSize
    )

    process {
        $apiParams = @{}
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            Id = 'id'; Name = 'name'; Provider = 'provider'; Protocol = 'protocol'; ZoneId = 'zoneid'; Keyword = 'keyword'; Page = 'page'; PageSize = 'pagesize'
        })
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'listSecondaryStagingStores' -Parameters $apiParams) -Command 'listSecondaryStagingStores'
    }
}

function New-CSSecondaryStagingStore {
    <#
    .SYNOPSIS
        Creates a secondary staging store.

    .DESCRIPTION
        Wraps createSecondaryStagingStore, an NFS staging cache used in front of an
        object-store (S3/Swift) secondary storage.

    .PARAMETER Url
        The staging store URL (for example nfs://server/export/staging)

    .PARAMETER ZoneId
        The zone the staging store serves

    .PARAMETER Provider
        The staging store provider

    .PARAMETER Scope
        The scope of the staging store

    .PARAMETER Details
        Extra settings as a hashtable

    .EXAMPLE
        New-CSSecondaryStagingStore -Url 'nfs://10.0.0.5/export/staging' -ZoneId $zoneId -Provider NFS
        Creates an NFS staging cache in a zone.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Url,

        [string]$ZoneId,

        [string]$Provider,

        [string]$Scope,

        [hashtable]$Details
    )

    $apiParams = @{ url = $Url }
    Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
        ZoneId = 'zoneid'; Provider = 'provider'; Scope = 'scope'
    })
    Add-CSMapParameter -ApiParameters $apiParams -Name 'details' -Map $Details
    if ($PSCmdlet.ShouldProcess("secondary staging store $Url", 'Create')) {
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'createSecondaryStagingStore' -Parameters $apiParams) -Command 'createSecondaryStagingStore'
    }
}

function Remove-CSSecondaryStagingStore {
    <#
    .SYNOPSIS
        Deletes a secondary staging store.

    .DESCRIPTION
        Wraps deleteSecondaryStagingStore. Accepts staging store objects on the
        pipeline.

    .PARAMETER Id
        The staging store to delete. Binds from a piped store's id.

    .EXAMPLE
        Remove-CSSecondaryStagingStore -Id $stagingId
        Deletes a staging store after confirmation.

    .EXAMPLE
        Get-CSSecondaryStagingStore -ZoneId $zoneId | Remove-CSSecondaryStagingStore
        Deletes the staging stores in a zone.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('StagingStoreId')]
        [string]$Id
    )

    process {
        if ($PSCmdlet.ShouldProcess("secondary staging store $Id", 'Delete')) {
            ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'deleteSecondaryStagingStore' -Parameters @{ id = $Id }) -Command 'deleteSecondaryStagingStore'
        }
    }
}

function Get-CSSecondaryStorageSelector {
    <#
    .SYNOPSIS
        Lists secondary storage selectors (heuristics).

    .DESCRIPTION
        Wraps listSecondaryStorageSelectors, the heuristic rules that decide which
        secondary storage a new template, ISO, snapshot, or volume lands on.

    .PARAMETER Id
        Filter by selector ID

    .PARAMETER ZoneId
        Filter by zone ID

    .PARAMETER Provider
        Filter by provider

    .PARAMETER ShowRemoved
        Include removed selectors

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .EXAMPLE
        Get-CSSecondaryStorageSelector -ZoneId $zoneId
        Lists the storage selectors in a zone.
    #>

    [CmdletBinding()]
    param(
        [string]$Id,

        [Parameter(ValueFromPipelineByPropertyName = $true)]
        [string]$ZoneId,

        [string]$Provider,

        [switch]$ShowRemoved,

        [string]$Keyword,

        [int]$Page,

        [int]$PageSize
    )

    process {
        $apiParams = @{}
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            Id = 'id'; ZoneId = 'zoneid'; Provider = 'provider'; ShowRemoved = 'showremoved'; Keyword = 'keyword'; Page = 'page'; PageSize = 'pagesize'
        })
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'listSecondaryStorageSelectors' -Parameters $apiParams) -Command 'listSecondaryStorageSelectors'
    }
}

function New-CSSecondaryStorageSelector {
    <#
    .SYNOPSIS
        Creates a secondary storage selector (heuristic).

    .DESCRIPTION
        Wraps createSecondaryStorageSelector. -HeuristicRule is a JavaScript
        expression that returns the id of the image store to place a resource of the
        given -Type on.

    .PARAMETER ZoneId
        The zone the selector applies to

    .PARAMETER Type
        The resource type the rule governs: TEMPLATE, ISO, SNAPSHOT, or VOLUME

    .PARAMETER HeuristicRule
        The JavaScript rule that chooses the image store

    .PARAMETER Description
        A description for the selector

    .EXAMPLE
        New-CSSecondaryStorageSelector -ZoneId $zoneId -Type TEMPLATE -HeuristicRule $rule -Description 'Templates to store A'
        Adds a heuristic that routes new templates in a zone.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [string]$ZoneId,

        [Parameter(Mandatory = $true)]
        [ValidateSet('TEMPLATE', 'ISO', 'SNAPSHOT', 'VOLUME')]
        [string]$Type,

        [Parameter(Mandatory = $true)]
        [string]$HeuristicRule,

        [string]$Description
    )

    process {
        $apiParams = @{ zoneid = $ZoneId; type = $Type; heuristicrule = $HeuristicRule }
        if ($PSBoundParameters.ContainsKey('Description')) { $apiParams['description'] = $Description }
        if ($PSCmdlet.ShouldProcess("$Type selector in zone $ZoneId", 'Create')) {
            ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'createSecondaryStorageSelector' -Parameters $apiParams) -Command 'createSecondaryStorageSelector'
        }
    }
}

function Set-CSSecondaryStorageSelector {
    <#
    .SYNOPSIS
        Updates a secondary storage selector's rule.

    .DESCRIPTION
        Wraps updateSecondaryStorageSelector, replacing a selector's heuristic rule.
        Accepts selector objects on the pipeline.

    .PARAMETER Id
        The selector to update. Binds from a piped selector's id.

    .PARAMETER HeuristicRule
        The new JavaScript rule

    .EXAMPLE
        Set-CSSecondaryStorageSelector -Id $selectorId -HeuristicRule $newRule
        Replaces a selector's rule.

    .EXAMPLE
        Get-CSSecondaryStorageSelector -ZoneId $zoneId | Select-Object -First 1 | Set-CSSecondaryStorageSelector -HeuristicRule $newRule
        Updates a selector piped in by object.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('SelectorId')]
        [string]$Id,

        [Parameter(Mandatory = $true)]
        [string]$HeuristicRule
    )

    process {
        if ($PSCmdlet.ShouldProcess("storage selector $Id", 'Update rule')) {
            ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'updateSecondaryStorageSelector' -Parameters @{ id = $Id; heuristicrule = $HeuristicRule }) -Command 'updateSecondaryStorageSelector'
        }
    }
}

function Remove-CSSecondaryStorageSelector {
    <#
    .SYNOPSIS
        Removes a secondary storage selector.

    .DESCRIPTION
        Wraps removeSecondaryStorageSelector. Accepts selector objects on the
        pipeline.

    .PARAMETER Id
        The selector to remove. Binds from a piped selector's id.

    .EXAMPLE
        Remove-CSSecondaryStorageSelector -Id $selectorId
        Removes a storage selector after confirmation.

    .EXAMPLE
        Get-CSSecondaryStorageSelector -ZoneId $zoneId | Remove-CSSecondaryStorageSelector
        Removes the selectors in a zone.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('SelectorId')]
        [string]$Id
    )

    process {
        if ($PSCmdlet.ShouldProcess("storage selector $Id", 'Remove')) {
            ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'removeSecondaryStorageSelector' -Parameters @{ id = $Id }) -Command 'removeSecondaryStorageSelector'
        }
    }
}

function Move-CSSecondaryStorageResource {
    <#
    .SYNOPSIS
        Migrates specific resources to another secondary storage.

    .DESCRIPTION
        Wraps migrateResourceToAnotherSecondaryStorage, moving named templates and/or
        snapshots off -SourceStoreId onto -DestinationStoreIds. This is an
        asynchronous job; use -Wait to block until it finishes.

    .PARAMETER SourceStoreId
        The image store to migrate resources from

    .PARAMETER DestinationStoreIds
        The image store(s) to migrate resources to

    .PARAMETER TemplateIds
        Specific template IDs to migrate

    .PARAMETER SnapshotIds
        Specific snapshot IDs to migrate

    .PARAMETER Wait
        Wait for the async job to finish and return the result

    .EXAMPLE
        Move-CSSecondaryStorageResource -SourceStoreId $srcId -DestinationStoreIds $destId -TemplateIds $tmplA, $tmplB -Wait
        Moves two templates to another secondary storage.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('Id', 'ImageStoreId')]
        [string]$SourceStoreId,

        [Parameter(Mandatory = $true)]
        [string[]]$DestinationStoreIds,

        [string[]]$TemplateIds,

        [string[]]$SnapshotIds,

        [switch]$Wait
    )

    process {
        $apiParams = @{ srcpool = $SourceStoreId; destpools = ($DestinationStoreIds -join ',') }
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            TemplateIds = 'templates'; SnapshotIds = 'snapshots'
        })
        if ($PSCmdlet.ShouldProcess("image store $SourceStoreId", 'Migrate resources to another secondary storage')) {
            Invoke-CSAsyncApiRequest -Command 'migrateResourceToAnotherSecondaryStorage' -Parameters $apiParams -Wait:$Wait
        }
    }
}

function Move-CSSecondaryStorageData {
    <#
    .SYNOPSIS
        Migrates data objects between secondary storages.

    .DESCRIPTION
        Wraps migrateSecondaryStorageData, rebalancing or fully moving the data
        objects on -SourceStoreId to -DestinationStoreIds. -MigrationType Complete
        moves everything; Balance spreads load across the destinations. This is an
        asynchronous job; use -Wait to block until it finishes.

    .PARAMETER SourceStoreId
        The image store to migrate data from

    .PARAMETER DestinationStoreIds
        The image store(s) to migrate data to

    .PARAMETER MigrationType
        Complete (move all) or Balance (spread load)

    .PARAMETER Wait
        Wait for the async job to finish and return the result

    .EXAMPLE
        Move-CSSecondaryStorageData -SourceStoreId $srcId -DestinationStoreIds $destA, $destB -MigrationType Balance -Wait
        Rebalances data across two destination stores.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [Alias('Id', 'ImageStoreId')]
        [string]$SourceStoreId,

        [Parameter(Mandatory = $true)]
        [string[]]$DestinationStoreIds,

        [ValidateSet('Complete', 'Balance')]
        [string]$MigrationType,

        [switch]$Wait
    )

    process {
        $apiParams = @{ srcpool = $SourceStoreId; destpools = ($DestinationStoreIds -join ',') }
        if ($PSBoundParameters.ContainsKey('MigrationType')) { $apiParams['migrationtype'] = $MigrationType }
        if ($PSCmdlet.ShouldProcess("image store $SourceStoreId", 'Migrate data to another secondary storage')) {
            Invoke-CSAsyncApiRequest -Command 'migrateSecondaryStorageData' -Parameters $apiParams -Wait:$Wait
        }
    }
}

function Convert-CSCloudToObjectStore {
    <#
    .SYNOPSIS
        Migrates the cloud's NFS secondary storage to an object store.

    .DESCRIPTION
        Wraps updateCloudToUseObjectStore, switching the region's secondary storage
        from NFS to the named object store (the NFS stores become staging caches).
        This is a one-time, cloud-wide change.

    .PARAMETER Name
        A name for the object store

    .PARAMETER Url
        The object store URL

    .PARAMETER Provider
        The object store provider (for example S3, Swift)

    .PARAMETER Details
        Extra provider settings as a hashtable

    .EXAMPLE
        Convert-CSCloudToObjectStore -Name 'region-s3' -Url 's3://cs-secondary' -Provider S3 -Details @{ accesskey = $ak; secretkey = $sk }
        Switches the cloud's secondary storage to an S3 object store.
    #>

    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    param(
        [Parameter(Mandatory = $true)]
        [string]$Name,

        [string]$Url,

        [string]$Provider,

        [hashtable]$Details
    )

    $apiParams = @{ name = $Name }
    Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
        Url = 'url'; Provider = 'provider'
    })
    Add-CSMapParameter -ApiParameters $apiParams -Name 'details' -Map $Details
    if ($PSCmdlet.ShouldProcess('cloud secondary storage', "Migrate to object store $Name")) {
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'updateCloudToUseObjectStore' -Parameters $apiParams) -Command 'updateCloudToUseObjectStore'
    }
}