Tuesday, January 28, 2014

XenServer Upgrade 6.0.2 to 6.2 : the vm is incompatible with the cpu features of this host

The Solution

In my case I ended up needing to force the VM migration via the command line on each server. From xencenter, connect to the host that you're getting the error on and bring up the console. Enter the following command.

xe vm-migrate host=<xenserverhost> force=true vm=<vmname>
#<xenserverhost> is the host you're migrating to - should be the one of the ones that has already been updated. You're not allowed to migrate to an un-upgraded host, so forcing it to do so could break everything. Be careful.
#<vmname> is the name that shows up in xencenter, there's also an option to do it by UUID

This will force the machine to migrate to the new host. Keep in mind I am running this in a homogeneous environment, so I had some assurance that compatibility wasn't going to be an issue. If you're running on non-homogeneous hardware you'll probably want to test with a non-critical (or at least less critical VM) before you start migrating everything.

The Cause/Full Story

Upgrading servers is always a time and a half. One of the reasons I like Citrix XenServer is the ability to do rolling upgrades on server pools without shutting down any VMs. It works great in theory, but theories are flimsy things because they exist on paper - a substance not known for ability to withstand stress (slightly tortured analogy).

I ran into a problem today upgrading some of my XenDesktop VM hosting XenServers from version 6.0.2 (+ various updates) to version 6.2. This version (and indeed all versions back to 5.6) are supposed to be compatible with the rolling upgrade feature in xencenter. 

I made all the backups, and followed all of the "before upgrading" steps listed in the guide, then started the install using the rolling pool upgrade wizard in xencenter. 

The first server (the master) went great. All the VMs migrated off the server, everything installed and it came back up just like it should. However when I went to start the second server update, none of the VMs could migrate off with the error "the vm is incompatible with the cpu features of this host"

Which was bull, since most of the VMs had just been running on that server, and were currently running on a server that was identical hardware. So after a bit of googling I found the follow commands.

xe host-cpu-info
xe host-reset-cpu-features
xe host-set-cpu-features

Running the first command on the upgraded server and an non-upgraded server I could see that the CPU feature set had changed (for some reason). I tried the second command, to see if resetting would work, but even after a server reboot the feature set was the same. I tried manually setting the feature set using the third command. That seemed to work, the "feature set after reboot" changed to the correct feature set. However after a reboot the feature set had not actually changed. 

Running low on options I went to the command line to try to migrate (GUIs are for babies, etc. etc.). Trying to migrate the servers manually using the "xe vm-migrate" command yielded the same error. But running xe help vm-migrate showed me there was a "force=" parameter I could set.

Luckily I had a few currently-not-in-use VMs I could use to test. The test machines were able to migrate using the force option. I was able to force migrate all of the VMs without any crashes or other problems. After this I was able to finish the upgrade on the other pool members. For the record these were all windows 7 machines (and one server 2008 R2) with the 6.0.2 XenTools installed.




Thursday, January 16, 2014

Setting up Wyse Xenith 2 as an Information Kiosk: Part 2

Previously: Setting up Xenith 2 Kiosk Part 1

And now for the long awaited conclusion to the epic story of setting up the Wyse Xenith 2 as an information kiosk. Reasons for the long delay between segments range from "really busy with end/beginning of semester stuff" to "couldn't be asked".

So today we'll be going over setting up of the web browser (chrome) in kiosk mode, getting everything to start automatically through logon scripts, and preventing users from accessing unauthorized websites.

Setting up Chrome in Kiosk Mode

This is actually really easy. Simple run from the command line (or append to the end of a shortcut command) <pathtochrome>/chrome.exe --kiosk. This will start chrome in kiosk mode, which will give user no access to the URL bar or any chrome settings. The key redirection we set up previously will insure users are unable to escape from the chrome window, or access any chrome console/debug windows/etc.

At this point you'll also want to set the homepage to whatever information page you want users to see first.

I choose chrome because it's easy to setup for a kiosk and some of the other extensions will be useful for website blocking. If you want to use another browser you may be able to find extensions/plugins to make it work.

Logon Scripts

The next thing we need to do is make sure everything starts when the user logs in. Having an auto-login thin client is pointless if you have to go start all of the software manually.

There's a few different ways you could handle this, and they way I did it is almost surely not the most efficient. The issue I ran into trying to combine everything into one script is that windows would not execute both commands simultaneously. It would run the chrome launch command, then wait for chrome to exit before running the auto hot key command. So here's what I did.

In group policy under users>policies>windows settings>scripts>logon create two separate scripts. One will be to run chrome, the other to start autohotkey with the appropriate script. They will look something like this

program: c:\windows\system32\cmd.exe
parameters: /C "\\this.is.my.domain\SysVol\this.is.my.domain\Policies\{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}\User\Scripts\Logon\launchchrome.bat"

program: c:\windows\system32\cmd.exe
parameters: /C "\\this.is.my.domain\SysVol\this.is.my.domain\Policies\{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}\User\Scripts\Logon\launchAHK.bat"

The contents of the batch file will look something like this:

LaunchAHK.bat
"C:\Program Files\AutoHotkey\AutoHotkey.exe" "\\this.is.my.domain\SysVol\this.is.my.domain\Policies\{AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}\User\Scripts\Logon\DisableKeys.ahk"

Launchchrome.bat
"C:\Program Files\Google\Chrome\Application\chrome.exe" --kiosk


Blocking users access to other websites

The easiest way to handle this is to craft a special web page for the kiosk that doesn't have links to any external sites. Because kiosk mode keeps people from accessing the URL/search bar, this will effectively block non-authorized usage.

However, if you (or your web guys) don't have time to setup a special website, there are other options.

The first, and most cumbersome is using windows firewall. Setting up firewall rules can allow you to block/allow certain IP addresses. However, this method cannot limit based on URL; so if a website has a non-static IP, or there are some pages on a website you don't want users to have access to this method will be insufficient. 

Luckily there are chrome plugins to do the job.  The one I ended up using was Whitelist for Chrome because I needed to allow access to our companies public site and block everything else. After installing the plugin all I had to do was add *.my.company.com to the whitelist and we were all set. 

Actually, I did use firewall to block access to a few web authentication servers, just to prevent employees from logging into their personal stuff from the public terminal. 

Conclusion 

So with all of that, you should be all set. A few things I have found out since I started writing this guide.

Nightly Reboot - If a user clicks a link that opens in a new tab/window the new tab/window will open but since it's in kiosk they won't be able to close it. This isn't much of an issue from a usability standpoint but can cause chrome to start taking up all system resources if left unmanaged for too long. I setup a nightly reboot to clear out everything. Note that you need to reboot the thin nightly as well (possible to set this up in the Xen.ini file) so that it reconnects after the vm reboots.

Screen Saver - The people I set this up for insisted that the machine not go to sleep. This makes sense from a usability standpoint; a kiosk is more approachable if there's something on the screen. However when had burn in (low end LCD monitor) within about a month of it being on ~24/7. So if you have similar requests find a way to do some sort of screen saver.

Well that's that. Post in the comments if you have any questions.

Wednesday, January 15, 2014

Adventures in XenDesktop 7 Powershell/SDK : Getting a full list of users/machines from an access policy

The Command You're Looking For

Get-BrokerAccessPolicyRule -name "<groupname>" | % {$_.<property>}

Example: Get-BrokerAccessPolicyRule name "mygroup_direct" | % {$_.includedusers}

This returns the full list of all included users/groups in the "mygroup_direct" rule.

Explanation

I've been working with get/set-brokeraccesspolicyrule a lot lately. It's super useful for managing what users have access to what desktops from what machines, in a much more exact way than is possible through the studio application.

It's allowed me to do some really nice things from a user experience standpoint, which I may elaborate on a little later.

One big problem I've been running into was getting information back out of these. For instance, I've got some ACLs (APRs?) set based on user AD Group membership. These work fine, but if I add a bunch, then want to double check which groups I've added, it's not quite so straight forward.

Running a command like : Get-BrokerAccessPolicyRule -name "group_direct"

returns this:

ExtensionData                    : System.Runtime.Serialization.ExtensionDataOb
                                   ject
AllowRestart                     : True
AllowedConnections               : NotViaAG
AllowedProtocols                 : {HDX, RDP}
AllowedUsers                     : Filtered
Description                      :
DesktopGroupName                 : <redacted>
DesktopGroupUid                  : 2
Enabled                          : True
ExcludedClientIPFilterEnabled    : False
ExcludedClientIPs                : {}
ExcludedClientNameFilterEnabled  : True
ExcludedClientNames              : {<redacted>}
ExcludedSmartAccessFilterEnabled : False
ExcludedSmartAccessTags          : {}
ExcludedUserFilterEnabled        : False
ExcludedUsers                    : {}
IncludedClientIPFilterEnabled    : False
IncludedClientIPs                : {}
IncludedClientNameFilterEnabled  : True
IncludedClientNames              : {<redacted>client1,client2,client3,client4.
                                   ..}
IncludedSmartAccessFilterEnabled : True
IncludedSmartAccessTags          : {}
IncludedUserFilterEnabled        : True
IncludedUsers                    : {<redacted>group1,group2,group3,group4,...}
MetadataMap                      : {}
Name                             : <redacted>_Direct

Uid                              : 1002

As you can see several of the sections get cut off with a "...". This is super annoying if you're trying to verify that all the groups you think you added are actually there. My typical approach here is to run a command to only display the field I'm looking for so it doesn't get cut off, something like this:  Get-BrokerAccessPolicyRule -name "group_direct" | select includedusers

This doesn't work here though, it returns the same cut off list. After a lot of playing around I finally found what works (See The Command You're Looking For above). It's a simple command, but it's a strange way of having to get information out of the system. Using that command you get output like this:

ExtensionData : System.Runtime.Serialization.ExtensionDataObject
FullName      : <redacted>
Name          : domain\group1
SID           : S-1-1-11-11111111-111111111-111111111-11111***
UPN           :

ExtensionData : System.Runtime.Serialization.ExtensionDataObject

FullName      : <redacted>
Name          : domain\group2
SID           : S-1-1-11-11111111-111111111-111111111-11111***
UPN           :

ExtensionData : System.Runtime.Serialization.ExtensionDataObject

FullName      : <redacted>
Name          : domain\group3
SID           : S-1-1-11-11111111-111111111-111111111-11111***
UPN           :

This information is far more useful, and can be selected,filtered, and sorted from here.