Coding With Windows Azure IaaS

Posted by Hisham El-bereky on ASP.net Weblogs See other posts from ASP.net Weblogs or by Hisham El-bereky
Published on Sun, 02 Dec 2012 20:04:48 GMT Indexed on 2012/12/04 17:07 UTC
Read the original article Hit count: 872

Filed under:
|
|
|
|

This post will focus on some advanced programming topics concerned with IaaS (Infrastructure as a Service) which provided as windows azure virtual machine (with its related resources like virtual disk and virtual network), you know that windows azure started as PaaS cloud platform but regarding to some business cases which need to have full control over their virtual machine, so windows azure directed toward providing IaaS.

Sometimes you will need to manage your cloud IaaS through code may be for these reasons:

  • Working on hyper-cloud system by providing bursting connector to windows azure virtual machines
  • Providing multi-tenant system which consume windows azure virtual machine
  • Automated process on your on-premises or cloud service which need to utilize some virtual resources

We are going to implement the following basic operation using C# code:

  • List images
  • Create virtual machine
  • List virtual machines
  • Restart virtual machine
  • Delete virtual machine

Before going to implement the above operations we need to prepare client side and windows azure subscription to communicate correctly by providing management certificate (x.509 v3 certificates) which permit client access to resources in your Windows Azure subscription, whilst requests made using the Windows Azure Service Management REST API require authentication against a certificate that you provide to Windows Azure

More info about setting management certificate located here. And to install .cer on other client machine you will need the .pfx file, or if not exist by exporting .cer as .pfx

Note: You will need to install .net 4.5 on your machine to try the code

So let start

This post built on the post sent by Michael Washam "Advanced Windows Azure IaaS – Demo Code", so I'm here to declare some points and to add new operation which is not exist in Michael's demo

The basic C# class object used here as client to azure REST API for IaaS service is HttpClient (Provides a base class for sending HTTP requests and receiving HTTP responses from a resource identified by a URI) this object must be initialized with the required data like certificate, headers and content if required.

Also I'd like to refer here that the code is based on using Asynchronous programming with calls to azure which enhance the performance and gives us the ability to work with complex calls which depends on more than one sub-call to achieve some operation

The following code explain how to get certificate and initializing HttpClient object with required data like headers and content

HttpClient GetHttpClient()

{

X509Store certificateStore = null;

X509Certificate2 certificate = null;

try

{

certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);

certificateStore.Open(OpenFlags.ReadOnly);

string thumbprint = ConfigurationManager.AppSettings["CertThumbprint"];

var certificates = certificateStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);

if (certificates.Count > 0)

{

certificate = certificates[0];

}

}

finally

{

if (certificateStore != null) certificateStore.Close();

}

 

WebRequestHandler handler = new WebRequestHandler();

if (certificate!= null)

{

handler.ClientCertificates.Add(certificate);

HttpClient httpClient = new HttpClient(handler);

//And to set required headers lik x-ms-version

httpClient.DefaultRequestHeaders.Add("x-ms-version", "2012-03-01");

httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));

return httpClient;

}

return null;

}

 

Let us keep the object httpClient as reference object used to call windows azure REST API IaaS service. For each request operation we need to define:

  • Request URI
  • HTTP Method
  • Headers
  • Content body

(1) List images

The List OS Images operation retrieves a list of the OS images from the image repository

Request URI

https://management.core.windows.net/<subscription-id>/services/images]

Replace <subscription-id> with your windows Id

HTTP Method

GET (HTTP 1.1)

Headers

x-ms-version: 2012-03-01

Body

None.

 

C# Code

List<String> imageList = new List<String>();

//replace _subscriptionid with your WA subscription

String uri = String.Format("https://management.core.windows.net/{0}/services/images", _subscriptionid);

 

HttpClient http = GetHttpClient();

Stream responseStream = await http.GetStreamAsync(uri);

 

if (responseStream != null)

{

     XDocument xml = XDocument.Load(responseStream);

     var images = xml.Root.Descendants(ns + "OSImage").Where(i => i.Element(ns + "OS").Value == "Windows");

     foreach (var image in images)

     {

     string img = image.Element(ns + "Name").Value;

     imageList.Add(img);

     }

}

More information about the REST call (Request/Response) located here on this link http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx

(2) Create Virtual Machine

Creating virtual machine required service and deployment to be created first, so creating VM should be done through three steps incase hosted service and deployment is not created yet

  1. Create hosted service, a container for service deployments in Windows Azure. A subscription may have zero or more hosted services
  2. Create deployment, a service that is running on Windows Azure. A deployment may be running in either the staging or production deployment environment. It may be managed either by referencing its deployment ID, or by referencing the deployment environment in which it's running.
  3. Create virtual machine, the previous two steps info required here in this step

I suggest here to use the same name for service, deployment and service to make it easy to manage virtual machines

Note: A name for the hosted service that is unique within Windows Azure. This name is the DNS prefix name and can be used to access the hosted service. For example: http://ServiceName.cloudapp.net//

2.1 Create service

Request URI

https://management.core.windows.net/<subscription-id>/services/hostedservices

HTTP Method

POST (HTTP 1.1)

Header

x-ms-version: 2012-03-01

Content-Type: application/xml

Body

More details about request body (and other information) are located here http://msdn.microsoft.com/en-us/library/windowsazure/gg441304.aspx

C# code

The following method show how to create hosted service

async public Task<String> NewAzureCloudService(String ServiceName, String Location, String AffinityGroup, String subscriptionid)

{

String requestID = String.Empty;

 

String uri = String.Format("https://management.core.windows.net/{0}/services/hostedservices", subscriptionid);

HttpClient http = GetHttpClient();

 

System.Text.ASCIIEncoding ae = new System.Text.ASCIIEncoding();

byte[] svcNameBytes = ae.GetBytes(ServiceName);

 

String locationEl = String.Empty;

String locationVal = String.Empty;

 

if (String.IsNullOrEmpty(Location) == false)

{

locationEl = "Location";

locationVal = Location;

}

else

{

locationEl = "AffinityGroup";

locationVal = AffinityGroup;

}

 

XElement srcTree = new XElement("CreateHostedService",

new XAttribute(XNamespace.Xmlns + "i", ns1),

new XElement("ServiceName", ServiceName),

new XElement("Label", Convert.ToBase64String(svcNameBytes)),

new XElement(locationEl, locationVal)

);

ApplyNamespace(srcTree, ns);

 

XDocument CSXML = new XDocument(srcTree);

HttpContent content = new StringContent(CSXML.ToString());

content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/xml");

 

HttpResponseMessage responseMsg = await http.PostAsync(uri, content);

if (responseMsg != null)

{

requestID = responseMsg.Headers.GetValues("x-ms-request-id").FirstOrDefault();

}

return requestID;

}

2.2 Create Deployment

Request URI

https://management.core.windows.net/<subscription-id>/services/hostedservices/<service-name>/deploymentslots/<deployment-slot-name>

<deployment-slot-name> with staging or production, depending on where you wish to deploy your service package

<service-name> provided as input from the previous step

HTTP Method

POST (HTTP 1.1)

Header

x-ms-version: 2012-03-01

Content-Type: application/xml

Body

More details about request body (and other information) are located here http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx

C# code

The following method show how to create hosted service deployment

async public Task<String> NewAzureVMDeployment(String ServiceName, String VMName, String VNETName, XDocument VMXML, XDocument DNSXML)

{

String requestID = String.Empty;

 

 

String uri = String.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}/deployments", _subscriptionid, ServiceName);

HttpClient http = GetHttpClient();

XElement srcTree = new XElement("Deployment",

new XAttribute(XNamespace.Xmlns + "i", ns1),

new XElement("Name", ServiceName),

new XElement("DeploymentSlot", "Production"),

new XElement("Label", ServiceName),

new XElement("RoleList", null)

);

 

if (String.IsNullOrEmpty(VNETName) == false)

{

srcTree.Add(new XElement("VirtualNetworkName", VNETName));

}

 

if(DNSXML != null)

{

srcTree.Add(new XElement("DNS", new XElement("DNSServers", DNSXML)));

}

 

XDocument deploymentXML = new XDocument(srcTree);

ApplyNamespace(srcTree, ns);

 

deploymentXML.Descendants(ns + "RoleList").FirstOrDefault().Add(VMXML.Root);

 

 

String fixedXML = deploymentXML.ToString().Replace(" xmlns=\"\"", "");

HttpContent content = new StringContent(fixedXML);

content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/xml");

 

HttpResponseMessage responseMsg = await http.PostAsync(uri, content);

if (responseMsg != null)

{

requestID = responseMsg.Headers.GetValues("x-ms-request-id").FirstOrDefault();

}

 

return requestID;

}

2.3 Create Virtual Machine

Request URI

https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments/<deployment-name>/roles

<cloudservice-name> and <deployment-name> are provided as input from the previous steps

Http Method

POST (HTTP 1.1)

Header

x-ms-version: 2012-03-01

Content-Type: application/xml

Body

More details about request body (and other information) located here http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx

C# code

async public Task<String> NewAzureVM(String ServiceName, String VMName, XDocument VMXML)

{

String requestID = String.Empty;

 

String deployment = await GetAzureDeploymentName(ServiceName);

 

String uri = String.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}/deployments/{2}/roles", _subscriptionid, ServiceName, deployment);

 

HttpClient http = GetHttpClient();

HttpContent content = new StringContent(VMXML.ToString());

content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/xml");

HttpResponseMessage responseMsg = await http.PostAsync(uri, content);

if (responseMsg != null)

{

requestID = responseMsg.Headers.GetValues("x-ms-request-id").FirstOrDefault();

}

return requestID;

}

(3) List Virtual Machines

To list virtual machine hosted on windows azure subscription we have to loop over all hosted services to get its hosted virtual machines

To do that we need to execute the following operations:

  • listing hosted services
  • listing hosted service Virtual machine

3.1 Listing Hosted Services

Request URI

https://management.core.windows.net/<subscription-id>/services/hostedservices

HTTP Method

GET (HTTP 1.1)

Headers

x-ms-version: 2012-03-01

Body

None.

More info about this HTTP request located here on this link http://msdn.microsoft.com/en-us/library/windowsazure/ee460781.aspx

C# Code

async private Task<List<XDocument>> GetAzureServices(String subscriptionid)

{

String uri = String.Format("https://management.core.windows.net/{0}/services/hostedservices ", subscriptionid);

List<XDocument> services = new List<XDocument>();

 

HttpClient http = GetHttpClient();

 

Stream responseStream = await http.GetStreamAsync(uri);

 

if (responseStream != null)

{

XDocument xml = XDocument.Load(responseStream);

var svcs = xml.Root.Descendants(ns + "HostedService");

foreach (XElement r in svcs)

{

XDocument vm = new XDocument(r);

services.Add(vm);

}

}

 

return services;

}

 

3.2 Listing Hosted Service Virtual Machines

Request URI

https://management.core.windows.net/<subscription-id>/services/hostedservices/<service-name>/deployments/<deployment-name>/roles/<role-name>

HTTP Method

GET (HTTP 1.1)

Headers

x-ms-version: 2012-03-01

Body

None.

More info about this HTTP request here http://msdn.microsoft.com/en-us/library/windowsazure/jj157193.aspx

C# Code

async public Task<XDocument> GetAzureVM(String ServiceName, String VMName, String subscriptionid)

{

String deployment = await GetAzureDeploymentName(ServiceName);

XDocument vmXML = new XDocument();

 

String uri = String.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}/deployments/{2}/roles/{3}",

subscriptionid, ServiceName, deployment, VMName);

 

HttpClient http = GetHttpClient();

Stream responseStream = await http.GetStreamAsync(uri);

if (responseStream != null)

{

vmXML = XDocument.Load(responseStream);

}

 

return vmXML;

}

 

So the final method which can be used to list all virtual machines is:

async public Task<XDocument> GetAzureVMs()

{

List<XDocument> services = await GetAzureServices();

XDocument vms = new XDocument();

vms.Add(new XElement("VirtualMachines"));

ApplyNamespace(vms.Root, ns);

foreach (var svc in services)

{

string ServiceName = svc.Root.Element(ns + "ServiceName").Value;

 

String uri = String.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}/deploymentslots/{2}", _subscriptionid, ServiceName, "Production");

 

try

{

HttpClient http = GetHttpClient();

Stream responseStream = await http.GetStreamAsync(uri);

 

if (responseStream != null)

{

XDocument xml = XDocument.Load(responseStream);

var roles = xml.Root.Descendants(ns + "RoleInstance");

foreach (XElement r in roles)

{

XElement svcnameel = new XElement("ServiceName", ServiceName);

ApplyNamespace(svcnameel, ns);

r.Add(svcnameel); // not part of the roleinstance

vms.Root.Add(r);

}

}

}

catch (HttpRequestException http)

{

// no vms with cloud service

}

}

return vms;

}

 

(4) Restart Virtual Machine

Request URI

https://management.core.windows.net/<subscription-id>/services/hostedservices/<service-name>/deployments/<deployment-name>/roles/<role-name>/Operations

HTTP Method

POST (HTTP 1.1)

Headers

x-ms-version: 2012-03-01

Content-Type: application/xml

Body

<RestartRoleOperation xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

<OperationType>RestartRoleOperation</OperationType>

</RestartRoleOperation>

 

More details about this http request here http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx

 

C# Code

async public Task<String> RebootVM(String ServiceName, String RoleName)

{

String requestID = String.Empty;

 

String deployment = await GetAzureDeploymentName(ServiceName);

String uri = String.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}/deployments/{2}/roleInstances/{3}/Operations",

_subscriptionid, ServiceName, deployment, RoleName);

 

HttpClient http = GetHttpClient();

 

XElement srcTree = new XElement("RestartRoleOperation",

new XAttribute(XNamespace.Xmlns + "i", ns1),

new XElement("OperationType", "RestartRoleOperation")

);

ApplyNamespace(srcTree, ns);

 

XDocument CSXML = new XDocument(srcTree);

HttpContent content = new StringContent(CSXML.ToString());

content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/xml");

 

HttpResponseMessage responseMsg = await http.PostAsync(uri, content);

if (responseMsg != null)

{

requestID = responseMsg.Headers.GetValues("x-ms-request-id").FirstOrDefault();

}

return requestID;

}

 

(5) Delete Virtual Machine

You can delete your hosted virtual machine by deleting its deployment, but I prefer to delete its hosted service also, so you can easily manage your virtual machines from code

5.1 Delete Deployment

Request URI

https://management.core.windows.net/< subscription-id >/services/hostedservices/< service-name >/deployments/<Deployment-Name>

HTTP Method

DELETE (HTTP 1.1)

Headers

x-ms-version: 2012-03-01

Body

None.

C# code

async public Task<HttpResponseMessage> DeleteDeployment( string deploymentName)

{

string xml = string.Empty;

String uri = String.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}/deployments/{2}", _subscriptionid, deploymentName, deploymentName);

HttpClient http = GetHttpClient();

HttpResponseMessage responseMessage = await http.DeleteAsync(uri);

return responseMessage;

}

 

5.2 Delete Hosted Service

Request URI

https://management.core.windows.net/<subscription-id>/services/hostedservices/<service-name>

HTTP Method

DELETE (HTTP 1.1)

Headers

x-ms-version: 2012-03-01

Body

None.

C# code

async public Task<HttpResponseMessage> DeleteService(string serviceName)

{

string xml = string.Empty;

String uri = String.Format("https://management.core.windows.net/{0}/services/hostedservices/{1}", _subscriptionid, serviceName);

Log.Info("Windows Azure URI (http DELETE verb): " + uri, typeof(VMManager));

HttpClient http = GetHttpClient();

HttpResponseMessage responseMessage = await http.DeleteAsync(uri);

return responseMessage;

}

 

And the following is the method which can used to delete both of deployment and service

async public Task<string> DeleteVM(string vmName)

{

string responseString = string.Empty;

 

// as a convention here in this post, a unified name used for service, deployment and VM instance to make it easy to manage VMs

HttpClient http = GetHttpClient();

HttpResponseMessage responseMessage = await DeleteDeployment(vmName);

 

if (responseMessage != null)

{

 

string requestID = responseMessage.Headers.GetValues("x-ms-request-id").FirstOrDefault();

OperationResult result = await PollGetOperationStatus(requestID, 5, 120);

if (result.Status == OperationStatus.Succeeded)

{

responseString = result.Message;

HttpResponseMessage sResponseMessage = await DeleteService(vmName);

if (sResponseMessage != null)

{

OperationResult sResult = await PollGetOperationStatus(requestID, 5, 120);

responseString += sResult.Message;

}

}

else

{

responseString = result.Message;

}

}

return responseString;

}

 

Note: This article is subject to be updated

Hisham

 

References

Advanced Windows Azure IaaS – Demo Code

Windows Azure Service Management REST API Reference

Introduction to the Azure Platform

Representational state transfer

Asynchronous Programming with Async and Await (C# and Visual Basic)

HttpClient Class

© ASP.net Weblogs or respective owner

Related posts about c#

Related posts about IaaS