top of page

Automating Citrix with VMware vRealize Automation


As part of the automation of virtual machines in the Datacenter it may be necessary to orchestrate all the deployment steps. This can start with the deployment of the virtual machine as such, but also the external components that are useful for the operation of the virtual machine, such as the registration of DNS information, the opening of network flows, the installation of application as well as remote access to the system.

In our case, we will see how to automate the integration of a machine into a Citrix environment to provide external access to the machine. The idea of ​​this article is to present the different scenarios when using a Private SDDC Cloud. The purpose of a private or public cloud is to provide a hosting environment for an internal service or, for example, a customer. If the customer service already has a Citrix solution it might be relevant to integrate a specific workflow to provide an all-in-one service to the end user. The goal is not to present Citrix products in detail but to take a use case like the Virtual Desktop Infrastructure (VDI) so in our example it will be the Citrix XenDesktop solution that will be configured through integration workflows.

To orchestrate Citrix XenDesktop, we'll use Microsoft PowerShell commands on a Citrix Delivery Controller server.

Add –PSSnapin Citrix.*.Admin.V*.

Citrix XenApp and XenDesktop provide a SDK based on a number of Microsoft Windows PowerShell version 3.0 snap-ins that allows you to perform the same tasks as you would with the Citrix Studio console, together with tasks you cannot do with Studio alone.

In our example we will see how to add a virtual machine to an existing Catalog and Delivery Group so that the user can access the virtual machine once created by VMware vRealize Automation. Here is the list of steps that will be performed when provisioning with Citrix.

The integration workflow of the virtual machine will therefore have to start as a result of the provisioning of the workstation by VMware vRealize Automation.

Steps 1 and 2 are for creating the virtual machine instance between VMware vRealize Automation and the vCenter, Step 3: is to start Orchestration Workflows through the same Blueprint (this is done through the Event Broker. 'Automation that will trigger the workflow based on the progress of the deployment of the Blueprint). Step 4: is the workflow trigger including PowerShell commands to the Citrix Delivery Controller. Step 5: shows the VDI extension deployed in the Citrix Catalog so that the user can then connect to it remotely (Step 6).

As discussed in the chapter on VMware vRealize Automation, the Citrix Integration Workflow will be in the form of VM Deployment Blueprint Property.

 

Creating the Citrix Integration Workflow

The goal is to be able to offer the user the Citrix XenDesktop catalog in which to add the provisioned machine from the list of existing Citrix catalogs. This list will be presented when deploying the VMware vRealize Automation Blueprint. So we will first create an Action script in the sense of VMware Orchestrator. The notion of Action in VMware Orchestrator makes it possible to perform a unitary task, if the need is to be able to call other scripts then it will be necessary to use a Workflow. To use the Action tab, select the Design view in VMware Orchestrator.

Our action script should take as argument only the address of the Citrix Server Delivery Controller and an output array (Array) with the list of catalog names available in Citrix. For the input value for the Citrix server address, it is best to create a configuration file with a CitrixDDC Name Attribute with the value of the Citrix Delivery Controller server address.

Since our example Citrix script is done under PowerShell, the simplest is that our Attribute is of the type PowerShellHost and the value points directly to the Host PowerShell object created previously.

The idea of ​​pointing the attribute name to the PowerShell object is to avoid having to change the value of the argument if the PowerShell object is changed. This avoids errors or omissions when changing the target Citrix server. Unlike Workflow, the Action object cannot take the attribute in input. Therefore, you must add the code below so that the script can dynamically recover the value of the Citrix configuration file:

var configElements = Server.getConfigurationElementCategoryWithPath("Citrix").configurationElements

for each (var configAttribute in configElements[0].attributes)

{

if (configAttribute.name == "CitrixDDC")

{

var Host=configAttribute.value

}

}

Our action should include 2 PowerShell lines:

Add the Citrix Snapin:

Add-PSSnapin -Name Citrix.broker.admin.v2 -ErrorAction SilentlyContinue

Return the list of Citrix catalogs:

Get-BrokerCatalog -AdminAddress " + Host.name + " -name * | Select-Object Name

In order to test the proper functioning of our action, you must create a property in VMware vRealize Automation. To do this, go to the Administration tab then Properties Dictionary and Property Definitions to create our Citrix.catalog property. The property should be of the type String, Dropdown view to display a list of choices to the user and point to our action in VMware Orchestrator:

Now that the property is created, it must be added to the Citrix Virtual Machine Deployment Blueprint. Thus, you need to access the VMware vRealize Automation Design tab and select Blueprints. To add our property just edit the target Blueprint and go to the Properties section then the Custom Properties tab:

We then indicate the name of our property and activate the option: Show in Request so that the menu can appear in our Blueprint during the user request as presented below :

To understand property usage in the VMware vRealize Automation sense, we could also add an option to let the user indicate whether they want to add his machine to Citrix before displaying the list of Citrix catalogs. To do this, you will need to create a new property as shown below :

This property should therefore be of a type string and propose a drop-down list of choices Yes / No. Now, in order for our option to appear in the Blueprint, you have to go back to the Design tab and add the property to the list with the default value of No :

For our action to display values ​​only when the Citrix option returns Yes, just add an input parameter (in our case the string variable named Confirm) and the following code in the code :

if (Confirm == "Yes")

{ … }

You must then go back to VMware vRealize Automation, go to the Property definitions section and modify it to have the option to set the input variable of the action to the output of the property created previously under the Citrix name.

So now when the user selects the Yes option they will be able to view the list of Citrix catalogs.

Then, to integrate our virtual machine deployed by VMware vRealize Automation, you need to create a new Workflow in VMware Orchestrator.

The workflow should have as parameter the properties sent by the Blueprint during validation by the user. To do this, select the Type Properties in the Parameters of the Inputs tab.

Thanks to the Input corresponding to the properties sent by the Blueprint we will be able to recover the name of the virtual machine and the name of the Citrix catalog. In Workflow Attribute, specify the PowerShellHost object pointing to the Citrix configuration file to dynamically retrieve the Citrix Delivery Controler server address. The Workflow must begin by reading the Properties object to retrieve the 2 necessary information (VM name and Target Citrix Catalog).

var machine = properties.get("machine");

if(machine != null)

{

var virtualMachineID = machine.get("id");

MachineName = machine.get("name");

System.log("Retreive MachineName = " + MachineName)

}

// Custom Properties Blueprint

var machineProperties = machine.get('properties');

CatalogName = machineProperties.get('citrix.catalog');

System.log("Retreive Citrix Catalog = " + CatalogName)

In the created workflow we add a scriptable task with the content below. The necessary PowerShell commands are: Add the Citrix Snapin:

Citrix.broker.admin.v2 -ErrorAction SilentlyContinue

Get the ID of the hypervisor hosting the VM:

Get-BrokerHypervisorConnection

Retrieve the Citrix Catalog ID:

Get-BrokerCatalog -AdminAddress " + RemoteHost.name + " -name '" + CATALOG + "'")

Add the virtual machine in the Citrix catalog :

new-brokermachine -AdminAddress '" + RemoteHost.name + "' -catalogUid '" + CatalogUid + "' -HostedMachineId '" + vmUuid + "' -HypervisorConnectionUid '" + BrokerUid + "' -MachineName '" + MachineName + "'");

Add the virtual machine in the Citrix delivery group :

add-brokermachine -AdminAddress " + RemoteHost.name + " -MachineName " + MachineName + " -DesktopGroup '" + CatalogName + "'");

The content of the script is as follows :

try {

//Open session to PowerShell host

var sess = RemoteHost.openSession()

//Add Snapin VMware & Citrix

sess.addCommandFromString("Add-PSSnapin -Name Citrix.broker.admin.v2 -ErrorAction SilentlyContinue")

sess.invokePipeline()

// Get VM Uid for add-brokermachine variable

System.log("-- Get VM Uid for add-brokermachine variable --\n")

for (var i in sdkConnections)

{

var host = sdkConnections[i];

var foundvm = host.getAllVirtualMachines(null, "xpath:matches(name, '" + MachineName + "')");

vmUuid = foundvm[0].config.uuid;

System.log("VM Uuid : " + vmUuid );

}

// Get Broker Uid for add-brokermachine variable

System.log("-- Get Broker Uid for add-brokermachine variable --\n")

System.log("Get-BrokerHypervisorConnection")

sess.addCommandFromString("Get-BrokerHypervisorConnection")

result = sess.invokePipeline()

if (result.invocationState == 'Failed'){errorCode=1; System.error("Error in Get Broker Uid : " + result.getErrors());throw errorCode}

var psObject = result.getResults()

var directories = psObject.getRootObject()

var BrokerUid = directories.getProperty('Uid')

System.log("BrokerHypervisor Uid : " + BrokerUid);

// Get Catalog Uid for add-brokermachine variable

System.log("-- Get Catalog Uid for add-brokermachine variable --\n")

System.log("Get-BrokerCatalog -AdminAddress " + RemoteHost.name + " -name '" + CATALOG + "'")

sess.addCommandFromString("Get-BrokerCatalog -AdminAddress " + RemoteHost.name + " -name '" + CATALOG + "'")

result = sess.invokePipeline()

if (result.invocationState == 'Failed'){errorCode=1; System.error("Error in Get Catalog Uid : " + result.getErrors());throw errorCode}

var psObject = result.getResults()

var directories = psObject.getRootObject()

var CatalogUid = directories.getProperty('Uid')

System.log("Catalog Uid : " + CatalogUid);

// Add VM into Catalog

System.log("-- Add VM into Catalog --\n")

System.log("new-brokermachine -AdminAddress '" + RemoteHost.name + "' -catalogUid '" + CatalogUid + "' -HostedMachineId '" + vmUuid + "' -HypervisorConnectionUid '" + BrokerUid + "' -MachineName '" + MachineName + "'");

sess.addCommandFromString("new-brokermachine -AdminAddress '" + RemoteHost.name + "' -catalogUid '" + CatalogUid + "' -HostedMachineId '" + vmUuid + "' -HypervisorConnectionUid '" + BrokerUid + "' -MachineName '" + MachineName + "'");

result = sess.invokePipeline()

if (result.invocationState == 'Failed'){errorCode=1; System.error("Error in Add VM into Catalog : " + result.getErrors());throw errorCode}

var psObject = result.getResults();

var directories = psObject.getRootObject();

MachineName = directories.getProperty('MachineName')

if (MachineName) { System.log("Machine Name : " + MachineName) }

else { errorCode=1; System.error("Error in Machine Name : " + MachineName); throw errorCode}

// Add VM into Desktop Group

System.log("-- Add VM into Desktop Group --\n")

System.log("add-brokermachine -AdminAddress " + RemoteHost.name + " -MachineName " + MachineName + " -DesktopGroup '" + CatalogName + "'");

sess.addCommandFromString("add-brokermachine -AdminAddress " + RemoteHost.name + " -MachineName " + MachineName + " -DesktopGroup '" + CatalogName + "'");

result = sess.invokePipeline()

if (result.invocationState == 'Failed'){ errorCode=1; System.error("Error in Add VM into Desktop Group : " + result.getErrors()); throw errorCode}

} catch (ex){

System.error (ex); errorCode=1; throw errorCode;

} finally {

if (sess) {

//Close session

RemoteHost.closeSession( sess.getSessionId() );

}

}

Now we need to create an Event Subscription in VMware vRealize Automation so that our Workflow can be executed at the end of the deployment of our virtual machine by our Blueprint. To do this, you must return to the VMware vRealize Automation interface and then go to the Administration tab, then Events and finally Subscriptions. Our Subscription must be of the type Machine Provisioning because our actions will be executed after the deployment of the virtual machine (Event of type POST) As previously explained in VMware vRealize Automation Events, we need to specify specific conditions for our Workflow execution, namely:

  • Start at the end of the virtual machine deployment (Lifecycle state VMPSMasterWorkflow32.BuildingMachine) and POST Phase

  • Machine type: Virtual Machine (to make sure the workflow runs well for a deployed virtual machine)

  • Blueprint Name: specify the name of the Blueprint or a value container (if we want to use our Workflow for all Blueprint containing the GOLD value for example, as shown below)

Extensibility.Lifecycle.Properties.VMPSMasterWorkflow32.BuildingMachine

The next step is to specify the workflow to use.

Featured Posts
Check back soon
Once posts are published, you’ll see them here.
Recent Posts
Archive
Search By Tags
No tags yet.
Follow Us
  • Facebook Basic Square
  • Twitter Basic Square
  • Google+ Social Icon
bottom of page