
Speed. More speed. And to get more speed with desktop virtualization, we hear more and more about how important IOPS are to being able to support the virtual desktop. Not enough IOPS means slowness. No speed. I’ve had a few blogs about it and plan to have a few more. What I wanted to talk about was an interesting discussion I recently had with 3 Senior Architects within Citrix Consulting(Doug Demskis, Dan Allen and Nick Rintalan). There are 3 smart guys who I talk to fairly regularly and the discussions get quite interesting.
This particular discussion was no different. We were talking about the importance of IOPS, RAID configs, spindle speeds with regards to an enterprise’s SAN infrastructure. (Deciding if you are going to use a SAN for your virtual desktops is a completely different discussion that I’ve had before and Brian Madden had more recently). But for the sake of this article, let’s say you’ve decided “Yes, I will use my SAN.” If your organization already has an enterprise SAN solution, chances are that the solution has controllers with plenty of cache. Does this make the IOPS discussion a moot point? If we simply use an IOPS calculator (at least the ones I’ve seen) and do not take into account the caching capabilities of the SAN controllers, won’t we over-provision our virtual desktop environment and end up wasting more money/resources?
Many of us who are familiar with XenDesktop knows that changes made to the golden disk image, when delivered via Provisioning services, is stored in a PVS Write Cache. From numerous tests and implementations, we know that 80-90% of the IO activity from a virtual desktop will be writes. If we configure the SAN Controllers to be 75% write (assuming we have battery-backed write cache controllers), we allow the controllers to allocate more cache for write operations, thus helping to offload the write IO to the disk, which raises the number of effective IOPS the storage infrastructure can support. Think of the controller’s caching capabilities as a large buffer for our disks. If our disks can only support so many write operations, the controller cache stores the writes until the disk is able to write it to the platter. This cache allows the infrastructure to keep moving forward with new operations even though the previous operations were not written to the disk yet. They are all buffered. Just remember, we aren’t reducing the total number of IO operations, we are just buffering them with the controller cache.
Think about it another way. If we encounter a storm where each user will require 10MB of write operations and the storage controller has a 4GB cache, that one controller can support 400+ simultaneous users for this particular storm, and we haven’t even talked about the disk IOPS yet!!! With this scenario, wouldn’t a single disk spindle be able to support this particular storm because the controller is buffering everything? And what’s also interesting is those write operations are being flushed to disk continuously so the number of users the controller will be able to support would be much, much higher.
So if we have cache on our controllers, which most SAN controllers I’ve seen lately have, are we over designing the storage infrastructure by only focusing on IOPS? (this is assuming you are using SAN and not local disks on your hypervisor which I talk about a lot as well). Just remember that those write operations must eventually get written to disk. So if we know what our controller cache is capable of, and we know the amount of storage required for a particular storm (logon, boot, logoff, etc), can’t we support more users (and I mean a lot more users) on the SAN?
What do you think?
Daniel – Lead Architect – Worldwide Consulting Solutions
Follow Me on twitter: @djfeller
My Blog: Virtualize My Desktop
Questions, then email Ask The Architect
It almost sounds like I’m talking about personal finances. You better plan your cache appropriately or you will run out. I’m not talking about money; I’m talking about system memory (although if you plan poorly we will quickly be talking about money).
It comes down to this… system cache is a powerful feature allowing a server to service requests extremely fast because instead of accessing disks, blocks of data are retrieved from RAM. Provisioning services relies on fast access to the blocks within the disk image (vDisk) to stream to the target devices. The faster the requests are serviced, the faster the target will receive. Allocating the largest possible size for the system cache should allow Provisioning services to store more of the vDisk into RAM as opposed to going to the physical disk.
Not planning system cache appropriately is the 8th mistake made when deploying virtual desktops
10. Not calculating user bandwidth requirements
9. Not considering the user profile
8. Lack of Application Virtualization Strategy
7. Improper Resource Allocation
5. Managing the incoming storm
4. Not Optimizing the Desktop Image
Unfortunately, many environments are not configured optimally. Simply adding RAM to a Provisioning services server is not enough; the system must be configured appropriately.
| Parameter |
Description |
|---|---|
| Operating System |
The operating system plays a large role in how large the system cache can become. * Windows Server 2003/2008 x32: 960 MB * Windows Server 2003/2008/2008 R2 x64: 1 TB Because the 64 bit operating system can have a larger system cache, a larger portion of the vDisk can be stored in RAM, which is recommended. Windows 2008 is recommended over 2003 because of the improvements in the memory manager subsystem, which has shown some improvements. |
| RAM | 8-32GB of RAM The more RAM allocated for the server, the larger the system cache can become. The larger the cache means vDisks reads will be faster. If you have more vDisks, you will need more RAM. A quick estimate is to plan for 2GB of RAM/Cache for each vDisk you will host. If you want more details, then I recommend the great article: Advanced Memory and Storage Considerations for Provisioning Servicescreated by Dan Allen (Sr. Architect at Citrix). It goes into the details of how Windows deals with cache. |
| vDisk Storage |
The vDisk can be stored on just about any type of storage (iSCSI, Fiber, local, NFS, CIFS, etc). However, there are a few instances where the storage selected will have an impact on how the Provisioning services server’s operating system caches the vDisk blocks. 1. Network Drive: If the Provisioning services server sees the vDisk drive as a network drive via a UNC path, the server will not cache the file. 2. CIFS Share: If the storage infrastructure is a network CIFS share, Provisioning services will not cache the vDisk in memory. |
| Optimizations | In Windows Server 2003, large system cache must be enabled by configuring the server’s performance options, which is shown in the figure to the right. ![]() In Windows Server 2008, this setting is not required due to the enhancements in the memory allocation system. Windows 2008 utilizes a dynamic kernel memory assignment that reallocates portions of memory on-the-fly, while previous versions had these values hard set during startup. As Windows 2008 requires more system cache, the operating system will dynamically allocate. |
Daniel – Lead Architect – Worldwide Consulting Solutions
Follow Me on twitter: @djfeller
My Blog: Virtualize My Desktop
Questions, then email Ask The Architect
Have you ever had a need to generate a large number of user accounts within Active Directory and didn’t have the time to manually create them? If you are in the business of building test environments or training environments, this scenario may have happenned to you more than once in your career.
In a recent project, we had a need to create 600+ user accounts within our Active Directory domain to support a training class. I took the challenge of producing a simple and intuitive utilty that could do it for us, since I could probably code such an application much quicker than I could manually create the accounts. The end-result is the Active Directory User Creation Utility that I’m providing as part of this article. I figured others could use this as well so I wanted to provide this as a free download. The download is at the bottom of this article – feel free to give it a spin and let me know what you think. For those programmers out there that are just looking to understand how this utility was built, I’ve also provided the full source code as a separate download at the bottom of this article as well.
Launch and configure the utility
Double-click the CreateADUsers.exe file from the downloaded ZIP file to launch the utility. This application can be run from any domain member, it doesn’t have to be run on the Domain Controller. I believe the only requirements for use are that you should log onto your machine as a domain user that has rights to create objects within Active Directory. Your machine should also have the .NET Framework 3.5 installed.
If you have ever manually created user accounts within the Active Directory Users and Computers snap-in, the utility should be pretty self-explanatory. Just in case, the instructions for how to configure the utilty are provided below:
| Setting | Configuration |
|---|---|
| Domain (NetBIOS Name) | Specify the NetBIOS name for your domain |
| Domain (Distinguished Name) | Specify the FQDN for your domain |
| User OU | Specify the Active Directory OU where you want the accounts placed. Examples: To place within the Users OU, you can specify CN=Users;DC=mydomain;DC=com To place within the Departments/HR OU, you can specify something like OU=HR;OU=Departments;DC=mydomain;DC=com |
| Single Account or Multiple Accounts | Specify whether you looking to create a single account or multiple accounts |
| Username | If you specified a single account, this is the username for the account |
| User Prefix | If you specified multiple accounts, this is the user prefix for the accounts |
| Starting Index | If you specified multiple accounts, this is the starting index for the accounts. For example, a user prefix of User with a starting index of 1 will create the accounts User1, User2, User3,… |
| Quantity | If you specified multiple accounts, this is the number of accounts to create |
| Password Never Expires | Specify whether to enable/disable the Password Never Expires attribute on the user accounts |
| User Cannot Change Password | Specify whether to enable/disable the User Cannot Change Password attribute on the user accounts |
| Static Password or Random Password | Specify whether to define a static password across all auto-generated accounts or define a random password for each account |
| Password | If you specified a static password, this is the user-defined password for the accounts |
| Password Length | If you specified a random password, this is the number of characters to include in the password |
| Require Capital Letter | If you specified a random password, this indicates whether the random password should include at least one capital letter |
| Require Lower Case Letter | If you specified a random password, this indicates whether the random password should include at least one lower case letter |
| Require Number | If you specified a random password, this indicates whether the random password should include at least one number |
| Store username and password details in text file | Specify whether you want to place the generated account details within a text file. This is recommended if using random passwords since this will be the only way to get the passwords for those accounts |
| Text File Name | Specify the name of the text file that will contain the generated account details. The default name is Accounts.txt |
| Text File Location | Specify the location where the text file will be saved. |
Run the utility
When you click the Create Users button, the utility will attempt to create the requested number of accounts in the specified OU within Active Directory. If you requested a large number of accounts, it may take a few minutes. A message box will be displayed with the status of the request. An event log entry is also created with additional details and is recommended to check if you run into any issues.
If you specified random passwords for the accounts, you will definitely need to check out the Accounts.txt file that is generated so you can get the passwords for those accounts. You should record these passwords in the proper location and delete this file for security purposes ![]()
Verify the Active Directory accounts have been created
Finally, open the Active Directory Users and Computers snap-in and verify the accounts were created in the proper OU. Feel free to modify the accounts further with profile information or other details. The accounts will be easily visible since the text Auto-generated account will be shown in the description field.
Key source code
Many of you may want to just incorporate this functionality into an existing application that you are building. I provided the full source code as a separate download at the bottom of this article. It’s a Visual Studio 2008 project. If you just wanted to skim the source code, here’s the key code snippets to look at. I’m leveraging the PrincipalContext and UserPrincipal objects provided in the .NET Framework 3.5 library to communicate with Active Directory.
Here are the includes for the project:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Diagnostics; using System.DirectoryServices; using System.DirectoryServices.AccountManagement; using System.IO;
Here is the function that creates the Active Directory accounts:
private void btnCreateUsers_Click(object sender, EventArgs e) { //************************************************** //Define local variables //************************************************** StreamWriter l_objWriter = null; string l_strMessage = ""; string l_strErrorAccountList = ""; int l_intSuccessAttempts = 0, l_intErrorAttempts = 0; try { //************************************************** //Grab values from form //************************************************** string l_strDomain = txtDomain.Text.Trim(); string l_strDomainDN = txtDomainDN.Text.Trim(); string l_strUserOU = txtUserOU.Text.Trim(); string l_strUserPrefix = txtUserPrefix.Text.Trim(); string l_strUsername = "", l_strPassword = ""; int l_intQuantity = Convert.ToInt32(txtQuantity.Text.Trim()); int l_intStartingIndex = Convert.ToInt32(txtStartingIndex.Text.Trim()); int l_intPasswordLength = Convert.ToInt32(txtPasswordLength.Text.Trim()); bool l_blnPasswordNeverExpires = chkPasswordNeverExpires.Checked; bool l_blnUserCannotChangePassword = chkUserCannotChangePassword.Checked; bool l_blnRequireCapital = chkRequireCapital.Checked; bool l_blnRequireLowerCase = chkRequireLowerCase.Checked; bool l_blnRequireNumber = chkRequireNumber.Checked; string l_strTextFileName = txtTextFileName.Text.Trim(); string l_strTextFileLocation = txtTextFileLocation.Text.Trim(); string l_strTextFileFullPath = l_strTextFileLocation + "\\" + l_strTextFileName; //****************************************************************** //Check whether to create single account or multiple accounts //****************************************************************** if (rdoSingleAccount.Checked) //Create single account { //Create user object PrincipalContext l_objContext = new PrincipalContext(ContextType.Domain, l_strDomain, l_strUserOU); UserPrincipal l_objNewUser = new UserPrincipal(l_objContext); //Set username and password l_strUsername = txtUsername.Text.Trim(); if (rdoStaticPassword.Checked) l_strPassword = txtPassword.Text.Trim(); else l_strPassword = this.GenerateRandomPassword(l_intPasswordLength, l_blnRequireCapital, l_blnRequireLowerCase, l_blnRequireNumber); l_objNewUser.SamAccountName = l_strUsername; l_objNewUser.SetPassword(l_strPassword); //Assign user properties l_objNewUser.UserPrincipalName = l_strUsername + "@" + l_strDomainDN; l_objNewUser.DisplayName = l_strUsername; l_objNewUser.Description = "Auto-generated account"; l_objNewUser.GivenName = l_strUsername; //first name l_objNewUser.PasswordNeverExpires = l_blnPasswordNeverExpires; l_objNewUser.UserCannotChangePassword = l_blnUserCannotChangePassword; l_objNewUser.Enabled = true; //Check if user already exists within Active Directory UserPrincipal usr = UserPrincipal.FindByIdentity(l_objContext, l_strUsername); if (usr == null) //User not found. Proceed with save { //Save user to the directory l_objNewUser.Save(); l_intSuccessAttempts++; } else //User already exists { if (l_strErrorAccountList == "") l_strErrorAccountList = l_strUsername; else l_strErrorAccountList += ", " + l_strUsername; l_intErrorAttempts++; } //Check if account details should be stored in text file if (chkStoreInTextFile.Checked) { //Save account details to file l_objWriter = new StreamWriter(l_strTextFileFullPath, false); l_objWriter.WriteLine("1," + l_strUsername + "," + l_strPassword); l_objWriter.Close(); } } else //Create multiple accounts { //Create the specified number of user accounts for (int index = 1; index <= l_intQuantity; index++) { //Create user object PrincipalContext l_objContext = new PrincipalContext(ContextType.Domain, l_strDomain, l_strUserOU); UserPrincipal l_objNewUser = new UserPrincipal(l_objContext); //Set username and password l_strUsername = l_strUserPrefix + l_intStartingIndex.ToString(); if (rdoStaticPassword.Checked) l_strPassword = txtPassword.Text.Trim(); else l_strPassword = this.GenerateRandomPassword(l_intPasswordLength, l_blnRequireCapital, l_blnRequireLowerCase, l_blnRequireNumber); l_objNewUser.SamAccountName = l_strUsername; l_objNewUser.SetPassword(l_strPassword); //Assign user properties l_objNewUser.UserPrincipalName = l_strUsername + "@" + l_strDomainDN; l_objNewUser.DisplayName = l_strUsername; l_objNewUser.Description = "Auto-generated account"; l_objNewUser.GivenName = l_strUsername; //first name l_objNewUser.PasswordNeverExpires = l_blnPasswordNeverExpires; l_objNewUser.UserCannotChangePassword = l_blnUserCannotChangePassword; l_objNewUser.Enabled = true; //Check if user already exists within Active Directory UserPrincipal usr = UserPrincipal.FindByIdentity(l_objContext, l_strUsername); if (usr == null) //User not found. Proceed with save { //Save user to the directory l_objNewUser.Save(); l_intSuccessAttempts++; //Check if account details should be stored in text file if (chkStoreInTextFile.Checked) { //Save account details to file if (l_objWriter == null) l_objWriter = new StreamWriter(l_strTextFileFullPath, false); l_objWriter.WriteLine(index + "," + l_strUsername + "," + l_strPassword); } } else //User already exists { if (l_strErrorAccountList == "") l_strErrorAccountList = l_strUsername; else l_strErrorAccountList += ", " + l_strUsername; l_intErrorAttempts++; } //Increment starting index l_intStartingIndex++; //Close writer if this was the last check if (chkStoreInTextFile.Checked && index == l_intQuantity && l_objWriter != null) l_objWriter.Close(); } } //Write event log entry and display status to user if (l_intSuccessAttempts > 0) { l_strMessage += "Successfully created " + l_intSuccessAttempts.ToString() + " account(s).\r\n"; } if (l_intErrorAttempts > 0) { l_strMessage += "Could not create " + l_intErrorAttempts.ToString() + " account(s): " + l_strErrorAccountList + "\r\n\r\n"; l_strMessage += "If any accounts were not created, they most likely already exist within Active Directory."; } System.Diagnostics.EventLog.WriteEntry("CreateADUsers", l_strMessage, EventLogEntryType.Information, 1001); MessageBox.Show("Task Completed!\r\n" + l_strMessage, "Create Users Task"); } catch (Exception objException) { //Write event log entry System.Diagnostics.EventLog.WriteEntry("CreateADUsers", "Error creating user within application.\r\n\r\nAdditional details:\r\n" + objException.Message, EventLogEntryType.Error, 1002); MessageBox.Show("Error! Please check event viewer...", "Create Users Task"); } }
Here is the function that generates the random password:
public string GenerateRandomPassword(int p_intPasswordLength, bool p_blnRequireCapital, bool p_blnRequireLowerCase, bool p_blnRequireNumber) { //Define available characters for password string[] l_strCapitals = { "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z" }; string[] l_strLowerCases = { "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z" }; string[] l_strNumbers = { "1","2","3","4","5","6","7","8","9","0" }; string[] l_strCharacters = { "A","B","C","D","E","F","G", "H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y", "Z","1","2","3","4","5","6","7","8","9","0","a","b","c","d","e","f","g","h", "i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"}; //Define additional variables string l_strPassword = ""; Random rGen = new Random(); int l_intPosition = 0; //Check if capital is required... if (p_blnRequireCapital && p_intPasswordLength > 0) { l_intPosition = rGen.Next(0, 25); l_strPassword += l_strCapitals[l_intPosition]; p_intPasswordLength = p_intPasswordLength - 1; //Adjust remaining password length } //Check if lower case is required... if (p_blnRequireLowerCase && p_intPasswordLength > 0) { l_intPosition = rGen.Next(0, 25); l_strPassword += l_strLowerCases[l_intPosition]; p_intPasswordLength = p_intPasswordLength - 1; //Adjust remaining password length } //Check if number is required... if (p_blnRequireNumber && p_intPasswordLength > 0) { l_intPosition = rGen.Next(0, 9); l_strPassword += l_strNumbers[l_intPosition]; p_intPasswordLength = p_intPasswordLength - 1; //Adjust remaining password length } //Generate remaining password characters for (int i = 1; i <= p_intPasswordLength; i++) { l_intPosition = rGen.Next(0, 60); l_strPassword += l_strCharacters[l_intPosition]; } //Return password return l_strPassword; }
Download the utility and full source code
The utility and full source code are provided below:
Ed York – Architect – Worldwide Technical Readiness
Ask-the-Architect Site: http://community.citrix.com/p/product-automation#home
Follow Me on twitter: http://twitter.com/citrixedy
For those of you who missed the June 18th TechTalk on the design for a 20,000 user environment, missed out. Well, not really. Luckily, we recorded the presentation so you can watch it whenever you desire. As you know, the webinar was based on a reference design for a 70,000 user school district. Links to the materials are as follows:
- TechTalk Webinar for 20,000 User Design
- Reference Design for the ABC School District
- ABC School District Blogs
In addition to the materials, we also had some really great questions during the webinar, which I’ve answered below:
- Yes
- No
- Maybe
- No Way
- Of Course
- Possibly
- You are Crazy!!!
- E-MC2
Just kidding, the questions you are probably more interested in are as follows:
| Q: Can you go over a little more on the RAM requirements that you need for the virtual desktops? A: Sure. Scalability tests conducted were able to run Windows 7 with 768MB of RAM. However, in an actual real-world implementation, you will most likely need more than that. First, you need to break your users down into different categories (Light, Normal and Power). As you move through these, the users will require more RAM. Based on the student population, high school users will use more apps than middle school or elementary. Thus we need to allocate more RAM for those groups of users. |
| Q: Great Webinar – Did you experience latency problems using Streaming Applications A: If you mean in the launching of applications, yes. Streamed applications will take longer to start than installed applications. What we did to help shorten the time (still not the same) was to move the RadeCache for the streamed applications to the virtual desktop’s D Drive, which is persistent across reboots. That means the application cache stays put and is reused for subsequent launches. Of course it still isn’t as fast as installed because streamed applications also validate the application cache is correct. |
| Q: how did you design HA for PXE services A: You will need redundancy in your DHCP environment. Unfortunately, DHCP can only give you 1 address for the TFTP server. If we integrate NetScaler VPX into the environment, we can perform load balancing for the TFTP server. So with 1 IP address we automatically balance across X number of TFTP servers. And NetScaler is smart enough to know when TFTP is down and it will not forward requests onto i |
| Q: Virtualization of PVS. How many workloads is the cutover between PVS virtual and PVS physical. I guess 2000 desktops = physical PVS , @40 XenApp servers = Virtual PVS is ok? Can you comment ..ta A: No good answer, unfortunately. Can you virtualize PVS… Yes. Do we recommend it? Not for large, enterprise deployments. Most people agree that server virtualization makes sense for workloads that do not fully consume a system resources. PVS does not fit as it will utilize your NIC to the fullest. Putting PVS on the hypervisor offers little benefit. However, for small deployments, 200 virtual desktops, you won’t fully utilize the NIC and might be able to consolidate some servers |
| Q: How can you figure out network overhead on your environment using PVS streaming to XenDesktop host A: Testing PVS is bursty. You only get traffic when you need more of the vDisk. When you do your pilot, you can look to see how much network traffic PVS is generating for a XenDesktop virtual desktop. Some guidelines are as follows: 1 Gbps NIC should be able to support 500 virtual desktop streams. Booting Windows 7 requires roughly 200-230 MB of data across the wire. As you use Office, 300 more MB is transferred (assuming you are using PowerPoint, Word and Excel). Once that data has been transferred, utilization drops until you need more of the vDisk. Although it is bursty, you need to have enough capacity (bandwidth) to support your storms (boot, logon, logoff) |
| Q: what was the plan for fault tolerance on the virtual desktops if using local storage? A: Users log onto another virtual desktop. If we assume the desktops are throw away machines, then there should be nothing relevant for the user. Their files, data, and personalization should be on a network share and not on the virtual desktop. If the server fails, a user just connects to a new virtual desktop |
| Q: What kind of impact do techs like WAAS and Riverbed have on this type of network traffic? A: Not certain. The challenge technologies will have is HDX is encrypted. In order for these devices to do caching/compression, they must be able to decrypt the traffic. Once the optimization solution can read the HDX packets, it can then compress not only within a single session, but across perform cross-session compression for users within the same office or school. But then before the packets are placed on the WAN, the traffic must be re-encrypted to protect the data. |
| Q: You actually assumed no dial-up?!? Nice neighborhood. A: There will be dial-up, but just not from the schools. Students can dial into their ISPs or connect via DSL or cable modem and get access to the environment remotely. This means we will want to optimize the HDX protocol for low-bandwidth situations, like those dial-up users |
| Q: What RAID type for the Virtual Desktop servers? A: RAID 10 (1+0). We have 8 spindles on each hypervisor that will support the virtual desktops. This allows us to not require the use of a SAN because 8 spindles should allow for enough IOPS to support the expected virtual desktop load. RAID 10 gives us fault tolerance, but without the huge write penalties we would get with RAID 5. |
Building a virtual desktop is simply a matter of installing the Windows operating system. Right? Slow down… although this will work, it won’t give you the best performance and scalability. One of the items that many people mistakenly forget to accomplish is to optimize the base operating system. This is the 7th mistake out of the top 10 mistakes made with virtual desktops:
10. Not calculating user bandwidth requirements
9. Not considering the user profile
8. Lack of Application Virtualization Strategy
7. Improper Resource Allocation
5. Managing the incoming storm
Most people spend time creating a customized standard operating environment for their desktop operating systems. This often involves specific location settings, default application settings, and desktop descriptions. However, when delivering an operating system into a virtual desktop, many organizations do not go far enough to optimize the desktop for the virtualized environment. Whether the desktop is a hosted VM-based VDI desktop, a local streamed desktop or a hosted shared desktop, certain optimizations allow the hardware to focus on user-related tasks as opposed to extraneous system-related tasks. The following are examples of virtual desktop optimizations:
- Disable Last Access Timestamp: Each time a file is accessed within an operating system, a time stamp is updated to identify when that file was last accessed. Booting up an operating system accesses hundreds and thousands of files, all of which must be updated. Each action requires disk and CPU time that would be better used for user-related tasks. Also, if Provisioning services is used to deliver the desktop image, those changes are removed when the desktop is rebooted.
- Disable Screen Saver: Utilizing a graphical screen saver consumes precious memory and CPU cycles when the user is not even using the desktop. Those processes should be freed and used by other users. If screen savers are required for security purposes, then simply blanking the screen should be invoked as this does not impact the memory and CPU consumption.
- Disable Unneeded Features: Windows 7 contains many valuable components like Media Center, Windows DVD Maker, Tablet PC Components, and Games. These applications are memory, CPU and graphics intensive and are often not required in most organizations. If these components are made available to users, they will be used. It is advisable to remove unneeded services before deploying the first images.
These are only a few recommendations, but it is obvious that optimizations have a major impact on the virtual desktop environment. I’ve started building a list of optimizations for virtual Windows 7 desktops, which can be found in the [Windows 7 â€] section of the Virtualize My Desktop site. If you are looking to optimize Windows XP, then you can find that in the Windows XP Optimizationdocument.
Stay tuned for more.
Daniel – Lead Architect – Worldwide Consulting Solutions
Follow Me on twitter: @djfeller
My Blog: Virtualize My Desktop
Questions, then email Ask The Architect
All I want is a list of documents that will help me design my XenDesktop environment. Who else wants the same thing? I bet many of you are saying “Yes, Me too!!” That’s great and everything but how do you know when a new white paper is released that relates to XenDesktop design? Do you keep your own personal library of white papers for XenDesktop design? And even more, how do you keep informed when updates are made to previously released white papers?
I’ve got a special treat for you, the NEW XenDesktop Design Handbook. Instead of trying to create a 1,000 page document that discusses all of the different design options and best practices, we are creating a kit for XenDesktop architects. In the kit you will find some goodies:
- Reference Architectures
- Reference Designs
- Implementation Guides
- Planning Guides
This is just the start. If you subscribe to the kit, you will be able to receive notifications when updates are made to the Design Handbook. We are in the process of developing many new best practice documents focused on different design areas that you won’t want to miss. Interested yet? Then how about I give you the link to the NEW XenDesktop Design Handbook (you must log on to MyCitrix).
Daniel – Lead Architect – Worldwide Consulting Solutions
Twitter: @djfeller
Blog: Virtualize My Desktop
Questions? Email Ask The Architect
I just recently posted a SoftLayer activity library to the Citrix Developer Network (CDN). The SoftLayer activity library allows you to order and cancel Cloud Computing Instances (CCIs) on the SoftLayer CloudLayer. This library also allows you to retrieve information about the instances, create templates from the instances, change the power state, and much more!
The activity library and setup instructions can be downloaded here.
Activities Included
This activity library includes the following activities. There’s a lot more I can add to the library, but this should give you a great start for automating various functions on SoftLayer within Citrix Workflow Studio workflows.
| Activity | Description |
|---|---|
| Connect To SoftLayer | Creates a SoftLayer connection using a specified API Username and API Key. |
| Cancel Instance | Cancels (deletes) an instance that is running on the SoftLayer account |
| Create Template | Creates a template from an existing virtual machine instance on the SoftLayer account |
| Disconnect From SoftLayer | Cancels the SoftLayer connection |
| Delete Template | Deletes a template from the SoftLayer account |
| Get Instance Info | Retrieves information for a single active instance running on the SoftLayer account |
| Get Instances | Retrieves the list of all active instances running on the SoftLayer account |
| Get Package Info | Retrieves package information from the SoftLayer account |
| Get Power State | Retrieves the current power state of an instance on the SoftLayer account |
| Get Pricing Info | Retrieves pricing code information from SoftLayer. Pricing codes include things such as OS ID, RAM ID, and CPU ID. This info is needed for placing an order for starting a new instance on the SoftLayer account. |
| Get Template Info | Gathers information about a template within the Softlayer account |
| Get Templates | Retrieves the list of templates stored on the SoftLayer account |
| Get Vlan Info | Retrieves vlan information from the Softlayer account |
| Place Order | Places an order to start a new virtual machine instance on the SoftLayer account |
| Pause Instance | Pauses an instance that is currently running on the SoftLayer account |
| Power Off Instance (Hard) | Performs a hard shutdown of an instance within the SoftLayer account. This is similar to the “force shutdown” command of a XenServer virtual machine that performs a hard shutdown. |
| Power Off Instance (Soft) | Performs a soft shutdown of an instance within the SoftLayer account. This is similar to the “shutdown” command of a XenServer virtual machine that performs a graceful shutdown. |
| Power On Instance | Starts an instance on the SoftLayer account that was previously shut down. |
| Reboot Instance (Hard) | Performs a hard reboot of an instance within the SoftLayer account. This is similar to the “force reboot” command of a XenServer virtual machine that performs a hard reboot. |
| Reboot Instance (Soft) | Performs a soft reboot of an instance within the SoftLayer account. This is similar to the “reboot” command of a XenServer virtual machine that performs a graceful reboot. |
| Resume Instance | Resumes an instance that is currently paused on the SoftLayer account |
Important Notes
To use this activity library, you need to be aware of the following items:
- SoftLayer API Username and API Key are required – once you have your SoftLayer account set up, navigate to https://manage.softlayer.com/Administrative/apiKeychain to generate your own API Key. The SoftLayer activity library will require the API username and API key assigned to your account.
- SoftLayer API is a private API – this means that to execute a workflow from the SoftLayer activity library, (1) your Workflow Studio machine needs to have a VPN connection to SoftLayer or (2) place Workflow Studio on a Cloud Computing Instance (CCI) running on SoftLayer. The instructions for creating your own VPN connection to SoftLayer are provided here – https://manage.softlayer.com/PrivateNetwork/vpn.
Sample Workflow
I’m going to start up a new blog series that discusses how to use the various activities within this library. Essentially all workflows will start with a Connect to SoftLayer activity and end with a Disconnect from SoftLayer activity. Stay tuned for this upcoming blog series!
References
The following resources were used in developing the SoftLayer activity library for Citrix Workflow Studio:
- SoftLayer Developer Network – http://sldn.softlayer.com/
- SoftLayer API – http://sldn.softlayer.com/wiki/index.php/The_SoftLayer_API
Blog Series
I created a blog series about how to use this activity library which is listed below.
- Getting Started
- Ordering instances on SoftLayer
- Checking status of instances on SoftLayer
- Cancelling instances on SoftLayer
- Creating templates on SoftLayer
Ed York – Architect – Worldwide Technical Readiness
Ask-the-Architect Site: http://community.citrix.com/p/product-automation#home
Follow Me on twitter: http://twitter.com/citrixedy
I recently created a SoftLayer Activity Library that allows you to provision new Cloud Computing Instances (CCIs) on SoftLayer within Citrix Workflow Studio workflows. SoftLayer is a cloud provider that allows you to provision virtual machines on their CloudLayer infrastructure. They utilize XenServer as their underlying hypervisor and currently provide three datacenters for provisioning virtual machines – Dallas, Seattle, and Washington DC. They offer a wide variety of operating system templates to choose from and they also provide granular selection over the type of hardware specs you need for running your virtual machines optimally in the most cost effective way.
In this blog, I want to discuss how to get started using the SoftLayer activity library. This is the first blog of a new blog series on how to use this activity library within Citrix Workflow Studio. To view the full list of blogs within this blog series, refer to the bottom of this article.
Why use this library?
Before we get into the technical details, here are some use cases for why you might want to consider using this library:
- CloudBursting – Some of the biggest challenges for managing a local datacenter are space and cost. Transforming servers into Type 1 hypervisors has a made a world of difference on better utilizing existing hardware resources and supporting more workloads. Throughout the course of the year, there can be periods where demand exceeds current capacity. This is where cloudbursting really fits in. With CloudBursting, you continually check the current load on the systems against a defined threshold. If that threshold is met, you spawn up new virtual machines in the cloud to meet the additional load demands. If the requests start to die down, you remove the cloud machines and just rely on your existing hardware again. The process of continually checking loads and provisioning new cloud instances on-demand really fits in well with the workflow concept of Citrix Workflow Studio. This activity library allows you to spawn up these new virtual machines on the SoftLayer CloudLayer.
- SoftLayer Virtual Machine Management – Some of you may already be a SoftLayer customer and you utilize the SoftLayer portal for managing your virtual machines. If you are looking for a simpler, automated way for managing virtual machines, the SoftLayer activity library can allow you to incorporate several virtual machine management functions (e.g. ordering, cancelling, checking status, restarting, etc.) as part of a workflow within Citrix Workflow Studio.
Before you begin
To use this activity library, you need to first perform the following steps:
- Get the API Username and API Key for your SoftLayer account – once you have your SoftLayer account set up, navigate to https://manage.softlayer.com/Administrative/apiKeychain to generate your own API Key. The SoftLayer activity library will require the API username and API key assigned to your account.
- Ensure your Workflow Studio environment can reach SoftLayer – the SoftLayer API is a private API. This means that to execute a workflow from the SoftLayer activity library, (1) your Workflow Studio machine needs to have a VPN connection to SoftLayer or (2) place Workflow Studio on a Cloud Computing Instance (CCI) running on SoftLayer. The instructions for creating your own VPN connection to SoftLayer are provided here – https://manage.softlayer.com/PrivateNetwork/vpn.
Create your first workflow to get the SoftLayer pricing codes
Once you have your Workflow Studio environment running and the SoftLayer API Username and Key handy, you are now ready to compose your first workflow. To order instances on SoftLayer, we need to gather the pricing codes for specifying the type of OS we want and the RAM/CPU/DISK to use for the virtual machine. If you have used the SoftLayer Management Portal in the past, their portal manages all of these codes for you and you never need to know they exist. However, since we are now automating the ordering process, we need to gather and supply these codes as part of the ordering process. This probably sounds more difficult than it actually is – and it’s very easy for us since the SoftLayer activity library can gather all of the pricing codes for us. The first workflow we create will allow us to get the SoftLayer pricing codes to use later when ordering instances.
Open the Workflow Studio Console and create a new workflow called GetPricingCodes. Within the Workflow Studio Designer, drag the Connect To SoftLayer, Get Pricing Info, Export To XML, and Disconnect From SoftLayer activities to the designer surface as shown below. The Export To XML activity can be found within the Windows PowerShell activity library section. The other three activities are all part of the SoftLayer activity library section.
Configure the activities as noted in the table below:
| Activity | Configuration |
|---|---|
| Connect To SoftLayer |
|
| Get Pricing Info |
|
| Export to XML |
|
| Disconnect From SoftLayer |
|
Run the workflow within the Designer. Ensure that it succeeds properly.
Locate the XML file that was generated from the workflow – C:\Citrix\SoftLayer\Pricing.xml. This XML file contains the pricing codes for several different SoftLayer ordering categories. We are just interested in the codes for operating system, RAM, CPU, and disk as these are required for ordering instances within the SoftLayer activity library.
Next Steps
In the next blog we will create a workflow to order an instance on SoftLayer using the pricing codes from the XML file. Stay tuned!
Blogs in this series
- SoftLayer Activity Library Download
- Getting Started (this one)
- Ordering instances on SoftLayer
- Checking status of instances on SoftLayer
- Cancelling instances on SoftLayer
- Creating templates on SoftLayer
Ed York – Architect – Worldwide Technical Readiness
Ask-the-Architect Site: http://community.citrix.com/p/product-automation#home
Follow Me on twitter: http://twitter.com/citrixedy
Electronic Medical Records (EMR) implementations have their own, unique challenges. Healthcare organizations are concerned with selecting a vendor, complying with a myriad of regulations, and basically transforming the way healthcare is delivered to their patients.
Given the transformative nature of an EMR implementation, virtualization is often just a side thought for health CIOs. Therefore, I’d like to shed some light into the topic and share my personal top 5 reasons to pursue this topic further- starting with the centralization of medical records data.
For a quick definition of the term itself, please refer to yesterday’s blog.
I assume that the backend database for your electronic health records reside in a single, centralized datacenter. Through global server load balancing, you may have already implemented site-to-site redundancy, but that’s beside the point for today’s discussion.
So, traditionally, you would have rich client applications or web browsers on the user’s endpoint to consume and manipulate the medical records data. This automatically implies that a lot of health data moves to and from the datacenter and often to remote locations where it is challenging to maintain a tight grip on security.
Application or Desktop Virtualization can solve that problem. Both of these techniques move the client software piece (or web browser) to the datacenter, where it executes securely inside your facility. The health data never even leaves the datacenter. The user interaction happens via a secure, high performance protocol (such as Citrix’ HDX in the XenApp and XenDesktop product lines) and gives the user a snappy interaction with the software, while only exchanging screen updates and keyboard/mouse events between the end user and the datacenter. Additional data streams pertaining to peripherals, printers, USB devices, scanners, and client hard drives are possible, but can easily be disabled to promote further security.
No data ever makes it to the end point, and therefore reducing the risk of HIPAA/HITECH covered security breaches. In addition, user sessions can be audited to establish an independent trail of information in case the regulators or courts require a closer look.
If you’re curious, I encourage you to check out Dan Feller’s Ask the Architect site. Dan has a wealth of information on desktop and application virtualization and associated whitepapers and reference architectures.
Florian Becker
Twitter: @florianbecker
Virtualization Pulse: Tech Target Blog
Ask the Architect – Everything Healthcare
Someone save me from antivirus. Did you read that correctly? I said save me from antivirus.
Odd isn’t it? Anti-virus is there to protect us, but we also need to be protected from antivirus. Antivirus solutions are critical, even in a virtual desktop environment. Many people believe that because a hosted VM-based virtual desktop image is created from a real-only image that they are immune from virus. That is only partially true. When you reboot, the virus goes away because the changes to the base image are destroyed (including the virus), but what about that time period between getting infected and the next reboot? Those few hours are dangerous and it is why antivirus is takes up the number 6 spot in the Top 10 Mistakes to Avoid with Desktop Virtualization:
10. Not calculating user bandwidth requirements
9. Not considering the user profile
8. Lack of Application Virtualization Strategy
7. Improper Resource Allocation
If using hosted shared desktops or hosted VM-based VDI desktops, those virtual desktops are located within the data center with other critical systems. If a virus made it into the data center, the entire infrastructure is at serious risk. However, simply adding an antivirus solution to the virtual desktop can protect the environment. So what’s the big deal? Just do it right? Well, nothing is as simple as one expects it to be. Antivirus can have a major impact on the virtualization infrastructure, and even cause users to experience poor virtual desktop performance, if done improperly.
If the virtual desktops are streamed with Provisioning services, and those desktops start a full system scan at roughly the same time. Provisioning services only streams the portions of the disk image that are required. However, if a full system scan is done, those virtual desktops will eventually request the entire vDisk image. This not only overwhelms the network and Provisioning services, but also impacts the storage infrastructure as the write cache is utilized and explodes in size. Overcoming these issues is a fairly easy matter and is based on the following recommendations:
- The desktop image must be free from viruses. It is recommended to do a full system scan in private image (read/write) mode. This guarantees the image is clean.
- When the desktop image is in standard mode (read-only), the antivirus should be configured as follows:
- Only scan create/modify activities of files
- Scan on write events only
- Scan local drives only
- Exclusions
- Pagefile
- Print Spooler directory
- Write cache file
- EdgeSight database
- ICA client’s bitmap cache directory
- Remove the antivirus configurations from the HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
\Current Version\Run registry key
- Reconfigure antivirus so that the virus definitions file is stored on a persistent diskso antivirus doens’t have to download the entire definition file on each startup.
These will help overcome antivirus headaches.
Daniel – Lead Architect – Worldwide Consulting Solutions
Follow Me on twitter: @djfeller
My Blog: Virtualize My Desktop
Questions, then email Ask The Architect




