Click here to Skip to main content
15,886,026 members
Articles / Web Development / ASP.NET

How to manage Azure IaaS Programmatically

Rate me:
Please Sign up or sign in to vote.
4.75/5 (4 votes)
2 Jun 2013Apache6 min read 35.6K   9   5
Learn how to manage windows azure virtual machines (IaaS) using C# code

Introduction

This is about 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 we may need to manage windows azure virtual machines (IaaS) through code for one or more of 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

<o:p>

<o:p>

<o:p>

<o:p>

We are going to implement the following basic operation using C# code:<o:p>

  •           List images
  •           Create virtual machine
  •           List virtual machines
  •           Restart virtual machine
  •           Delete virtual machine
<o:p>

<o:p>

<o:p>

<o:p>

<o:p>

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<o:p>

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  <o:p>

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

Using the code

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. <o:p>

Also I’d like to refer here that the code is based on using Asynchronous programming with azure calls 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   <o:p>

The following code explain how to get certificate and initializing HttpClient object with required data like headers and content<o:p> 

C#
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:<o:p>

  •           Request URI
  •           HTTP Method
  •           Headers
  •           Content body 

(1) List Images 

<o:p>

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#
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

<o:p>

(2) Create Virtual Machine<o:p>

Creating virtual machine requires 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 <o:p>

  •        Create hosted service, a container for service deployments in Windows Azure. A subscription may have zero or more hosted services
  •        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.
  •         Create virtual machine, the previous two steps info required here in this step
<o:p>

<o:p>

<o:p>

I suggest here to use the same name for service, deployment and virtual machine to make it easy to manage virtual machines <o:p>

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#
//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#
//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#
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<o:p>

To list virtual machine hosted on windows azure subscription we have to loop over all hosted services to get its hosted virtual machines<o:p>

To do that we need to execute the following operations:<o:p>

  •          listing hosted services
  •          listing virtual machines for each hosted service  
<o:p>

<o:p>

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#
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#
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: 

C#
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="http://schemas.microsoft.com/windowsazure" 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#
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#
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#
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;
}

<o:p>

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

C#
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;
        } 

 

References 

Advanced Windows Azure IaaS – Demo Code<o:p>

Windows Azure Service Management REST API Reference<o:p>

Introduction to the Azure Platform<o:p>

Representational state transfer<o:p>

Asynchronous Programming with Async and Await (C# and Visual Basic)<o:p>

<o:p>

HttpClient Class 

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
HP
Egypt Egypt
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionwhere is the code man? Pin
Member 80030631-Mar-16 2:30
Member 80030631-Mar-16 2:30 
GeneralBad Request Pin
Rachakonda Nagender7-Apr-15 23:17
Rachakonda Nagender7-Apr-15 23:17 
GeneralRe: Bad Request Pin
CodingBruce3-Aug-15 5:35
CodingBruce3-Aug-15 5:35 
The Azure management REST API has changed. It no-longer accepts this format. I've attempted to reverse engineer it without success. If anyone knows of a C# management wrapper that works in 2015, that would be awesome
-bruce

QuestionMissing XML Related Code Pin
JamesCurran13-Jun-13 7:19
JamesCurran13-Jun-13 7:19 
AnswerRe: Missing XML Related Code Pin
Hisham Elbreky16-Jun-13 23:53
Hisham Elbreky16-Jun-13 23:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.