Startup tasks, Elevated privileges & VM Role
In this blog post, let’s do a hands on implementation of the Windows Azure Startup tasks and compare the different role types in Azure.
A Primer on Windows Azure Roles
Windows Azure supports three types of roles:
- Web role: used for web applications and is supported by IIS 7.
- Worker role: used for general development and/or to perform any background processing work for a web role.
- VM role: used to run an image of Windows Server 2008 R2 created on-premise with any required customizations.
In addition to these with 1.3 SDK, you now have to ability to launch your Web/Worker role with elevated privileges and/or use startup tasks to run scripts/exe’s/msi etc. with elevated privileges. So think of it as Web/Worker role with Jet packs.
With great power comes greater responsibility
The diagram above is not meant to say one is better or the other is bad, it is meant to give you an understanding of the differences with respect to the abstraction and control that varies with each of them. As you start changing the environment going upwards, manageability of the application environment becomes more of your responsibility rather than the Fabric’s.
Startup Tasks
To demonstrate a scenario where you need to prep your application environment with a dependency, let’s attempt to install Internet Explorer 9 beta on a Cloud VM which is running on Windows Server 2008 R2.
Please note that to try this on Windows Server 2008 (non R2) you might have to additionally install Platform update for Windows Server 2008 for DirectX (which is a dependency for IE9).
Here is the screenshot of my solution explorer for visual clarity.
I have a tiny little REST service “DistributeRain” which simply returns the installed browser information
public class DistributeRain { Version ver = null; //REST Service to return browser information [WebInvoke(UriTemplate = "/GetBrowserVersion", Method = "GET")] public string GetBrowserVersion() { Thread t = new Thread(new ThreadStart(GetBrowserInfo)); t.SetApartmentState(ApartmentState.STA); t.Start(); t.Join(); return ver.ToString(); } //Grab the version public void GetBrowserInfo () { WebBrowser browser = new WebBrowser(); ver = browser.Version; } }
First let’s try an out-of-box install of our service with some of the default configuration settings in the ServiceConfiguration file that is generated with the 1.3 SDK. We still haven’t done anything to install IE9 beta.
Here is how my service configuration looks, notice the highlighted line
<?xml version="1.0" encoding="utf-8"?> <
ServiceConfiguration serviceName=“RainCloud” xmlns=“http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration” osFamily=“1” osVersion=“*“
> <Role name="RainService"> <Instances count="1" /> <ConfigurationSettings> <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" /> <Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.Enabled" value="true" /> <Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountUsername" value="username" /> <Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountEncryptedPassword" value="password" /> <Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountExpiration" value="2999-03-23T23:59:59.0000000-07:00" /> <Setting name="Microsoft.WindowsAzure.Plugins.RemoteForwarder.Enabled" value="true" /> </ConfigurationSettings> <Certificates> <Certificate name="Microsoft.WindowsAzure.Plugins.RemoteAccess.PasswordEncryption" thumbprint="thumbprint" thumbprintAlgorithm="sha1" /> </Certificates> </Role> </ServiceConfiguration>
So the following attributes determines the Operating System on which your role will be deployed
osFamily="1" osVersion="*"
1.X versions of the OS are compatible with Windows Server 2008 SP2 and 2.X is compatible with Windows Server 2008 R2.
Let’s deploy the above solution as is and check the results.
So we got back Internet Explorer 7, which comes installed out-of-box with a Windows Server 2008 SP2 compatible OS.
Take a look at the OS matrix for the OS flavors available on Azure.
Now lets flip the osFamily switch and redeploy with the following change.
osFamily="
2
" osVersion="*"
Like expected you get back a version corresponding to Internet Explorer 8 which is running on a Windows Server 2008 R2 compatible OS.
You can change the version of the Operating System from theportal
Now that we know the lay of the land, let’s attempt to install Internet Explorer 9 beta on a Windows Server 2008 R2 instance.
Install IE9 beta
So the magic piece of code is highlighted below in the ServiceDefinition file.
<?xml version="1.0" encoding="utf-8"?> <ServiceDefinition name="RainCloud" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition"> <WebRole name="RainService"> <Sites> <Site name="Web"> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" /> </Bindings> </Site> </Sites> <Endpoints> <InputEndpoint name="Endpoint1" protocol="http" port="80" /> </Endpoints> <Imports> <Import moduleName="Diagnostics" /> <Import moduleName="RemoteAccess" /> <Import moduleName="RemoteForwarder" /> </Imports> <Startup
> <Task commandLine=“IE9.cmd” executionContext=“elevated” taskType=“simple“> </Task> </Startup
> </WebRole> </ServiceDefinition>
You need to simply set the commandLine to the name of the program/script that you want to run and executionContext to the permissions with which you want the commandLine arguments to run.
So what is in our IE9.cmd file?
IE9-Windows7-x64-enu.exe /quiet
Yes, that’s it!
Remember to use silent switches (non UI) while installing executables/MSI’s to avoid the need for user intervention.
Make sure to change the command file properties in Visual Studio to “Copy to the Output Directory”
Seems like we’re all set to have IE9 installed on Azure, let’s try another deploy and retest.
So seems like our IE9 install failed for some reason. Some debugging by remoting in revealed an error “Process exit code 0x00000070 (112) [There is not enough space on the disk. ]”
I did notice in the logs, that the IE9 install was attempting to install a .MSU file (which is a windows update), and anytime you think about Windows Update in Azure, know that Windows update is disabled since all OS updates are managed for you by the platform itself. So I went ahead and turned on Windows Update with a slight change to my startup task.
I added the following to my IE9.cmd batch file.
sc config wuauserv start= auto net start wuauserv
IE9-Windows7-x64-enu.exe /quiet
Ideally you should turn off Windows Update right after your installs are completed, and installing IE9 introduces reboot scenarios. I will not cover install + reboot scenarios in this blog post.
So I was feeling slightly more confident, but the next deploy with this change had the same issue.
Steve Marx suggested remoting into the Azure VM and running the Startup task as a “System” user which is a great way to simulate what the startup task was attempting to do. I saw the same error when running as System which validated that the issue had something to do with space where the install files were expanding.
%TEMP%
So there is a 100MB limit on the TEMP folder used by the startup tasks. So to extend the Quota and make sure that my process had access to the TEMP variable, I wrote a console app which spawned my IE9 install and prior to spawning the install, it did the following to set the TEMP variable. All you need to do after that is to call the console app from the startup task.
Directory.CreateDirectory(path); Environment.SetEnvironmentVariable("TEMP", path);
Let’s see what our REST service returns back after this change.
Perfect, we now get back the version corresponding to IE9 beta. Hopefully this will get you started with thinking about the possibilities and applications for Startup tasks.
I will cover Elevated privileges and VM Roles in subsequent blog posts. Stay tuned!