How to manage Azure IaaS Programmatically






4.75/5 (4 votes)
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
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
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.
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
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
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 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
- 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
I suggest here to use the same
name for service, deployment and virtual machine 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
//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;
}
//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
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 virtual machines for each hosted service
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
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
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
POST (HTTP 1.1)
Content-Type: application/xml
More details about this http request here http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx
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.
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.
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;
}
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)