PowerCLI vCloud Director Customer Provisioning

Ich konnte letzte Woche endlich ein kleines Projekt fertigstellen, welches mich schon etwas länger verfolgte. Das vCloud Director Customer Provisioning mit VMware PowerCLI. Neue Kunden im VMware vCloud Director anzulegen ist wieder mal ein Paradebeispiel für eine Automation, denn es muss schnell, standardisiert und hoffentlich oft erledigt werden.

vCloud Director Customer Provisioning - PS Console

Die meisten Service Provider werden diese Aufgabe nicht unbedingt per PowerShell abbilden, sondern ehr direkt die API des VMware vCloud Director nutzen. Ich wollte jedoch mit meinem Projekt vCloud Director Customer Provisioning sehen, ob das Komplett mit VMware PowerCLI abbildbar ist. Eines schon vorweg, es ist nicht sehr komfortabel und auch nur eingeschränkt möglich.

Schritte beim vCloud Director Customer Provisioning

Die Anlage eines komplett neuen Kunden ist in mehrere Schritte gegliedert, welche teilweise in der richtigen Reihenfolge ausgeführt werden müssen.

Initial müssen allerdings erst noch die PowerShell Module geladen und der VMware vCloud Director verbunden werden:

# Import VMware PowerCLI vCD Module
Import-Module VMware.VimAutomation.Cloud

# Import My vCD Module
Import-Module .\VMware-vCD-Module\

# Connect vCD Instance
Connect-CIServer <Your vCD FQDN>

Create VMware vCloud Director Organization

Die Organisationen im VMware vCD kann man als Mandanten betrachten. Jeder Kunden hat im Normalfall seine eigene Organisation hinter der eine eigene URL und seine eigenen Benutzer sowie Ressourcen stehen.

Wie auch für die meisten weiteren Schritte gibt es in VMware PowerCLI ein natives Cmdlet für das Erstellen einer neuen Organisation: New-Org
Für meine Zwecke hat dieses Cmdlet allerdings zu wenig Möglichkeiten die Optionen der Organisation direkt beim Anlegen anzupassen.

Meine weiterführenden Optionen:

  • Catalog Publishing
  • Catalog Subscription
  • VM Quota
  • Stored VM Quota
  • VM Lease Time
  • Stored VM Lease Time
  • Password Policy Settings

Daher habe ich für das vCloud Director Customer Provisioning folgende Funktion geschrieben um alle meine Anforderungen zu erfüllen:

#Requires -Version 4
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.3.0.0"}
Function New-MyOrg {
<#
.SYNOPSIS
    Creates a new vCD Org with Default Parameters

.DESCRIPTION
    Creates a new vCD Org with Default Parameters.

    Default Parameters are:
    * Catalog Publishing
    * Catalog Subscription
    * VM Quota
    * Stored VM Quota
    * VM Lease Time
    * Stored VM Lease Time
    * Password Policy Settings

.NOTES
    File Name  : New-MyOrg.ps1
    Author     : Markus Kraus
    Version    : 1.1
    State      : Ready

.LINK
    https://mycloudrevolution.com/

.EXAMPLE
    New-MyOrg -Name "TestOrg" -FullName "Test Org" -Description "PowerCLI Test Org"

.PARAMETER Name
    Name of the New Org as String

.PARAMETER FullName
    Full Name of the New Org as String

.PARAMETER Description
    Description of the New Org as String

.PARAMETER Enabled
    Should the New Org be enabled after creation

    Default:$false

#>
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Org as string")]
        [ValidateNotNullorEmpty()]
            [String] $Name,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Full Name of the New Org as string")]
        [ValidateNotNullorEmpty()]
            [String] $FullName,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Description of the New Org as string")]
        [ValidateNotNullorEmpty()]
            [String] $Description,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the New Org be enabled after creation")]
        [ValidateNotNullorEmpty()]
            [Switch]$Enabled
    )
    Process {
        $vcloud = $DefaultCIServers[0].ExtensionData

        ## Create Objects
        $AdminOrg = New-Object VMware.VimAutomation.Cloud.Views.AdminOrg
        $orgGeneralSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgGeneralSettings
        $orgOrgLeaseSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgLeaseSettings
        $orgOrgVAppTemplateLeaseSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgVAppTemplateLeaseSettings
        $orgOrgPasswordPolicySettings = New-Object VMware.VimAutomation.Cloud.Views.OrgPasswordPolicySettings
        $orgSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgSettings

        ## Admin Settings
        $adminOrg.Name = $name
        $adminOrg.FullName = $FullName
        $adminOrg.Description = $description
        $adminOrg.IsEnabled = $Enabled

        ## Org Setting
        ### General Org Settings
        $orgGeneralSettings.CanPublishCatalogs = $False
        $orgGeneralSettings.CanPublishExternally = $False
        $orgGeneralSettings.CanSubscribe = $True
        $orgGeneralSettings.DeployedVMQuota = 0
        $orgGeneralSettings.StoredVmQuota = 0
        $orgSettings.OrgGeneralSettings = $orgGeneralSettings
        ### vApp Org Setting
        $orgOrgLeaseSettings.DeleteOnStorageLeaseExpiration = $false
        $orgOrgLeaseSettings.DeploymentLeaseSeconds = 0
        $orgOrgLeaseSettings.StorageLeaseSeconds = 0
        $orgSettings.VAppLeaseSettings = $orgOrgLeaseSettings
        ### vApp Template Org Setting
        $orgOrgVAppTemplateLeaseSettings.DeleteOnStorageLeaseExpiration = $false
        $orgOrgVAppTemplateLeaseSettings.StorageLeaseSeconds = 0
        $orgSettings.VAppTemplateLeaseSettings = $orgOrgVAppTemplateLeaseSettings
        ### PasswordPolicySettings Org Setting
        $orgOrgPasswordPolicySettings.AccountLockoutEnabled = $True
        $orgOrgPasswordPolicySettings.InvalidLoginsBeforeLockout = 5
        $orgOrgPasswordPolicySettings.AccountLockoutIntervalMinutes = 30
        $orgSettings.OrgPasswordPolicySettings = $orgOrgPasswordPolicySettings

        $adminOrg.Settings = $orgSettings

        $CreateOrg = $vcloud.CreateOrg($adminOrg)

        Get-Org -Name $name | Format-Table -AutoSize
    }
}

vCloud Director Customer Provisioning - Org

Create VMware vCloud Director Organization Administrator

Update – 14.01.2019

Mit der PowerCLI Version 11.0 (und wahrescheinlich neuer) hat sich die Handhabung der User Rollen in den Organisationen verändert. Auf den Hinweiß von Sebastian Kirsch hin habe ich die Funktion New-MyOrgAdmin entsprechend angepasst.

Um dem neuen Kunden auch Zugriff auf seine Ressourcen zu gewähren muss mindestens ein User initial angelegt werden, Im optimalen Fall ist das ein Organisations Administrator. Mit diesem User kann der Kunden dann alle weiteren User selbst anlegen und einige Einstellungen anpassen (Siehe auch: Predefined Roles and Their Rights).

Für diesen Prozess gibt es leider kein natives Cmdlet in VMware PowerCLI.

Meine Funktion zur Useranlage sieht vor, dass der User für das vCloud Director Customer Provisioning fix als Organisations Administrator angelegt wird:

Function New-MyOrgAdmin {
<#
.SYNOPSIS
    Creates a new vCD Org Admin with Default Parameters

.DESCRIPTION
    Creates a new vCD Org Admin with Default Parameters

    Default Parameters are:
    * User Role

.NOTES
    File Name  : New-MyOrgAdmin.ps1
    Author     : Markus Kraus
    Version    : 1.2
    State      : Ready

.LINK
    https://mycloudrevolution.com/

.EXAMPLE
    New-MyOrgAdmin -Name "OrgAdmin" -Pasword "Anfang!!" -FullName "Org Admin" -EmailAddress "[email protected]" -Org "TestOrg"

.PARAMETER Name
    Name of the New Org Admin as String

.PARAMETER FullName
    Full Name of the New Org Admin as String

.PARAMETER Password
    Password of the New Org Admin as String

.PARAMETER EmailAddress
    EmailAddress of the New Org Admin as String

.PARAMETER Enabled
    Should the New Org be enabled after creation

    Default:$false

.PARAMETER Org
    Org where the new Org Admin should be created as string

#>
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Org Admin as String")]
        [ValidateNotNullorEmpty()]
            [String] $Name,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Password of the New Org Admin as String")]
        [ValidateNotNullorEmpty()]
            [String] $Pasword,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Full Name of the New Org Admin as String")]
        [ValidateNotNullorEmpty()]
            [String] $FullName,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="EmailAddress of the New Org Admin as String")]
        [ValidateNotNullorEmpty()]
            [String] $EmailAddress,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Org where the new Org Admin should be created as string")]
        [ValidateNotNullorEmpty()]
            [String] $Org,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the New Org be enabled after creation")]
        [ValidateNotNullorEmpty()]
            [Switch]$Enabled
    )
    Process {

        ## Create Objects
        $OrgED = (Get-Org $Org).ExtensionData
        $orgAdminUser = New-Object VMware.VimAutomation.Cloud.Views.User

        ## Settings
        $orgAdminUser.Name = $Name
        $orgAdminUser.FullName = $FullName
        $orgAdminUser.EmailAddress = $EmailAddress
        $orgAdminUser.Password = $Pasword
        $orgAdminUser.IsEnabled = $Enabled

        $vcloud = $DefaultCIServers[0].ExtensionData

        ## Find Role
        if ((Get-Module -Name VMware.VimAutomation.Cloud).Version.Major -eq "6") {
            $vcloud = $global:DefaultCIServers[0].ExtensionData
            $orgAdminRole = $vcloud.RoleReferences.RoleReference | Where-Object {$_.Name -eq "Organization Administrator"}

        }
        elseif ((Get-Module -Name VMware.VimAutomation.Cloud).Version.Major -ge "11") {
            $orgAdminRole = $OrgED.RoleReferences.RoleReference | Where-Object {$_.Name -eq "Organization Administrator"}
        }

        $orgAdminUser.Role = $orgAdminRole

        ## Create User
        $user = $orgED.CreateUser($orgAdminUser)

        Get-CIUser -Org $Org -Name $Name | Format-Table -AutoSize
    }
}

vCloud Director Customer Provisioning - Org User

Create VMware vCloud Director Organization VDC

Als letzter und umfangreichster Schritt soll der Kunde noch ein Virtual Datacenter (VDC) bekommen. Das Organization VDC (OrgVDC) legt grob gesagt die Compute, Storage und Netzwerk Ressourcen für den Mandanten fest.

Speziell die Storage Ressourcen gestalten sich in der Anlage ziemlich komplex wenn man mit Storage Profiles arbeitet. Weder das native Cmdlet zur Anlage eins neuen OrgVDC (New-OrgVdc) noch das Cmdlet zum Anpassen dieser (Set-OrgVdc) kennen Storage Profiles. Mit dem korrekten Storage Profil kann dann auch ein Privater Katalog für Medien und vApp Templates in der Organisation erstellt werden. Diesen Schritt könnte der Kunde zwar auch selbst erledigen, aber wenn wir ja sowieso schon dabei sind…

Note:

Das Provider VDC muss das Storage Profile ‚Any‚ aktiviert haben um das Provisionieren zu ermöglichen.
Dieses wird dann temporär dem neuen OrgVDC zugeordnet aber dann direkt gegen das korrekte ersetzt.

Aber auch im bereich Netzwerk gibt es einige Hürden zu nehmen. VXLAN Network Pools und External Networks sind auch nicht gerade simpel bereitzustellen.

Da es sich ja um ein standardisiertes Bereitstellen handelt werden auch wieder einige Optionen fix gesetzt.

Fixe Optionen:

  • Allocation Model
  • Network Quota
  • VM Quota
  • ‚vCpu In Mhz‘
  • Fast Provisioning
  • Thin Provisioning

Meine Funktion zum Bereitstellen eines Org VDC für das vCloud Director Customer Provisioning sieht dann so aus:

#Requires -Version 4
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.3.0.0"}
Function New-MyOrgVdc {
<#
.SYNOPSIS
    Creates a new vCD Org VDC with Default Parameters

.DESCRIPTION
    Creates a new vCD Org VDC with Default Parameters

    Default Parameters are:
    * Allocation Model
    * Network Quota
    * VM Quota
    * 'vCpu In Mhz'
    * Fast Provisioning
    * Thin Provisioning
    * private Catalog

.NOTES
    File Name  : New-MyOrgVdc.ps1
    Author     : Markus Kraus
    Version    : 1.2
    State      : Ready

.LINK
    https://mycloudrevolution.com/

.EXAMPLE
    New-MyOrgVdc -Name "TestVdc" -CPULimit 1000 -MEMLimit 1000 -StorageLimit 1000 -StorageProfile "Standard-DC01" -NetworkPool "NetworkPool-DC01" -ProviderVDC "Provider-VDC-DC01" -Org "TestOrg" -ExternalNetwork "External_OrgVdcNet"

.EXAMPLE
    New-MyOrgVdc -Name "TestVdc" -CPULimit 1000 -MEMLimit 1000 -StorageLimit 1000 -StorageProfile "Standard-DC01" -NetworkPool "NetworkPool-DC01" -ProviderVDC "Provider-VDC-DC01" -Org "TestOrg"

.PARAMETER Name
    Name of the New Org VDC as String

.PARAMETER CPULimit
    CPU Limit (MHz) of the New Org VDC as String

.PARAMETER MEMLimit
    Memory Limit (MB) of the New Org VDC as String

.PARAMETER StorageLimit
    Storage Limit (MB) of the New Org VDC as String

.PARAMETER StorageProfile
     Storage Profile of the New Org VDC as String

.PARAMETER NetworkPool
     Network Pool of the New Org VDC as String

.PARAMETER ExternalNetwork
     Optional External Network of the New Org VDC as String

.PARAMETER Enabled
    Should the New Org VDC be enabled after creation

    Default:$false

    Note: If an External Network is requested the Org VDC will be enabled during External Network Configuration

.PARAMETER ProviderVDC
    ProviderVDC where the new Org VDC should be created as string

.PARAMETER Org
    Org where the new Org VDC should be created as string

.PARAMETER Timeout
    Timeout for teh Org VDC to get Ready

    Default: 120s

#>
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [String] $Name,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="CPU Limit (MHz) of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [int] $CPULimit,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Memory Limit (MB) of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [int] $MEMLimit,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Storage Limit (MB) of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [int] $StorageLimit,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Storage Profile of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [String] $StorageProfile,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Network Pool of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [String] $NetworkPool,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Optional External Network of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [String] $ExternalNetwork,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the New Org VDC be enabled after creation")]
        [ValidateNotNullorEmpty()]
            [Switch]$Enabled,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="ProviderVDC where the new Org VDC should be created as string")]
        [ValidateNotNullorEmpty()]
            [String] $ProviderVDC,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Org where the new Org VDC should be created as string")]
        [ValidateNotNullorEmpty()]
            [String] $Org,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False,HelpMessage="Timeout for teh Org VDC to get Ready")]
        [ValidateNotNullorEmpty()]
            [int] $Timeout = 120
    )
    Process {
        ## Create Objects and all Settings
        Write-Verbose "Create Objects and all Settings"
        $adminVdc = New-Object VMware.VimAutomation.Cloud.Views.AdminVdc
        $adminVdc.Name = $name
        $adminVdc.IsEnabled = $Enabled
        $OrgVdcproviderVdc = Get-ProviderVdc $ProviderVDC
        $providerVdcRef = New-Object VMware.VimAutomation.Cloud.Views.Reference
        $providerVdcRef.Href = $OrgVdcproviderVdc.Href
        $adminVdc.ProviderVdcReference = $providerVdcRef
        $adminVdc.AllocationModel = "AllocationPool"
        $adminVdc.ComputeCapacity = New-Object VMware.VimAutomation.Cloud.Views.ComputeCapacity
        $adminVdc.ComputeCapacity.Cpu = New-Object VMware.VimAutomation.Cloud.Views.CapacityWithUsage
        $adminVdc.ComputeCapacity.Cpu.Units = "MHz"
        $adminVdc.ComputeCapacity.Cpu.Limit = $CPULimit
        $adminVdc.ComputeCapacity.Cpu.Allocated = $CPULimit
        $adminVdc.ComputeCapacity.Memory = New-Object VMware.VimAutomation.Cloud.Views.CapacityWithUsage
        $adminVdc.ComputeCapacity.Memory.Units = "MB"
        $adminVdc.ComputeCapacity.Memory.Limit = $MEMLimit
        $adminVdc.ComputeCapacity.Memory.Allocated = $MEMLimit
        $adminVdc.StorageCapacity = New-Object VMware.VimAutomation.Cloud.Views.CapacityWithUsage
        $adminVdc.StorageCapacity.Units = "MB"
        $adminVdc.StorageCapacity.Limit = $StorageLimit
        $adminVdc.NetworkQuota = 10
        $adminVdc.VmQuota = 0
        $adminVdc.VCpuInMhz = 1000
        $adminVdc.VCpuInMhz2 = 1000
        $adminVdc.UsesFastProvisioning = $false
        $adminVdc.IsThinProvision = $true

        ## Create Org vDC
        Write-Verbose "Create Org vDC"
        $OrgED = (Get-Org $Org).ExtensionData
        $orgVdc = $orgED.CreateVdc($adminVdc)

        ## Wait for getting Ready
        Write-Verbose "Wait for getting Ready"
        $i = 0
        while(($orgVdc = Get-OrgVdc -Name $Name).Status -eq "NotReady"){
            $i++
            Start-Sleep 2
            if($i -gt $Timeout) { Write-Error "Creating Org Failed."; break}
            Write-Progress -Activity "Creating Org" -Status "Wait for Org to become Ready..."
            }
        Write-Progress -Activity "Creating Org" -Completed
        Start-Sleep 2

        ## Search given Storage Profile
        Write-Verbose "Search given Storage Profile"
        $ProVdcStorageProfile = search-cloud -QueryType ProviderVdcStorageProfile -Name $StorageProfile | Get-CIView

        ## Create Storage Profile Object with Settings
        Write-Verbose "Create Storage Profile Object with Settings"
        $spParams = new-object VMware.VimAutomation.Cloud.Views.VdcStorageProfileParams
        $spParams.Limit = $StorageLimit
        $spParams.Units = "MB"
        $spParams.ProviderVdcStorageProfile = $ProVdcStorageProfile.href
        $spParams.Enabled = $true
        $spParams.Default = $true
        $UpdateParams = new-object VMware.VimAutomation.Cloud.Views.UpdateVdcStorageProfiles
        $UpdateParams.AddStorageProfile = $spParams

        ## Update Org vDC
        $orgVdc = Get-OrgVdc -Name $name
        $orgVdc.ExtensionData.CreateVdcStorageProfile($UpdateParams)

        ## Wait for getting Ready
        Write-Verbose "Wait for getting Ready"
        while(($orgVdc = Get-OrgVdc -Name $name).Status -eq "NotReady"){
            $i++
            Start-Sleep 1
            if($i -gt $Timeout) { Write-Error "Update Org Failed."; break}
            Write-Progress -Activity "Updating Org" -Status "Wait for Org to become Ready..."
            }
        Write-Progress -Activity "Updating Org" -Completed
        Start-Sleep 1

        ## Search Any-StorageProfile
        Write-Verbose "Search Any-StorageProfile"
        $orgvDCAnyProfile = search-cloud -querytype AdminOrgVdcStorageProfile | Where-Object {($_.Name -match '\*') -and ($_.VdcName -eq $orgVdc.Name)} | Get-CIView

        ## Disable Any-StorageProfile
        Write-Verbose "Disable Any-StorageProfile"
        $orgvDCAnyProfile.Enabled = $False
        $return = $orgvDCAnyProfile.UpdateServerData()

        ## Remove Any-StorageProfile
        Write-Verbose "Remove Any-StorageProfile"
        $ProfileUpdateParams = new-object VMware.VimAutomation.Cloud.Views.UpdateVdcStorageProfiles
        $ProfileUpdateParams.RemoveStorageProfile = $orgvDCAnyProfile.href
        $remove = $orgvdc.extensiondata.CreatevDCStorageProfile($ProfileUpdateParams)

         ## Wait for getting Ready
        Write-Verbose "Wait for getting Ready"
        while(($orgVdc = Get-OrgVdc -Name $name).Status -eq "NotReady"){
            $i++
            Start-Sleep 1
            if($i -gt $Timeout) { Write-Error "Update Org Failed."; break}
            Write-Progress -Activity "Updating Org" -Status "Wait for Org to become Ready..."
            }
        Write-Progress -Activity "Updating Org" -Completed
        Start-Sleep 1

        ## Set NetworkPool for correct location
        Write-Verbose "Set NetworkPool for correct location"
        $orgVdc = Get-OrgVdc -Name $name
        $ProVdcNetworkPool = Get-NetworkPool -ProviderVdc $ProviderVDC -Name $NetworkPool
        $set = Set-OrgVdc -OrgVdc $orgVdc -NetworkPool $ProVdcNetworkPool -NetworkMaxCount "10"

        ## Create private Catalog
        Write-Verbose "Create private Catalog Object"
        $OrgCatalog = New-Object VMware.VimAutomation.Cloud.Views.AdminCatalog
        $OrgCatalog.name = "$Org Private Catalog"
        if (!(Get-Org $org | Get-Catalog -Name $OrgCatalog.name -ErrorAction SilentlyContinue)) {
            Write-Verbose "Create private Catalog"
            $CreateCatalog = (Get-Org $org  | Get-CIView).CreateCatalog($OrgCatalog)
            $AccessControlRule = New-CIAccessControlRule -Entity $CreateCatalog.name -EveryoneInOrg -AccessLevel ReadWrite -Confirm:$False
            }
            else {
            Write-Output "Catalog '$($OrgCatalog.name)' aleady exists!"
                }

        ## Create a direct connect network
        if ($ExternalNetwork) {
            Write-Verbose "Create a direct connect network"
            Write-Output "Org VDC '$Name' needs to be enabled to add an external Network!"
            $EnableOrgVdc = Set-OrgVdc -OrgVdc $Name -Enabled:$True
            $orgVdcView = Get-OrgVdc $Name | Get-CIView
            $extNetwork = $_.externalnetwork
            $extNetwork = Get-ExternalNetwork | Get-CIView | Where-Object {$_.name -eq $ExternalNetwork}
            $orgNetwork = new-object vmware.vimautomation.cloud.views.orgvdcnetwork
            $orgNetwork.name = $ExternalNetwork
            $orgNetwork.Configuration = New-Object VMware.VimAutomation.Cloud.Views.NetworkConfiguration
            $orgNetwork.Configuration.FenceMode = 'bridged'
            $orgNetwork.configuration.ParentNetwork = New-Object vmware.vimautomation.cloud.views.reference
            $orgNetwork.configuration.ParentNetwork.href = $extNetwork.href

            $result = $orgVdcView.CreateNetwork($orgNetwork)
            }

        Get-OrgVdc -Name $name | Format-Table -AutoSize
    }
}

vCloud Director Customer Provisioning - Org VDC

vCloud Director Customer Provisioning - Catalog

Starten des vCloud Director Customer Provisioning

Um nun die oben aufgeführten Schritte alle mögliches effizient in Kombination auszuführen habe ich mir eine übergeordnete Funktion erstellt. Diese PowerShell Funktion wird mit einem JSON Config File gefüttert und ruft dann die erforderlichen Funktionen mit den entsprechenden Parametern auf.

In dieser übergeordneten Funktion habe ich zusätzlich die Möglichkeit abgebildet mit OrgVDC T-Shirt Sizes zu arbeiten. Das bedeutet hinter der Größe M ist dann bereits ein gewisse Parametrisierung für CPU RAM und Storage hinterlegt. Wenn in dem JSON File das Feld ‚FixedSize‘ leer ist („FixedSize“: „“,) werden die darauffolgenden, manuellen Werte verwendet.

Ähnliches gilt für das Feld ‚ExternalNetwork‘. Ist dieses leer wir das neue OrgVDC ohne ein Externes Netzwerk angelegt.

Das JSON Config File

{
"Org": {
        "Name":"TestOrg",
        "FullName": "Test Org",
        "Description":"Automation Test Org"
    },
"OrgAdmin": {
        "Name":"TestOrgAdmin",
        "Pasword": "myPassword1!",
        "FullName":"Test OrgAdmin",
        "EmailAddress":"[email protected]"
    },
"OrgVdc": {
        "Name":"TestOrgVdc",
        "FixedSize": "M",
        "CPULimit": "1000",
        "MEMLimit":"1024",
        "StorageLimit":"1024",
        "StorageProfile":"Standard-DC01",
        "ProviderVDC":"Provider-VDC-DC01",
        "NetworkPool":"Provider-VDC-DC01-NetPool",
        "ExternalNetwork": "External-OrgVdcNet"
    }
}

Die PowerShell Funktion

#Requires -Version 4
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.3.0.0"}
Function Invoke-MyOnBoarding {
<#
.SYNOPSIS
    Creates all vCD Objecst for a new IAAS Customer

.DESCRIPTION
    Creates all vCD Objects for a new IAAS Customer

    All Objects are:
    * Org
    * Default Org Admin
    * Org VDC
    ** Private Catalog
    ** Optional Bridged Network

    JSON Config Example:

    {
    "Org": {
            "Name":"TestOrg",
            "FullName": "Test Org",
            "Description":"Automation Test Org"
        },
    "OrgAdmin": {
            "Name":"TestOrgAdmin",
            "Pasword": "myPassword1!",
            "FullName":"Test OrgAdmin",
            "EmailAddress":"[email protected]"
        },
    "OrgVdc": {
            "Name":"TestOrgVdc",
            "FixedSize": "M",
            "CPULimit": "1000",
            "MEMLimit":"1000",
            "StorageLimit":"1000",
            "StorageProfile":"Standard-DC01",
            "ProviderVDC":"Provider-VDC-DC01",
            "NetworkPool":"Provider-VDC-DC01-NetPool",
            "ExternalNetwork": "External_OrgVdcNet"
        }
    }

.NOTES
    File Name  : Invoke-MyOnBoarding.ps1
    Author     : Markus Kraus
    Version    : 1.2
    State      : Ready

.LINK
    https://mycloudrevolution.com/

.EXAMPLE
    Invoke-MyOnBoarding -ConfigFile ".\OnBoarding.json" -Enabled:$true

.EXAMPLE
    Invoke-MyOnBoarding -ConfigFile ".\OnBoarding.json" -Enabled:$false

.PARAMETER ConfigFile
    Full Path to the JSON Config File

.PARAMETER Enabled
    Should the Customer be enabled after creation

    Default: $False

#>
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Full Path to the JSON Config File")]
        [ValidateNotNullorEmpty()]
            [String] $ConfigFile,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the Customer be enabled after creation")]
        [ValidateNotNullorEmpty()]
            [Switch]$Enabled
    )
    Process {

    $Valid = $true

    Write-Verbose "## Import JSON Config"
    Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Importing JSON Config...`n"
    $Configs = Get-Content -Raw -Path $ConfigFile -ErrorAction Continue | ConvertFrom-Json -ErrorAction Continue

    if (!($Configs)) {
        $Valid = $false
        Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Importing JSON Config Failed" -ForegroundColor Red
        }
        else {
            Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Importing JSON Config OK" -ForegroundColor Green
            }

    if ($Valid) {
        try{
            Write-Verbose "## Create Org"
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new Org...`n" -ForegroundColor Yellow
            $Trash = New-MyOrg -Name $Configs.Org.Name -FullName $Configs.Org.Fullname -Description $Configs.Org.Description -Enabled:$Enabled
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new Org OK" -ForegroundColor Green
            Get-Org -Name $Configs.Org.Name | Select-Object Name, FullName, Enabled | Format-Table -AutoSize
            }
            catch {
                $Valid = $false
                Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new Org Failed" -ForegroundColor Red
            }
        }

    if ($Valid) {
        try{
            Write-Verbose "## Create OrgAdmin"
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgAdmin...`n" -ForegroundColor Yellow
            $Trash = New-MyOrgAdmin -Name $Configs.OrgAdmin.Name -Pasword $Configs.OrgAdmin.Pasword -FullName $Configs.OrgAdmin.FullName  -EmailAddress $Configs.OrgAdmin.EmailAddress -Org $Configs.Org.Name -Enabled:$Enabled
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgAdmin OK" -ForegroundColor Green
            Get-CIUser -Org $Configs.Org.Name -Name $Configs.OrgAdmin.Name  | Select-Object Name, FullName, Email | Format-Table -AutoSize
            }
            catch {
                $Valid = $false
                Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgAdmin Failed" -ForegroundColor Red
            }
        }
    if ($Valid) {
        try{
            Write-Verbose "## Create OrgVdc"
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgVdc...`n" -ForegroundColor Yellow

            if ($Configs.OrgVdc.FixedSize){

                Write-Host "Fixed Size (T-Shirt Size) '$($Configs.OrgVdc.FixedSize)' Org VDC Requested!"

                switch ($Configs.OrgVdc.FixedSize) {
                    M {
                        [String]$CPULimit = 36000
                        [String]$MEMLimit = 122880
                        [String]$StorageLimit = 1048576
                    }
                    L {
                        [String]$CPULimit = 36000
                        [String]$MEMLimit = 245760
                        [String]$StorageLimit = 1048576
                    }
                    default {throw "Invalid T-Shirt Size!"}
                    }

                }
                else{
                Write-Host "Custom Org VDC Size Requested!"

                $CPULimit = $Configs.OrgVdc.CPULimit
                $MEMLimit = $Configs.OrgVdc.MEMLimit
                $StorageLimit = $Configs.OrgVdc.StorageLimit

                }

            if ($Configs.OrgVdc.ExternalNetwork){
                $Trash = New-MyOrgVdc -Name $Configs.OrgVdc.Name -CPULimit $CPULimit -MEMLimit $MEMLimit -StorageLimit $StorageLimit -Networkpool $Configs.OrgVdc.NetworkPool -StorageProfile $Configs.OrgVdc.StorageProfile -ProviderVDC $Configs.OrgVdc.ProviderVDC -ExternalNetwork $Configs.OrgVdc.ExternalNetwork  -Org $Configs.Org.Name -Enabled:$Enabled
                }
                else {
                    $Trash = New-MyOrgVdc -Name $Configs.OrgVdc.Name -CPULimit $CPULimit -MEMLimit $MEMLimit -StorageLimit $StorageLimit -Networkpool $Configs.OrgVdc.NetworkPool -StorageProfile $Configs.OrgVdc.StorageProfile -ProviderVDC $Configs.OrgVdc.ProviderVDC -Org $Configs.Org.Name -Enabled:$Enabled
                }
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgVdc OK" -ForegroundColor Green
            Get-OrgVdc -Org $Configs.Org.Name -Name $Configs.OrgVdc.Name  | Select-Object Name, Enabled, CpuAllocationGhz, MemoryLimitGB, StorageLimitGB, AllocationModel, ThinProvisioned, UseFastProvisioning, `
            @{N="StorageProfile";E={$_.ExtensionData.VdcStorageProfiles.VdcStorageProfile.Name}}, `
            @{N='VCpuInMhz';E={$_.ExtensionData.VCpuInMhz}} | Format-Table -AutoSize
            }
            catch {
                $Valid = $false
                Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgVdc Failed" -ForegroundColor Red
            }
        }

    Write-Output "Overall Execution was Valid: $Valid"
    }
}

Offene Punkte vCloud Director Customer Provisioning

Wie dem aufmerksamen Leser vielleicht aufgefallen ist, kann die New-MyOrgVdc Funktion zwar auf Wunsch ein Externel Netzwerk im Bridged Modus dem OrgVDC hinzufügen aber ’noch‘ kein Edge Gatway.

Ich arbeite hier weiter an einer Möglichkeit. Wer da bereits etwas Vergleichbares in PowerShell abgebildet hat kann mir gerne eine Tipp geben. Auf meine VMware Community Frage gab es leider bisher keine Reaktionen.

Später soll das vCloud Director Customer Provisioning Modul dann über das blanke Anlegen hinaus erweitert werden. Also Erweitern der Ressourcen eines OrgVDC, hinzufügen weiterer Storage Profiles und weitere Dinge dieser Art.

Das vCloud Director Customer Provisioning Projekt

Pester Tests

Für mein Projekt habe ich auch ein paar grundlegende Pester Tests vorgesehen. Die Tests validieren die PowerShell Syntax, die Voranforderungen auf dem System und den erfolgreichen Import des Modules.

vCloud Director Customer Provisioning - Pester Tests

Read the Docs

Um den Einstieg in das vCloud Director Customer Provisioning etwas zu erleichtern habe ich, wie in meinem Plaster Artikel angekündigt, eine kleine Dokumentation der Funktionen bereitgestellt:

Welcome to my VMware-vCD-Module Module

vCloud Director Customer Provisioning - Read The Docs

GitHub Repository

Ein GitHub Repository durfte natürlich auch wieder nicht fehlen:

GitHub: VMware-vCD-Module

vCloud Director Customer Provisioning - GitHub Repository

Weitere Quellen

#LongLiveVCD

3 Comments

  1. William de Marigny 14. Juni 2017
    • Markus Kraus 14. Juni 2017

Leave a Reply