Friday, September 20, 2024

No REST For The RESTful: Omnissa's Horizon Server API

The Horizon Server API is a RESTful API that supersedes the legacy View API for Horizon.  It's the outcome of a modernization effort years in the making, a REST based API at full parity with it's predecessor as of the Horizon 2312 release. While Horizon currently supports both the newer and legacy API, the writing is on the wall.  Going forward new Horizon automations should be created using the Horizon Server API and any previous automations based on the View API should be considered for migration. 

https://developer.omnissa.com/horizon-apis/horizon-server/
https://developer.omnissa.com/horizon-apis/horizon-server/














Customers have the flexibility to access the RESTful Horizon Server API from pretty much any programing language, OS or endpoint imaginable, a major advantage over the PowerShell constricted View API.   However, many Horizon admins are unfamiliar with RESTful APIs and the principals that guide their use, so I've put together this primer.  After a brief review of RESTful concepts I'll focus on Swagger and Postman as tools to get familiar with the Horizon Server API.  


RESTful APIs 

When making calls to the Horizon Server API and it's various endpoints, the base url will be https://<fqdn_of_connection_server>/rest/For example, my Horizon Connection Server is horizon.evengooder.com, so the base URL is https://horizon.evengooder.com/rest/.  Then there's the various endpoints offering different functionality, such as monitor/v3/connection-servers, inventory/v2/sessions, or external/v1/ad-users-or-groups.













Leveraging various endpoints is all about sending HTTP requests to these URLs and in turn receiving HTTP responses.  The exact requirements for the requests vary from endpoint to endpoint.  Some require special parameters to the URL or path variables, while others require specific JSON attributes within the body of the request.  The responses vary as well, though they all involve returning data in the JSON format within the body of the responses. 

Intro To APIs Part 3: HTTP Protocol Explained - https://www.youtube.com/watch?v=FAnuh0_BU4c&list=PLM-7VG-sgbtBBnWb2Jc5kufgtWYEmiMAw&index=3























The JSON objects returned are collections of key\value pairs, separated by colons and commas, wrapped in brackets.   The values of these key\value pairs can be strings, other objects, arrays or even arrays of other objects.   






















This standardized format makes the Horizon Server API output easy to work with across languages.  As json.org puts it, "JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate."  

An ideal way to begin exploring the various Horizon Server API endpoints is through the Swagger implementation available by default on your Horizon Connection Servers.  Along with providing documentation, this Swagger implementation is essentially an HTTP client with training wheels, guiding admins in the execution of calls against the local instance of the Horizon Server API. 


Swagger Like Us

While there's on-line documentation available for the Horizon Server API, the Connection Server's built-in Swagger implementation provides a readily accessible and more useful alternative.  It's accessed by pointing your browser to https://<fqdn-of-connectionserver>/rest/swagger-ui/index.html.  























As you explore the various endpoints you'll see there's an option to execute against them directly from within the documentation using a built-in client.  The client prompts for any required parameters, path variables or body responses needed for successful execution of a specific endpoint, helping nudge customers towards proper syntax.  For example, there's a call you can make to inventory/v8/desktop-pools to get information regarding a specific desktop pool.  Since it requires a desktop pool's ID as a path variable the Swagger interface prompts for the ID, indicating it as required. 













When you provide the necessary ID and execute you'll see the client automatically appends the ID to your call for you. 



















Along with required parameters or path variables Swagger also provides guidance on any attributes required in the request body.  Take for example the entitlements/v1/desktop-pools endpoint.  Swagger provides a sample of the name/value attributes required to execute this call successfully.  Replace them with valid ad_user_or_group_ids and a proper desktop pool ID and you'll get your entitlement created. 





























Before executing calls through Swagger it's necessary to obtain a valid bearer token for authentication.  The most common way to do this is through the login endpoint under Auth.

















After clicking on the option to, "Try it out,"  you'll see a preconfigured response body with variables to fill out.   Enter in the domain name, short AD username, and password for an account with admin privileges. 


































Hit the execute button and if things go well you should see a body response that includes an access_token name and value.  













Copy the access_token value, navigate back up to the top of the Swagger interface and click the authorize button.   Paste the access token in as your Bearer value.  
















At this point you can fire at will, leveraging all the different endpoints available from the Swagger interface for the default 30 minutes the access_token takes to expire. 

Overall, Swagger offers a solid process for nailing down your syntax and getting your hands dirty quick with the JSON output.  As far as I'm concerned Swagger on the local Connection Server should be the first stop for anyone looking to explore a specific endpoint.   However, if you're looking to explore more complex tasks that involve multiple calls working together Postman is definitely worth checking out. 


Getting Further Acquainted With The Horizon Server API Through Postman

Postman is an HTTP client designed to assist with the development and testing of APIs.  As such, it's an ideal vehicle for getting familiar with the Horizon Server API and it's REST architecture.   A free version of Postman is available after registering at Postman.com.   Once registered you can log into Postman and easily import my own Postman collection, Horizon Server API Shenanigans, by clicking on this button:


After importing the collection you'll have access to handful of requests, including some advanced sequences within the Horizon Automation folder. 














This collection is an adaptation of a collection originally shared by Chris Halstead in 2019.  While his shared collections attempted to provide preconfigured calls for every supported endpoint, Horizon Server API Shenanigans is a more stripped down collection of calls for the purpose of demonstrating how to chain Horizon REST API calls together.  It shamelessly borrows the authentication scheme introduced in Chris's original work.  The process starts by entering in your admin AD credentials in the collection's Variables tab.






















After setting those variables navigate to the Login call within the root folder and execute it.   If the call is successful a JWtoken global variable is assigned a fresh access_token.   The collection is configured so that this access token is automatically inserted in the header of other calls executed by the collection.  If you look at the authorization tab at the root of the Postman collection you can see how this is configured:



















All the other calls are configured to emulate this authentication scheme by leveraging the option, "Inherit auth of parent."  So, once you've successfully executed this first call you can fire at will with all the other ones, at least until your access token expires in 30 minutes.  An easy way to take things for an initial test spin is to poke around the Horizon Monitoring folder.  For example, here's the status for the Horizon Connection Server:


























All these Infrastructure monitoring calls can be executed once the Login call has been run.   Other sequences, such as Message User And Disconnect, rely on additional variables getting set ahead of time.  I'll address this sequence in more detail next.  


Chaining Multiple Calls For More Advanced Procedures 

The main objective of Horizon Server API Shenanigans is to demonstrate how multiple calls to the Horizon Server API are chained together to perform complex automations.  For example, the Message User And Disconnect folder includes 5 different calls that build upon each other.  The first 3 calls have a post-response script configured to parse responses and retrieve variables that our leveraged for future requests.  For example, the call to the login endpoint is used to retrieve an access token that's used for the next 4 calls.  The external/v1/ad-users-and-groups endpoint is used to locate the unique ID associated with a specific user's login account.  The inventory/v1/sessions endpoint is used to locate a session ID associated with this AD account.  Finally. the send message and disconnect endpoints are used to send a message and disconnect a session.













You can see all this in action by first setting the target_user variable, under the collection's Variables tab, to the short AD login name for the user you wish to target.  Then navigate to the Message User And Disconnect folder and begin executing the calls one by one.   With the first call to the login endpoint the global JWtoken variable gets set.  After running Fetch target_user ID successfully the collection variable ad_user_id is set to the target user's ID.  After running Fetch target_user Session ID the collection variable SessionHunt gets set to the target user's session ID.  You can confirm how these collection variables have been set by navigating to the Variables tab of the collection.





















Finally, the Send Message To User and Disconnect session calls will leverage the SessionHunt variable to send the target_user a message and disconnect them.






























Within the Horizon Automation folder of Horizon Server API Shenanigans, similar flows are available for adding user entitlements to desktop pools, adding desktops to manual pools or killing specific applications within VDI sessions.   Each of these flows requires the setting of specific collection variables, like target_pool or machine_name.   






















To get deeper on this topic of chaining calls together through variables and post-request scripts, check up my follow up article, No REST For The RESTful: Chaining Together Calls To The Horizon Server API.


Adding Additional Calls To Postman Via Swagger Exploration

You can add additional calls to your Postman collection by right clicking and selecting Add Request.



Rather than stressing about getting proper syntax and URLs lined up, you can get everything sorted out ahead of time through the Swagger interface.  For example, to add a new request to a monitoring API, navigate to saml-autheneticators under monitor within Swagger.  Hit the Try it out button and click execute.  You'll get a response like this: 























Note, not only have you successfully executed a call against the local Connection Server, but you have the request URL clearly spelled out for you.  You can copy and then paste this request URL directly into Postman and your off to the races:





















That is a very simple example of how we can pull a query from Swagger into the Postman interface.  There are definitely more complex calls to adopt with this strategy.  These will be demonstrated in the follow up No REST For The RESTful: Chaining Together Calls To The Horizon Server API


Original Collection Put Out By Chris Halstead

Still available at GitHub today is a preconfigured Postman Collection for VMware Horizon REST API put out by Chris Halstead.  While this collection is a bit dated, last updated for Horizon 2111, I think it's still highly relevant and worthwhile for anyone getting started with the Horizon Server API today.   It includes 100's of preconfigured calls for folks to explore and tinker with, all organized according to endpoint type and versioning.  

While I'm a big fan of this collection, and Chris Halstead in general, it is slightly dated and starting to show it's age.  For one thing, I had challenges leveraging the collection variables for authentication purposes.  To get it working properly I had to change Username, Password and Domain to lowercase.  



















Another challenge I ran into was that the authentication method for all the individual calls were defaulting to bearer token, rather than, "Inherit auth from parent."  So for each call I was interested in running I had to make this adjustment.   It's not rocket science once you know to do it, but it can lead to confusion.  






















Finally, some of the logic includes deprecated code.  It still works, but can be a bit confusing for the uninformed as you see lines cutting across the screen.  













All that said, if you're looking to explore the Horizon Sever API it's silly not to take advantage of all these preconfigured and organized calls.   You can go ahead and create your own collection, but also import this collection and start copying it's most relevant calls into your own.  That's certainly what I did.  Stand on the shoulders of giants baby!  

Speaking of giants, along with these Postman Collections, Chris also once authored an article in TechZone called, "Using The VMware Horizon Server REST API." Like his collections, it was getting a little long in the tooth which is why I imagine it was removed from TechZone November of last year.  However, it was a beautiful piece of documentation, providing many a Horizon admin their first introduction to REST architecture and the JSON standard.  So I'd highly recommend taking a look at the original article using the internet archive.  Here's a link to a version of the document that was published as of November of 2023.  


"I got bills to pay 
 I got mouths to feed
 There ain't nothing in this world for free" - Cage The Elephant

For a lot of grizzled Horizon admin the trickiest thing about Horizon Server API adoption is it's REST architecture.  Sure, as windows admins they've had all the motivation in the world to learn PowerShell, but up till now they may never have had  reason to access a REST based API.  So for some folks there's a bit of a learning curve as they get up to speed with REST architecture and JSON format.  But once the Horizon admin is THERE, they're THERE and they can certainly do anything they've been doing with PowerCLI using the more modern Horizon Server API.  As an added bonus, getting up to speed on REST architecture leads to deeper understanding of how much of the internet runs today, and sets a foundation for automating against SaaS solutions that enterprises have been fully embracing.   

To get deeper into the Horizon Server API and REST principles in general, check out my follow up article, No REST For The RESTful: Chaining Together Calls To The Horizon Server API.  

No comments:

Post a Comment