Public/vlan.ps1

# VLAN IP ranges (public/guest/pod IP ranges tied to a VLAN) and guest VLAN
# range dedication to accounts.

function Get-CSVlanIpRange {
    <#
    .SYNOPSIS
        Lists VLAN IP ranges.

    .DESCRIPTION
        Wraps listVlanIpRanges. A VLAN IP range is a block of IPs on a VLAN, used
        for public IPs, a shared/guest network, or pod direct IPs. Filter by zone,
        network, physical network, pod, owner, or VLAN tag.

    .PARAMETER Id
        Filter by VLAN IP range ID

    .PARAMETER ZoneId
        Filter by zone ID

    .PARAMETER NetworkId
        Filter by the network the range belongs to

    .PARAMETER PhysicalNetworkId
        Filter by physical network ID

    .PARAMETER PodId
        Filter by pod ID

    .PARAMETER Account
        Filter by account name. Must be used with -DomainId.

    .PARAMETER DomainId
        Filter by domain ID

    .PARAMETER ProjectId
        Filter by project ID

    .PARAMETER Vlan
        Filter by VLAN tag

    .PARAMETER ForVirtualNetwork
        $true for public (virtual network) ranges, $false for direct/shared ranges

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .EXAMPLE
        Get-CSVlanIpRange -ZoneId $zoneId
        Lists every VLAN IP range in a zone.

    .EXAMPLE
        Get-CSVlanIpRange -PhysicalNetworkId $pnetId -ForVirtualNetwork $true
        Lists the public IP ranges on a physical network.
    #>

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

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

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

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

        [string]$PodId,

        [string]$Account,

        [string]$DomainId,

        [string]$ProjectId,

        [string]$Vlan,

        [Nullable[bool]]$ForVirtualNetwork,

        [string]$Keyword,

        [int]$Page,

        [int]$PageSize
    )

    process {
        $apiParams = @{}
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            Id = 'id'; ZoneId = 'zoneid'; NetworkId = 'networkid'; PhysicalNetworkId = 'physicalnetworkid'; PodId = 'podid'
            Account = 'account'; DomainId = 'domainid'; ProjectId = 'projectid'; Vlan = 'vlan'; Keyword = 'keyword'; Page = 'page'; PageSize = 'pagesize'
        })
        if ($PSBoundParameters.ContainsKey('ForVirtualNetwork')) { $apiParams['forvirtualnetwork'] = ([bool]$ForVirtualNetwork).ToString().ToLowerInvariant() }
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'listVlanIpRanges' -Parameters $apiParams) -Command 'listVlanIpRanges'
    }
}

function New-CSVlanIpRange {
    <#
    .SYNOPSIS
        Creates a VLAN IP range.

    .DESCRIPTION
        Wraps createVlanIpRange. Give -NetworkId to add a range to an existing
        network, or -ZoneId (with the IPv4 addressing) to create a public or pod
        range. -ForVirtualNetwork $true makes it a public range; $false makes it a
        direct/shared range.

    .PARAMETER ZoneId
        The zone for the range (for a public or pod range)

    .PARAMETER NetworkId
        Add the range to this existing network

    .PARAMETER PhysicalNetworkId
        The physical network to create the range on

    .PARAMETER PodId
        The pod, for a pod-local direct IP range

    .PARAMETER Vlan
        The VLAN tag, or 'untagged'

    .PARAMETER Gateway
        IPv4 gateway for the range

    .PARAMETER Netmask
        IPv4 netmask for the range

    .PARAMETER StartIp
        First IPv4 address of the range

    .PARAMETER EndIp
        Last IPv4 address of the range

    .PARAMETER ForVirtualNetwork
        $true for a public (virtual network) range, $false for a direct/shared range

    .PARAMETER ForSystemVms
        Reserve the range for system VMs

    .PARAMETER Ip6Gateway
        IPv6 gateway for the range

    .PARAMETER Ip6Cidr
        IPv6 CIDR for the range

    .PARAMETER StartIpv6
        First IPv6 address of the range

    .PARAMETER EndIpv6
        Last IPv6 address of the range

    .PARAMETER Account
        Dedicate the range to this account. Must be used with -DomainId.

    .PARAMETER DomainId
        The domain of -Account

    .PARAMETER ProjectId
        Dedicate the range to this project

    .PARAMETER ForDisplay
        Whether the range is shown to end users

    .EXAMPLE
        New-CSVlanIpRange -ZoneId $zoneId -PhysicalNetworkId $pnetId -Vlan untagged -Gateway '203.0.113.1' -Netmask '255.255.255.0' -StartIp '203.0.113.10' -EndIp '203.0.113.100' -ForVirtualNetwork $true
        Adds a public IP range to a zone.

    .EXAMPLE
        New-CSVlanIpRange -NetworkId $sharedNetId -Gateway '10.1.1.1' -Netmask '255.255.255.0' -StartIp '10.1.1.10' -EndIp '10.1.1.200'
        Extends a shared network with another IP range.
    #>

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

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

        [string]$PhysicalNetworkId,

        [string]$PodId,

        [string]$Vlan,

        [string]$Gateway,

        [string]$Netmask,

        [string]$StartIp,

        [string]$EndIp,

        [Nullable[bool]]$ForVirtualNetwork,

        [switch]$ForSystemVms,

        [string]$Ip6Gateway,

        [string]$Ip6Cidr,

        [string]$StartIpv6,

        [string]$EndIpv6,

        [string]$Account,

        [string]$DomainId,

        [string]$ProjectId,

        [Nullable[bool]]$ForDisplay
    )

    process {
        if (-not $PSBoundParameters.ContainsKey('NetworkId') -and -not $PSBoundParameters.ContainsKey('ZoneId')) {
            throw 'Specify -NetworkId to extend a network, or -ZoneId to create a public/pod range.'
        }
        if ($PSBoundParameters.ContainsKey('Account') -and -not $PSBoundParameters.ContainsKey('DomainId')) {
            throw '-DomainId is required when -Account is specified.'
        }
        $apiParams = @{}
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            ZoneId = 'zoneid'; NetworkId = 'networkid'; PhysicalNetworkId = 'physicalnetworkid'; PodId = 'podid'; Vlan = 'vlan'
            Gateway = 'gateway'; Netmask = 'netmask'; StartIp = 'startip'; EndIp = 'endip'; ForSystemVms = 'forsystemvms'
            Ip6Gateway = 'ip6gateway'; Ip6Cidr = 'ip6cidr'; StartIpv6 = 'startipv6'; EndIpv6 = 'endipv6'
            Account = 'account'; DomainId = 'domainid'; ProjectId = 'projectid'
        })
        if ($PSBoundParameters.ContainsKey('ForVirtualNetwork')) { $apiParams['forvirtualnetwork'] = ([bool]$ForVirtualNetwork).ToString().ToLowerInvariant() }
        if ($PSBoundParameters.ContainsKey('ForDisplay')) { $apiParams['fordisplay'] = ([bool]$ForDisplay).ToString().ToLowerInvariant() }
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'createVlanIpRange' -Parameters $apiParams) -Command 'createVlanIpRange'
    }
}

function Set-CSVlanIpRange {
    <#
    .SYNOPSIS
        Updates a VLAN IP range.

    .DESCRIPTION
        Wraps updateVlanIpRange. Only the attributes you supply are changed. Accepts
        VLAN IP range objects on the pipeline.

    .PARAMETER Id
        The VLAN IP range to update. Binds from a piped range's id.

    .PARAMETER Gateway
        New IPv4 gateway

    .PARAMETER Netmask
        New IPv4 netmask

    .PARAMETER StartIp
        New first IPv4 address

    .PARAMETER EndIp
        New last IPv4 address

    .PARAMETER Ip6Gateway
        New IPv6 gateway

    .PARAMETER Ip6Cidr
        New IPv6 CIDR

    .PARAMETER StartIpv6
        New first IPv6 address

    .PARAMETER EndIpv6
        New last IPv6 address

    .PARAMETER ForDisplay
        Whether the range is shown to end users

    .EXAMPLE
        Set-CSVlanIpRange -Id $rangeId -EndIp '203.0.113.150'
        Extends a range's upper bound.

    .EXAMPLE
        Get-CSVlanIpRange -ZoneId $zoneId | Where-Object vlan -eq '100' | Set-CSVlanIpRange -ForDisplay $false
        Hides a VLAN's range from end users.
    #>

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

        [string]$Gateway,

        [string]$Netmask,

        [string]$StartIp,

        [string]$EndIp,

        [string]$Ip6Gateway,

        [string]$Ip6Cidr,

        [string]$StartIpv6,

        [string]$EndIpv6,

        [Nullable[bool]]$ForDisplay
    )

    process {
        $apiParams = @{ id = $Id }
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            Gateway = 'gateway'; Netmask = 'netmask'; StartIp = 'startip'; EndIp = 'endip'
            Ip6Gateway = 'ip6gateway'; Ip6Cidr = 'ip6cidr'; StartIpv6 = 'startipv6'; EndIpv6 = 'endipv6'
        })
        if ($PSBoundParameters.ContainsKey('ForDisplay')) { $apiParams['fordisplay'] = ([bool]$ForDisplay).ToString().ToLowerInvariant() }
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'updateVlanIpRange' -Parameters $apiParams) -Command 'updateVlanIpRange'
    }
}

function Remove-CSVlanIpRange {
    <#
    .SYNOPSIS
        Deletes a VLAN IP range.

    .DESCRIPTION
        Wraps deleteVlanIpRange. The range must have no IPs still in use. Accepts
        VLAN IP range objects on the pipeline.

    .PARAMETER Id
        The VLAN IP range to delete. Binds from a piped range's id.

    .EXAMPLE
        Remove-CSVlanIpRange -Id $rangeId
        Deletes a VLAN IP range after confirmation.

    .EXAMPLE
        Get-CSVlanIpRange -ZoneId $zoneId | Where-Object vlan -eq '100' | Remove-CSVlanIpRange
        Removes the ranges on a VLAN.
    #>

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

    process {
        if ($PSCmdlet.ShouldProcess("VLAN IP range $Id", 'Delete')) {
            ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'deleteVlanIpRange' -Parameters @{ id = $Id }) -Command 'deleteVlanIpRange'
        }
    }
}

function Get-CSGuestVlan {
    <#
    .SYNOPSIS
        Lists guest VLANs and their allocation.

    .DESCRIPTION
        Wraps listGuestVlans, which reports the guest VLANs on a physical network,
        whether each is allocated, and to which network or account.

    .PARAMETER Id
        Filter by guest VLAN ID

    .PARAMETER ZoneId
        Filter by zone ID

    .PARAMETER NetworkId
        Filter by the network using the VLAN

    .PARAMETER PhysicalNetworkId
        Filter by physical network ID

    .PARAMETER Vnet
        Filter by VLAN/VNI value

    .PARAMETER AllocatedOnly
        Only list VLANs that are currently allocated

    .PARAMETER Account
        Filter by account name. Must be used with -DomainId.

    .PARAMETER DomainId
        Filter by domain ID

    .PARAMETER ProjectId
        Filter by project ID

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .EXAMPLE
        Get-CSGuestVlan -PhysicalNetworkId $pnetId
        Lists the guest VLANs on a physical network.

    .EXAMPLE
        Get-CSGuestVlan -ZoneId $zoneId -AllocatedOnly
        Lists only the guest VLANs currently in use in a zone.
    #>

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

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

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

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

        [string]$Vnet,

        [switch]$AllocatedOnly,

        [string]$Account,

        [string]$DomainId,

        [string]$ProjectId,

        [string]$Keyword,

        [int]$Page,

        [int]$PageSize
    )

    process {
        $apiParams = @{}
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            Id = 'id'; ZoneId = 'zoneid'; NetworkId = 'networkid'; PhysicalNetworkId = 'physicalnetworkid'; Vnet = 'vnet'
            AllocatedOnly = 'allocatedonly'; Account = 'account'; DomainId = 'domainid'; ProjectId = 'projectid'
            Keyword = 'keyword'; Page = 'page'; PageSize = 'pagesize'
        })
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'listGuestVlans' -Parameters $apiParams) -Command 'listGuestVlans'
    }
}

function Get-CSGuestVlanRangeDedicated {
    <#
    .SYNOPSIS
        Lists guest VLAN ranges dedicated to accounts.

    .DESCRIPTION
        Wraps listDedicatedGuestVlanRanges. Shows which guest VLAN ranges have been
        reserved for which accounts, domains, or projects.

    .PARAMETER Id
        Filter by dedicated range ID

    .PARAMETER Account
        Filter by account name. Must be used with -DomainId.

    .PARAMETER DomainId
        Filter by domain ID

    .PARAMETER ProjectId
        Filter by project ID

    .PARAMETER PhysicalNetworkId
        Filter by physical network ID

    .PARAMETER ZoneId
        Filter by zone ID

    .PARAMETER GuestVlanRange
        Filter by the VLAN range (for example '100-200')

    .PARAMETER Keyword
        Filter by keyword

    .PARAMETER Page
        Page number of results to return

    .PARAMETER PageSize
        Number of results per page

    .EXAMPLE
        Get-CSGuestVlanRangeDedicated -PhysicalNetworkId $pnetId
        Lists the dedicated guest VLAN ranges on a physical network.

    .EXAMPLE
        Get-CSGuestVlanRangeDedicated -Account 'engineering' -DomainId $domainId
        Shows the VLAN ranges reserved for an account.
    #>

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

        [string]$Account,

        [string]$DomainId,

        [string]$ProjectId,

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

        [string]$ZoneId,

        [string]$GuestVlanRange,

        [string]$Keyword,

        [int]$Page,

        [int]$PageSize
    )

    process {
        $apiParams = @{}
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            Id = 'id'; Account = 'account'; DomainId = 'domainid'; ProjectId = 'projectid'; PhysicalNetworkId = 'physicalnetworkid'
            ZoneId = 'zoneid'; GuestVlanRange = 'guestvlanrange'; Keyword = 'keyword'; Page = 'page'; PageSize = 'pagesize'
        })
        ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'listDedicatedGuestVlanRanges' -Parameters $apiParams) -Command 'listDedicatedGuestVlanRanges'
    }
}

function Set-CSGuestVlanRangeDedicated {
    <#
    .SYNOPSIS
        Dedicates a guest VLAN range to an account.

    .DESCRIPTION
        Wraps dedicateGuestVlanRange, reserving a block of guest VLANs on a physical
        network for one account so only that account's networks use them. Release it
        again with Clear-CSGuestVlanRangeDedicated. Accepts physical network objects
        on the pipeline.

    .PARAMETER PhysicalNetworkId
        The physical network the VLAN range is on. Binds from a piped physical
        network's id.

    .PARAMETER VlanRange
        The guest VLAN range to dedicate (for example '100-200')

    .PARAMETER Account
        The account to dedicate the range to

    .PARAMETER DomainId
        The domain of -Account

    .PARAMETER ProjectId
        Dedicate the range to this project instead of an account

    .EXAMPLE
        Set-CSGuestVlanRangeDedicated -PhysicalNetworkId $pnetId -VlanRange '100-200' -Account 'engineering' -DomainId $domainId
        Reserves VLANs 100-200 for an account.

    .EXAMPLE
        Get-CSPhysicalNetwork -Name 'guest-pn' | Set-CSGuestVlanRangeDedicated -VlanRange '300-350' -ProjectId $projectId
        Dedicates a VLAN range to a project on a piped physical network.
    #>

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

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

        [string]$Account,

        [string]$DomainId,

        [string]$ProjectId
    )

    process {
        if ($PSBoundParameters.ContainsKey('Account') -and -not $PSBoundParameters.ContainsKey('DomainId')) {
            throw '-DomainId is required when -Account is specified.'
        }
        if (-not $PSBoundParameters.ContainsKey('Account') -and -not $PSBoundParameters.ContainsKey('ProjectId')) {
            throw 'Specify an owner with -Account (plus -DomainId) or -ProjectId.'
        }
        $apiParams = @{ physicalnetworkid = $PhysicalNetworkId; vlanrange = $VlanRange }
        Add-CSOptionalParameter -ApiParameters $apiParams -BoundParameters $PSBoundParameters -Map ([ordered]@{
            Account = 'account'; DomainId = 'domainid'; ProjectId = 'projectid'
        })
        $owner = if ($ProjectId) { "project $ProjectId" } else { "account $Account" }
        if ($PSCmdlet.ShouldProcess("guest VLAN range $VlanRange", "Dedicate to $owner")) {
            ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'dedicateGuestVlanRange' -Parameters $apiParams) -Command 'dedicateGuestVlanRange'
        }
    }
}

function Clear-CSGuestVlanRangeDedicated {
    <#
    .SYNOPSIS
        Releases a dedicated guest VLAN range back to the system.

    .DESCRIPTION
        Wraps releaseDedicatedGuestVlanRange, undoing a dedication made with
        Set-CSGuestVlanRangeDedicated so the VLANs are available to any account
        again. Accepts dedicated-range objects on the pipeline.

    .PARAMETER Id
        The dedicated guest VLAN range to release. Binds from a piped range's id.

    .EXAMPLE
        Clear-CSGuestVlanRangeDedicated -Id $dedicatedRangeId
        Releases one dedicated range.

    .EXAMPLE
        Get-CSGuestVlanRangeDedicated -Account 'engineering' -DomainId $domainId | Clear-CSGuestVlanRangeDedicated
        Releases every range dedicated to an account.
    #>

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

    process {
        if ($PSCmdlet.ShouldProcess("dedicated guest VLAN range $Id", 'Release')) {
            ConvertFrom-CSResponse -Response (Invoke-CSApiRequest -Command 'releaseDedicatedGuestVlanRange' -Parameters @{ id = $Id }) -Command 'releaseDedicatedGuestVlanRange'
        }
    }
}