Managing Azure Hosted Services with the Service Management API

0
97
11 min read

 

Microsoft Windows Azure Development Cookbook

Microsoft Windows Azure Development Cookbook

Over 80 advanced recipes for developing scalable services with the Windows Azure platform

        Read more about this book      

(For more resources on this subject, see here.)

Introduction

The Windows Azure Portal provides a convenient and easy-to-use way of managing the hosted services and storage account in a Windows Azure subscription, as well as any deployments into these hosted services. The Windows Azure Service Management REST API provides a programmatic way of managing the hosted services and storage accounts in a Windows Azure subscription, as well as any deployments into these hosted services. These techniques are complementary and, indeed, it is possible to use the Service Management API to develop an application that provides nearly all the features of the Windows Azure Portal.

The Service Management API provides almost complete control over the hosted services and storage accounts contained in a Windows Azure subscription. All operations using this API must be authenticated using an X.509 management certificate. We see how to do this in the Authenticating against the Windows Azure Service Management REST API recipe in Controlling Access in the Windows Azure Platform.

In Windows Azure, a hosted service is an administrative and security boundary for an application. A hosted service specifies a name for the application, as well as specifying a Windows Azure datacenter or affinity group into which the application is deployed. In the Creating a Windows Azure hosted service recipe, we see how to use the Service Management API to create a hosted service.

A hosted service has no features or functions until an application is deployed into it. An application is deployed by specifying a deployment slot, either production or staging, and by providing the application package containing the code, as well as the service configuration file used to configure the application. We see how to do this using the Service Management API in the Deploying an application into a hosted service recipe.

Once an application has been deployed, it probably has to be upgraded occasionally. This requires the provision of a new application package and service configuration file. We see how to do this using the Service Management API in the Upgrading an application deployed to a hosted service recipe.

A hosted service has various properties defining it as do the applications deployed into it. There could, after all, be separate applications deployed into each of the production and staging slots. In the Retrieving the properties of a hosted service recipe, we see how to use the Service Management API to get these properties.

An application deployed as a hosted service in Windows Azure can use the Service Management API to modify itself while running. Specifically, an application can autoscale by varying the number of role instances to match anticipated demand. We see how to do this in the Autoscaling with the Windows Azure Service Management REST API recipe.

We can use the Service Management API to develop our own management applications. Alternatively, we can use one of the PowerShell cmdlets libraries that have already been developed using the API. Both the Windows Azure team and Cerebrata have developed such libraries. We see how to use them in the Using the Windows Azure Platform PowerShell Cmdlets recipe.

Creating a Windows Azure hosted service

A hosted service is the administrative and security boundary for an application deployed to Windows Azure. The hosted service specifies the service name, a label, and either the Windows Azure datacenter location or the affinity group into which the application is to be deployed. These cannot be changed once the hosted service is created. The service name is the subdomain under cloudapp.net used by the application, and the label is a humanreadable name used to identify the hosted service on the Windows Azure Portal.

The Windows Azure Service Management REST API exposes a create hosted service operation. The REST endpoint for the create hosted service operation specifies the subscription ID under which the hosted service is to be created. The request requires a payload comprising an XML document containing the properties needed to define the hosted service, as well as various optional properties. The service name provided must be unique across all hosted services in Windows Azure, so there is a possibility that a valid create hosted service operation will fail with a 409 Conflict error if the provided service name is already in use. As the create hosted service operation is asynchronous, the response contains a request ID that can be passed into a get operation status operation to check the current status of the operation.

In this recipe, we will learn how to use the Service Management API to create a Windows Azure hosted service.

Getting ready

The recipes in this article use the ServiceManagementOperation utility class to invoke operations against the Windows Azure Service Management REST API. We implement this class as follows:

  1. Add a class named ServiceManagementOperation to the project.
  2. Add the following assembly reference to the project:

    System.Xml.Linq.dll

  3. Add the following using statements to the top of the class file:

    using System.Security.Cryptography.X509Certificates;
    using System.Net;
    using System.Xml.Linq;
    using System.IO;

  4. Add the following private members to the class:

    String thumbprint;
    String versionId = "2011-02-25";

  5. Add the following constructor to the class:

    public ServiceManagementOperation(String thumbprint)
    {
    this.thumbprint = thumbprint;
    }

  6. Add the following method, retrieving an X.509 certificate from the certificate store, to the class:

    private X509Certificate2 GetX509Certificate2(
    String thumbprint)
    {
    X509Certificate2 x509Certificate2 = null;
    X509Store store =
    new X509Store("My", StoreLocation.LocalMachine);
    try
    {
    store.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection x509Certificate2Collection =
    store.Certificates.Find(
    X509FindType.FindByThumbprint, thumbprint, false);
    x509Certificate2 = x509Certificate2Collection[0];
    }
    finally
    {
    store.Close();
    }
    return x509Certificate2;
    }

  7. Add the following method, creating an HttpWebRequest, to the class:

    private HttpWebRequest CreateHttpWebRequest(
    Uri uri, String httpWebRequestMethod)
    {
    X509Certificate2 x509Certificate2 =
    GetX509Certificate2(thumbprint);
    HttpWebRequest httpWebRequest =
    (HttpWebRequest)HttpWebRequest.Create(uri);
    httpWebRequest.Method = httpWebRequestMethod;
    httpWebRequest.Headers.Add("x-ms-version", versionId);
    httpWebRequest.ClientCertificates.Add(x509Certificate2);
    httpWebRequest.ContentType = "application/xml";
    return httpWebRequest;
    }

  8. Add the following method, invoking a GET operation on the Service Management API, to the class:

    public XDocument Invoke(String uri)
    {
    XDocument responsePayload;
    Uri operationUri = new Uri(uri);
    HttpWebRequest httpWebRequest =
    CreateHttpWebRequest(operationUri, "GET");
    using (HttpWebResponse response =
    (HttpWebResponse)httpWebRequest.GetResponse())
    {
    Stream responseStream = response.GetResponseStream();
    responsePayload = XDocument.Load(responseStream);
    }
    return responsePayload;
    }

  9. Add the following method, invoking a POST operation on the Service Management API, to the class:

    public String Invoke(String uri, XDocument payload)
    {
    Uri operationUri = new Uri(uri);
    HttpWebRequest httpWebRequest =
    CreateHttpWebRequest(operationUri, "POST");
    using (Stream requestStream =
    httpWebRequest.GetRequestStream())
    {
    using (StreamWriter streamWriter =
    new StreamWriter(requestStream,
    System.Text.UTF8Encoding.UTF8))
    {
    payload.Save(streamWriter,
    SaveOptions.DisableFormatting);
    }
    }

    String requestId;
    using (HttpWebResponse response =
    (HttpWebResponse)httpWebRequest.GetResponse())
    {
    requestId = response.Headers["x-ms-request-id"];
    }
    return requestId;
    }

How it works…

In steps 1 through 3, we set up the class. In step 4, we add a version ID for service management operations. Note that Microsoft periodically releases new operations for which it provides a new version ID, which is usually applicable for operations added earlier. In step 4, we also add a private member for the X.509 certificate thumbprint that we initialize in the constructor we add in step 5.

In step 6, we open the Personal (My) certificate store on the local machine level and retrieve an X.509 certificate identified by thumbprint. If necessary, we can specify the current user level, instead of the local machine level, by using StoreLocation.CurrentUser instead of StoreLocation.LocalMachine.

In step 7, we create an HttpWebRequest with the desired HTTP method type, and add the X.509 certificate to it. We also add various headers including the required x-ms-version.

In step 8, we invoke a GET request against the Service Management API and load the response into an XML document which we then return. In step 9, we write an XML document, containing the payload, into the request stream for an HttpWebRequest and then invoke a POST request against the Service Management API. We extract the request ID from the response and return it.

How to do it…

We are now going to construct the payload required for the create hosted service operation, and then use it when we invoke the operation against the Windows Azure Service Management REST API. We do this as follows:

  1. Add a new class named CreateHostedServiceExample to the WPF project.
  2. If necessary, add the following assembly reference to the project:

    System.Xml.Linq.dll

  3. Add the following using statement to the top of the class file:

    using System.Xml.Linq;

  4. Add the following private members to the class:

    XNamespace wa =
    "http://schemas.microsoft.com/windowsazure";
    String createHostedServiceFormat =
    "https://management.core.windows.net/{0}/services/hostedservices";

  5. Add the following method, creating a base-64 encoded string, to the class:

    private String ConvertToBase64String(String value)
    {
    Byte[] bytes = System.Text.Encoding.UTF8.GetBytes(value);
    String base64String = Convert.ToBase64String(bytes);
    return base64String;
    }

  6. Add the following method, creating the payload, to the class:

    private XDocument CreatePayload(
    String serviceName, String label, String description,
    String location, String affinityGroup)
    {
    String base64LabelName = ConvertToBase64String(label);

    XElement xServiceName =
    new XElement(wa + "ServiceName", serviceName);
    XElement xLabel =
    new XElement(wa + "Label", base64LabelName);
    XElement xDescription =
    new XElement(wa + "Description", description);
    XElement xLocation =
    new XElement(wa + "Location", location);
    XElement xAffinityGroup =
    new XElement(wa + "AffinityGroup", affinityGroup);
    XElement createHostedService =
    new XElement(wa +"CreateHostedService");

    createHostedService.Add(xServiceName);
    createHostedService.Add(xLabel);
    createHostedService.Add(xDescription);
    createHostedService.Add(xLocation);
    //createHostedService.Add(xAffinityGroup);
    XDocument payload = new XDocument();
    payload.Add(createHostedService);
    payload.Declaration =
    new XDeclaration("1.0", "UTF-8", "no");
    return payload;
    }

  7. Add the following method, invoking the create hosted service operation, to the class:

    private String CreateHostedService(String subscriptionId,
    String thumbprint, String serviceName, String label,
    String description, String location, String affinityGroup)
    {
    String uri =
    String.Format(createHostedServiceFormat, subscriptionId);

    XDocument payload = CreatePayload(serviceName, label,
    description, location, affinityGroup);
    ServiceManagementOperation operation =
    new ServiceManagementOperation(thumbprint);
    String requestId = operation.Invoke(uri, payload);
    return requestId;
    }

  8. Add the following method, invoking the methods added earlier, to the class:

    public static void UseCreateHostedServiceExample()
    {
    String subscriptionId = "{SUBSCRIPTION_ID}";
    String thumbprint = "{THUMBPRINT}";
    String serviceName = "{SERVICE_NAME}";
    String label = "{LABEL}";
    String description = "Newly created service";
    String location = "{LOCATION}";
    String affinityGroup = "{AFFINITY_GROUP}";
    CreateHostedServiceExample example =
    new CreateHostedServiceExample();
    String requestId = example.CreateHostedService(
    subscriptionId, thumbprint, serviceName, label,
    description, location, affinityGroup);
    }

How it works…

In steps 1 through 3, we set up the class. In step 4, we add private members to define the XML namespace used in creating the payload and the String format used in generating the endpoint for the create hosted service operation. In step 5, we add a helper method to create a base-64 encoded copy of a String.

We create the payload in step 6 by creating an XElement instance for each of the required and optional properties, as well as the root element. We add each of these elements to the root element and then add this to an XML document. Note that we do not add an AffinityGroup element because we provide a Location element and only one of them should be provided.

In step 7, we use the ServiceManagementOperation utility class , described in the Getting ready section, to invoke the create hosted service operation on the Service Management API. The Invoke() method creates an HttpWebRequest, adds the required X.509 certificate and the payload, and then sends the request to the create hosted services endpoint. It then parses the response to retrieve the request ID which can be used to check the status of the asynchronous create hosted services operation.

In step 8, we add a method that invokes the methods added earlier. We need to provide the subscription ID for the Windows Azure subscription, a globally unique service name for the hosted service, and a label used to identify the hosted service in the Windows Azure Portal. The location must be one of the official location names for a Windows Azure datacenter, such as North Central US. Alternatively, we can provide the GUID identifier of an existing affinity group and swap the commenting out in the code, adding the Location and AffinityGroup elements in step 6. We see how to retrieve the list of locations and affinity groups in the Locations and affinity groups section of this recipe.

There’s more…

Each Windows Azure subscription can create six hosted services. This is a soft limit that can be raised by requesting a quota increase from Windows Azure Support at the following URL:

http://www.microsoft.com/windowsazure/support/

There are also soft limits on the number of cores per subscription (20) and the number of Windows Azure storage accounts per subscription (5). These limits can also be increased by request to Windows Azure Support.

Locations and affinity groups

The list of locations and affinity groups can be retrieved using the list locations and list affinity groups operations respectively in the Service Management API. We see how to do this in the Using the Windows Azure Platform PowerShell Cmdlets recipe.

As of this writing, the locations are:

  • Anywhere US
  • South Central US
  • North Central US
  • Anywhere Europe
  • North Europe
  • West Europe
  • Anywhere Asia
  • Southeast Asia
  • East Asia

The affinity groups are specific to a subscription.

LEAVE A REPLY

Please enter your comment!
Please enter your name here