If you use the Citrix Director web-based management console to keep XenDesktop and XenApp sites running well, you may want to add customized fields to the monitoring tool. Why?

For most organizations, it is often a requirement to add some customized fields on the monitoring tool. For example, you may want to expose the SNMP traps information from Director Server as a JSON API. Or perhaps you would like to show extra information on Director UserDetails page.

This post explains how to do that by writing Director Plugins.

Citrix Director is designed so that we can add our own plugins. There are 2 types of Plugins, Backend Plugin and UI Plugin. When we have to expose any extra information as a JSON API calls, backend Plugin mechanism can be used. If we want to display extra information on the Director UI or if we wish to show other console on Director then the UI plugin is used.

Director Plugin Architecture

architecture

As the diagram shows, Director can load Internal and external plugins. For internal plugins, the plugin code is loaded and hosted by director webservice. External Plugins are the ones that are hosted on a separate web server and embedded into Director.

How to add a Director backend Plugin

Director is hosted as a webservice, which exposes multiple APIs for trends, dashboard and other Pages. For exposing our own custom APIs through Director, we need to write a director backend plugin.

Writing a plugin to Director Backend is very easy. All that we need is to create a .dll file and place it the folder “C:\inetpub\wwwroot\Director\plugin” on Director server and restart the IIS Server.

Here is sample code of how we can write a backend plugin. You can directly use this code to write the business logic in test function. Then build a dll and use it you’re your plugin. There are comments between the codes to make it easier to understand. We recommend using Visual Studio for developing and compiling the dll.

Just to have a sneak peek inside the code, first we need to import the namespaces.  There are 3 important classes that we need to import, webservice, plugin. you can find these dlls in c:\inetpub\wwwroot\ Director\bin

code1

We need to define a return class that will be returned after a web service query. Make sure to add DataContract and DataMember properties. This is to register these classes and property as public.

code2

Then you need to create an interface with PluginAttribute property. It should contain the prototype of the function that will be exposed as webservice. In this case “MakeOdataQuery” is the api that is being exposed.

code3

Finally, the interface should be implemented to a class. Have a look into the OdataQuery.cs to get the complete code.

How to write Director UI Plugin

Director supports to add our own UI plugin on DashBoard, Trends, Endpoint details , Machine details and User details page. For the plugin to show up, we need to follow just two steps.

  • Create a Plugin Config File

Create a config file for the plugin and place it in any folder in the location “C:\inetpub\wwwroot\Director\DisplayConfig”.

If you would like to load the external Site, the config file would look like this :

<?xml version=”1.0″ encoding=”utf-8″?>

<plugin id=”MyPluginId”>

<title>

<en> MyPlugin </en>

<ja> MyPlugin </ja>

<zh_CN> MyPlugin</zh_CN>

</title>

<!– write the location of html file to be loaded . This plugin will show up the citrix website on Director UI –>

<url>http://www.citrix.com</url>

<detailedViewUrl> http://www.citrix.com </detailedViewUrl>

<!–if director has to show the POPUP window –>

<height>649</height>

</plugin>

The Config file looks as follows, If you would like to load the file within Director server :

<?xml version=”1.0″ encoding=”utf-8″?>

<plugin id=”MyPluginId”>

<title>

<en> MyPlugin </en>

<ja> MyPlugin </ja>

<zh_CN> MyPlugin</zh_CN>

</title>

<!– write the location of html file to be loaded. The html file should be placed inside the <director >/plugins folder –>

<url>plugins/MyPLugin.html</url>

<detailedViewUrl>plugins/MyPLugin.html</detailedViewUrl>

<!– if director has to show the POPUP window we need to populate detailedviewurl–>

<height>649</height>

</plugin>

Note: you can copy the above content and save it as mypluginConfig.xml

  • Edit page config file

Dashboard, trends and UserDetial page have their own config file. We can find them in the folder “C:\inetpub\wwwroot\Director\DisplayConfig” in Director Server. Inorder to add the plugin, we have to add following lines in the respective file.

<row>

<panel pluginId=”MyPuginId” />

</row>

By adding the above lines into the config files, we will add a new row on the respective page. In this row, the plugin will be loaded. If you would like to add 2 plugin side by side on same row, you can do so by adding the following lines

<row>

<panel pluginId=”MyPuginId1″ />

<panel pluginId=”MyPuginId2″ />

</row>

Here is the sample HTML\Javascript code of the UI Plugin, which calls the backend Service and displays the JSON Response on the textbox.

<!DOCTYPE HTML>

<html>

<head>

<meta charset=”UTF-8″>

<title>Director Plugin</title>

<meta name=”description” content=”testing” />

<meta id=”view” name=”viewport” content=”width=device-width, initial-scale=1.0″ />

<meta http-equiv=”X-UA-Compatible” content=”IE=9″ />

<script>

function httpGet(theUrl)

{

var xmlHttp = null;

xmlHttp = new XMLHttpRequest();

xmlHttp.open( “POST”, theUrl, false );

xmlHttp.setRequestHeader(“Content-type”,”application/json; charset=utf-8″);

xmlHttp.send(‘{“input”:”hello”}’);

document.getElementById(‘1’).value = xmlHttp.responseText;

return xmlHttp.responseText;

}

</script>

</head>

<body>

<button type=”button” onclick=”httpGet(‘http://10.105.154.96/Director/service.svc/web/test’)”>testing</button>

<input type=”text” name=”fname” id = “1”></input>

</body>

</html>

Save the above code as MyPLugin.html in the folder “C:\inetpub\wwwroot\Director”.  Now restart the server and plugin will be loaded on to the Director UI.

Example

Let’s have a look into one example. We have implemented a plugin for generating custom report on XenDesktop.

Customer Report plugin

This plugin has 2 parts. UI plugin and backend Plugin. You can download complete code and executables from here.

CustomReports Code

CustomReportInstaller-XD 7.6

GiHub Repository

To add UI plugin, unzip the downloaded file. Complete logic of UI is in index.html file inside custom reports folder.

Steps to configure Director to load  UI plugin on trendsPage :

  • Place CustomReport folder inside c:\inetpub\wwwroot\Director\Plugins directory.
  • You will have to edit TrendspageConfig.xml inside c:\inetpub\wwwroot\Director\DisplayConfig. Replace the file with the one in zipped folder.
  • Create a folder called Customreport inside c:\inetpub\wwwroot\Director\DisplayConfig and copy XDCustomreportConfig.xml file into it.

This will load UI plugin director. It looks this

custom report

To add a backend plugin, you need to copy the OdataQuery.dll and restart IIS. Director Service will import this dll and expose the API from this dll as a webservice.

Just to have a sneak peek inside the dll, template Code looks as follows:

//Director Namespaces that we have to use

using Citrix.Dmc.Common;

using Citrix.Dmc.Common.Utilities;

using Citrix.Dmc.Common.Plugin;

using Citrix.Dmc.Connector;

using Citrix.Dmc.WebService.Utilities;

using Citrix.Dmc.Connector.Broker;

using Citrix.Dmc.Resources.Service;

using System.Diagnostics;

using Citrix.Dmc.WebService;

//The Namespace the you implement

namespace OdataQuery

{

[DataContract]

public class OdataReturn

{

[DataMember]

public string[][] response;

public OdataReturn(string[][] res)

{

response = res;

}

}

[PluginAttribute]

public interface pluginDllInterafce

{

[OperationContract]

[FaultContract(typeof(DmcServiceFault))]

[WebInvoke(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped)]

String MakeOdataQuery(String ReportName, string SiteId, String Query);

}

// your class

public class PluginTest : pluginDllInterafce,IDisposable

{

public string MakeOdataQuery(String ReportName,string SiteId, String Query)

{

/* Login implementation  *?

}}}