Service Management API in Windows Azure

The Windows Azure Service portal is the standard way to manage Azure Services and Storage. However, Microsoft has released a Service Management API which exposes to developers nearly all the functionality provided on the Azure Service portal. The Service Management API can be used to automate many of the tasks that would require human intervention on the portal. It supports the entire Azure Service lifecycle of deployment, configuration, staging, suspension and deletion of Azure Services.

Microsoft has released through CodePlex the Windows Azure Service Management CmdLets that use the Service Management API to administer Azure Services and Storage. Ryan Dunn introduces them here on his blog.

UPDATE 8/11/2011 – Packt Publishing has made available a free download of the chapter in my book, Microsoft Windows Azure Development Cookbook, that covers the Windows Azure Service Management REST API. This sample chapter provides an alternative and more up-to-date discussion of the Service Management API than contained in this post.

UPDATE 5/22/2011 – I did a post on the SQL Azure Management API which is very similar to the Windows Azure Service Management API. That post is worth looking at because it shows how to use XDocument to load the response data from API operations.

Authentication

On the Azure Service portal, authentication is provided through Windows Live Id. In Azure Storage, authentication is supported through the use of Azure Storage account names and account keys. The Service Management API introduces another authentication method – X.509 v3 Certificates. These certificates can be self-signed since they are used only for private communication between an application using the Service Management API and the Azure Management Service. They can be created using IIS 7 or through using the makecert utility.

David Aiken has posted detailed instructions on using II7 to create the X.509 certificate. The following is an example use of makecert to generate a certificate:

makecert -r -pe -a sha1 -n “CN=Azure Service Management” -ss My
-len 2048  -sp “Microsoft Enhanced RSA and AES Cryptographic Provider” -sy 24 AzureServiceManagement.cer

This creates a self-signed (-r), 2048-bit certificate (-len) with subject name of Azure Service Management (-n), installs it in the Personal certificate store for the user (-ss My) and creates an output certificate file named AzureServiceManagement.cer in the current directory. Note that Azure places no restrictions on the subject name or the name of the output certificate file – the names used here are merely convenient in identifying the certificates in the store. The remaining parameters indicate that the certificate has an exportable private key (-pe), uses the SHA-1 algorithm (-a sha1), and is created using the Microsoft Enhanced RSA and AES Cryptographic Provider (sp) with provider type of 24 (-sy 24). (I’m not sure why the certificate needs an exportable private key since the private key must not be exported when the certificate is used for authentication with Azure Service Management.)

The makecert command above installs the certificate in the Personal certificate store for the user where it can be viewed in the certmgr.msc plug-in to mmc. It is located in the Personal/Certificates for the Local User. If necessary, it can be exported without the private key as a DER-encoded binary certificate (*.cer).

The (exported) certificate must be uploaded to the Azure Service portal and associated as an API certificate with the Azure Services account. An API certificate is associated with the account rather than a service so that it can be used to authenticate operations at the accounts level such as listing all the compute and storage services associated with the account. This can be used to mitigate the current problem where compute and storage services are associated with individual Windows Live Ids and that sharing the Windows Live Id among several developers may not be desirable from a security standpoint. A single account can have up to five API certificates associated with it and these could be shared with developers leaving confidential the Windows Live Id that owns the account. Note that API certificates have nothing to do with the certificates needed to provide secure communication between an Azure web role and someone accessing its website.

Applications using the Service Management API must send the certificate with every operation requested from the Azure Management Service. The certificate can be retrieved programmatically from the certificate store as follows:

private X509Certificate2 GetX509Certificate2(String subjectName)
{
X509Certificate2 x509Certificate2 = null;
X509Store store = new X509Store(“My”, StoreLocation.CurrentUser);
try
{
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection x509Certificate2Collection =
store.Certificates.Find(X509FindType.FindBySubjectName,
subjectName, false);
x509Certificate2 = x509Certificate2Collection[0];
}
finally
{
store.Close();
}
return x509Certificate2;
}

This opens the X509Store Personal store for the Current User and retrieves the first certificate with the specified subject name, Azure Service Management in the makecert example. The parameter value of My indicates the Personal Store. The false parameter to the Find() method indicates that the certificate chain is not tested for validity – since, being self-signed, the certificate is not trusted by default. Note the use of X509Certificate2 rather than X509Certificate. This is recommended by Microsoft since X509Certificate2 provides additional functionality over the older X509Certificate class.

The Service Management API is a RESTful API. Consequently, service management operations are invoked through raw HTTP web request calls. The API certificate is associated with the request as shown in the following code fragment:

private HttpWebRequest CreateHttpWebRequest(Uri uri,
String httpWebRequestMethod)
{
X509Certificate2 x509Certificate2 = GetX509Certificate2(
“Azure Service Management”);

HttpWebRequest httpWebRequest =
(HttpWebRequest)HttpWebRequest.Create(uri);
httpWebRequest.Method = httpWebRequestMethod;
httpWebRequest.Headers.Add(“x-ms-version”, “2009-10-01″);
httpWebRequest.ClientCertificates.Add(x509Certificate2);
httpWebRequest.ContentType = “application/xml”;

return httpWebRequest;
}

Note the use of the x-ms-version header to indicate that this operation is consistent with the 2009-10-01 version of the Service Management API.

RESTful Interface

The Service Management API is RESTful and is not a high-level .Net API like the recently released Storage Client API. It uses a simplified REST using only POSTs to update the Azure Service Manager, GETs to retrieve information from it, and a DELETE to delete a depoyment. The Service Management API uses POSTs even for a few operations, such as Change Deployment Configuration, where a PUT could have been used.

The operations are defined by the following:

  • URI
  • HTTP Method
  • Request Payload
  • Version

The specific service management resource being operated on is indicated by the URI. The HTTP method is either GET or POST depending on whether the service management operation is retrieving or submitting information to the Azure Management Service. POST operations include a request payload containing the information submitted to the Azure Management Service. The version of an operation is specified through an x-ms-version header submitted with the http request. The only value currently used for x-ms-version is 2009-10-01.

URI

Each resource accessible to the Service Management API has a unique service endpoint specified by a URI. The following shows the service endpoint for the staging deployment slot of a hosted service named whitespider for an account with a subscription Id of XY2XY2X5-5Y53-4772-9X6Y-X493YYX4757X:

https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y-X493YYX4757X/services/hostedservices/whitespider/deploymentslots/staging

The base URI for the Management Service  is:

https://management.core.windows.net

This can be compared with the base URIs for the Azure Storage Service which are respectively for blobs, queues and tables:

The Managed Service identifies the Azure Account by its subscription Id while Azure Storage uses the individual storage accounts created inside each Azure Account.

Distinct endpoints are documented for each of the service management resources: subscriptions, storage accounts hosted services, deployments, deployment slots, certificates, affinity and operations. Other than operations these all represent resources accessible through the Azure Service portal. Operations represent asynchronous operations invoked through the Service Management API. For example, the Create Deployment operation is invoked asynchronously because it is an operation that can take some time. The results of an asynchronous operation is discovered through a Get Operation operation.

Request Payload

Each operation that changes a service management resource must be accompanied through a POST and have an accompanying request payload. This is in the form of an XML document describing the required changes. The XML schema for the request payload is specific to each service management operation. For example, the request payload schema for the Create Deployment operation is:

<?xml version=”1.0″ encoding=”utf-8″?>
<CreateDeployment
xmlns=”http://schemas.microsoft.com/windowsazure”&gt;
<Name>deployment-name</Name>
<PackageUrl>package-url-in-blob-storage</PackageUrl>
<Label>base64-encoded-deployment-label</Label>
<Configuration>base64-encoded-configuration-file</Configuration>
</CreateDeployment>

The Create Deployment operation is invoked on an existing hosting service to create a new deployment for that service. The Name specifies a deployment name identifying this specific deployment among all others for this service and must be unique among these. It could be set to a Guid, for example. The PackageUrl specifies the URI for the blob containing the deployment package for this service. Since there is no way to provide a storage account name and key for this blob it must reside on an Azure Storage account belonging to the same Windows Live Id account as the service to be deployed. Label is base64-encoded string used as a label for the deployment on the Azure Service portal that could, for example, contain a version number. Configuration is a base-64 encoded version of the the Azure Service configuration file.

When an Azure Service is deployed through the Azure portal, locations for the service package and service configuration must be provided so they can be deployed. When the Service Management API is used, the service package must be pre-loaded into Azure Blob storage and the service configuration is provided through the Create Deployment operation.

Other Service Management API operations have different payload requests but the general idea remains the same. The payload request is a simple XML document where some of the data might be base-64 encoded. Note that the schema must be adhered to and, in particular, elements must appear in the documented order.

The following class is (for better or worse) a simple implementation of the IXmlSerializable to enable XML Serialization of the Create Deployment request payload:

[XmlRootAttribute(ElementName = "CreateDeployment", Namespace = "http://schemas.microsoft.com/windowsazure")]
public class WhiteSpiderServiceDeployment : IXmlSerializable
{
public WhiteSpiderServiceDeployment() { }
public String DeploymentName { get;    set; }
public Uri packageUri { get;    set; }
public String Configuration { get;    set; }
public String Label { get;    set; }

public XmlSchema GetSchema()
{
return null;
}

public void ReadXml(XmlReader xmlReader)
{
System.Text.ASCIIEncoding asciiEncoding =
new System.Text.ASCIIEncoding();

xmlReader.ReadStartElement();

DeploymentName = xmlReader.ReadElementContentAsString();
String deploymentSlot = xmlReader.ReadElementContentAsString();
String privateId = xmlReader.ReadElementContentAsString();

String status = xmlReader.ReadElementContentAsString();

String base64Label = xmlReader.ReadElementContentAsString();
Byte[] labelData = System.Convert.FromBase64String(base64Label);
Label = asciiEncoding.GetString(labelData);

String packageUriString = xmlReader.ReadElementContentAsString();

String base64Configuration =
xmlReader.ReadElementContentAsString();
Byte[] configurationData =
System.Convert.FromBase64String(base64Configuration);
Configuration = asciiEncoding.GetString(configurationData);
}

public void WriteXml(XmlWriter xmlWriter)
{
Byte[] configurationBytes =
System.Text.Encoding.UTF8.GetBytes(Configuration);
Byte[] labelBytes = System.Text.Encoding.UTF8.GetBytes(Label);

xmlWriter.WriteElementString(“Name”, DeploymentName);
xmlWriter.WriteElementString(“PackageUrl”,
packageUri.AbsoluteUri);
xmlWriter.WriteStartElement(“Label”);
xmlWriter.WriteBase64(labelBytes, 0, labelBytes.Count<Byte>());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement(“Configuration”);
xmlWriter.WriteBase64(configurationBytes, 0,
configurationBytes.Count<Byte>());
xmlWriter.WriteEndElement();
}
}

The XmlWriter.WriteBase64() method provides a convenient way of getting the Label and Configuration into base-64 form. The request payload can be added to a HTTP Web Request stream as follows:

public void WriteCreateDeploymentRequest(Stream stream)
{
String configuration = GetConfiguration();

AzureServiceCreateDeployment azureDeployment =
new AzureServiceCreateDeployment
{
DeploymentName = Guid.NewGuid().ToString(),
packageUri =new Uri(“https://nordwand.blob.core.windows.net/installs/WhiteSpiderCloudService.cspkg&#8221;),
Configuration = configuration,
Label = “White Spider v0.5″
};

XmlSerializer xmlSerializer = new XmlSerializer(
typeof(AzureServiceCreateDeployment));
xmlSerializer.Serialize(stream, azureDeployment);
}

GetConfiguration() simply returns the text of the Service configuration file. It could read it from a file or generate it programmatically in a similar manner to how the Create Deployment payload is generated.

There are many ways to achieve the above some of which would be much simpler if XMLWriter could emit the phrase encoding=”utf-8″ into a stream backed by a StringBuilder.

Service Management Operations

The Service Management API exposes almost all the functionality available on the Azure Service portal. However, it is not possible to use the Service Management API to create hosted services and storage accounts. Once a hosted service or a storage account has been created on the Azure Service portal it can be administered using the Service Management API.

The Service Management operations fall into the following groups distinguished by the service management resources they operate on:

  • Storage accounts
  • Hosted services
  • Deployments
  • Deployment slots
  • Certificates
  • Affinity groups
  • Operations

Storage account operations comprise: List Storage Accounts; Get Storage Account Properties; Get Storage Account Keys; Regenerate Storage Account Keys. Hosted service operations comprise: List Hosted Services; Get Hosted Service Properties; Swap Deployment (to/from staging and production). Deployment operations comprise: Get Deployment; Delete Deployment; Change Deployment Configuration; Update Deployment Status (to suspend or run); Upgrade Deployment; Walk Upgrade Domain (to perform an in-place upgrade). Deployment slot operations comprise all the deployment operations plus Create Deployment. Certificate operations comprise: List Certificates; Get Certificate; Add Certificate; Delete Certificate. Note that these certificates refer to server certificates for an Azure Service not the API certificates used to authenticate service management operations.Affinity Group operations comprise: List Affinity Groups; Get Affinity Group Properties. The only Operations operation is Get Operation Status which retrieves the status of an asynchronous operation.

Get Operation Status

Operations such as Create Deployment that effect a change in a service management resource are implemented asynchronously using an http POST. By asynchronously is meant that a correctly invoked operation respond immediately with with a status code of 202 (Accept) and an x-ms-request-id response header identifying the request. This request identifier can be passed into a subsequent invocation of a Get Operation Status operation which returns the current status of the operation.

Get Operation Status is a synchronous operation implemented as a GET with the following endpoint:

https://management.core.windows.net/<subscription-id>/operations/<request-id&gt;

Get Operation Status can be invoked as follows:

private String GetOperationStatus(String requestId)
{
String responseFromServer = string.Empty;
String uriString = String.Format(
“https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y-X493YYX4757X/operations/{0}”, requestId);
Uri uri = new Uri(uriString);
HttpWebRequest httpWebRequest =
CreateHttpWebRequest(uri, “GET”);
using (HttpWebResponse response =
(HttpWebResponse)httpWebRequest.GetResponse())
{
Stream dataStream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(dataStream))
{
responseFromServer = reader.ReadToEnd();
}
}
return responseFromServer;
}

The following is an example response from the server for a Get Operation Status operation for an in-progress Create Deployment operation:

<Operation xmlns=”http://schemas.microsoft.com/windowsazure&#8221;
xmlns:i=”http://www.w3.org/2001/XMLSchema-instance”&gt;
<ID>b47f9321-7423-4ed0-b221-ce42b8f8ee1b</ID>
<Status>InProgress</Status>
</Operation>

Get Operation Status include an error message in the response XML if an error has occurred.

List Storage Accounts & List Hosted Services

Two basic GET operations provided by the Service Management API are List Storage Accounts and List Hosted Services. The former lists the storage accounts associated with a specified subscription while the latter lists the hosted services associated with the subscription.

List Storage Accounts is a synchronous operation implemented as a GET from the following endpoint:

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

List Hosted Services is a synchronous operation implemented as a GET from the following endpoint:

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

The following shows a simple method that can be called to invoke either List Storage Accounts or List Hosted Services depending on the parameter passed in to the method:

enum ServiceType
{
Storage,
Hosted
}

private String ListServices(ServiceType serviceType)
{
String responseFromServer = string.Empty;
String serviceName =
serviceType == ServiceType.Storage ? “storage” : “hosted”;
String uriString =
String.Format(
“https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y-X493YYX4757X/services/{0}services, serviceName”);
Uri uri = new Uri(uriString);
HttpWebRequest httpWebRequest =
CreateHttpWebRequest(uri, “GET”);
using (HttpWebResponse response =
(HttpWebResponse)httpWebRequest.GetResponse())
{
Stream dataStream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(dataStream))
{
responseFromServer = reader.ReadToEnd();
}
}
return responseFromServer;
}

The following shows sample responses from List Storage Accounts and List Hosted Services respectively:

<StorageServices xmlns=”http://schemas.microsoft.com/windowsazure&#8221;
xmlns:i=”http://www.w3.org/2001/XMLSchema-instance”&gt;
<StorageService>
<Url>https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y-X493YYX4757X/services/storageservices/pizbadile</Url&gt;
<ServiceName>pizbadile</ServiceName>
</StorageService>
<StorageService>
<Url>https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y-X493YYX4757X/services/storageservices/cimagrande</Url&gt;
<ServiceName>cimagrande</ServiceName>
</StorageService>
</StorageServices>

<HostedServices xmlns=”http://schemas.microsoft.com/windowsazure&#8221;
xmlns:i=”http://www.w3.org/2001/XMLSchema-instance”&gt;
<HostedService>
<Url>https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y-X493YYX4757X/services/hostedservices/eiger</Url&gt;
<ServiceName>eiger</ServiceName>
</HostedService>
<HostedService>
<Url>https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y-X493YYX4757X/services/hostedservices/whitespider</Url&gt;
<ServiceName>whitespider</ServiceName>
</HostedService>
</HostedServices>

Create Deployment

Create Deployment deploys a service package and a service configuration to an empty deployment slot of an existing Azure Service. This deployment slot can be either Production or Staging. The service package must be stored already in a specified Azure Storage blob while the service configuration is supplied in the request body of the Create Deployment operation. Create Deployment is an asynchronous operation so should be used along with a Get Operation Status operation so that the progress of the Create Deployment can be tracked. Alternatively, a Get Deployment Status operation could be used but it would not provide the error messages resulting from the Create Deployment operation that Get Deployment Status might return.

Create Deployment is an asynchronous operation implemented as a POST to the following endpoint:

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

The Create Deployment operation can be invoked as follows:

private String CreateDeployment(String serviceName)
{
String requestId = String.Empty;
String uriString = String.Format(“https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y-X493YYX4757X/services/hostedservices/{0}/deploymentslots/staging, serviceName”);
Uri uri = new Uri(uriString);
HttpWebRequest httpWebRequest =
CreateHttpWebRequest(uri, “POST”);
using (Stream requestStream = httpWebRequest.GetRequestStream())
{
WriteCreateDeploymentRequest(requestStream);
}

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

return requestId;
}

This creates a deployment in Staging deployment slot. The WriteCreateDeploymentRequest() method inserts the XML document defining the deployment into the request payload. A version of WriteCreateDeploymentRequest() and a Create Deployment request payload are provided in the Request Payload section earlier in this post. The returned requestId  is used to identify this particular operation in a Get Operation Status operation.

Get Deployment

The Get Deployment operation retrieves the service configuration along with the status and various system properties of a specified deployment.

Get Deployment is a synchronous operation implemented as a GET from either of the following endpoints:

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

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

The following is an example of a Get Deployment operation that retrieves the deployment information for the Staging slot of a hosted service named whitespider:

private WhiteSpiderConfiguration GetDeployment(String serviceName)
{
WhiteSpiderConfiguration whiteSpiderConfiguration =
new WhiteSpiderConfiguration();

String uriString = String.Format(
https://management.core.windows.net/XY2XY2X5-5Y53-4772-
9X6Y-X493YYX4757X/services/hostedservices/{0}/deploymentslots/staging”, serviceName);
Uri uri = new Uri(uriString);
HttpWebRequest httpWebRequest =
CreateHttpWebRequest(uri, “GET”);
using (HttpWebResponse response =
(HttpWebResponse)httpWebRequest.GetResponse())
{
Stream dataStream = response.GetResponseStream();

using (StreamReader reader = new StreamReader(dataStream))
{
using (XmlReader xmlReader = XmlReader.Create(dataStream))
{
WhiteSpiderServiceDeployment azureServiceDeployment =
new WhiteSpiderServiceDeployment();
azureServiceDeployment.ReadXml(xmlReader);
whiteSpiderConfiguration = WhiteSpiderConfiguration.ReadXml(
azureServiceDeployment.Configuration);
}
}
}
return whiteSpiderConfiguration;
}

An example of the deployment information returned from the Get Deployment operation is:

<Deployment xmlns=”http://schemas.microsoft.com/windowsazure”
xmlns:i=”http://www.w3.org/2001/XMLSchema-instance”&gt;
<Name>411f406a-7343-43a0-863a-6d289de263ec</Name>
<DeploymentSlot>Staging</DeploymentSlot>
<PrivateID>2e71828182845904523536</PrivateID>
<Status>Suspended</Status>
<Label>UHJvc3Blcm8gdjAuNg==</Label>
<Url>http://2e71828182845904523536.cloudapp.net/</Url&gt;
<Configuration>base64-encoded version of the service configuration</Configuration>
<RoleInstanceList>
<RoleInstance>
<RoleName>WebRole1</RoleName>
<InstanceName>WebRole1_IN_0</InstanceName>
<InstanceStatus>Stopped</InstanceStatus>
</RoleInstance>
<RoleInstance>
<RoleName>WebRole1</RoleName>
<InstanceName>WebRole1_IN_1</InstanceName>
<InstanceStatus>Stopped</InstanceStatus>
</RoleInstance>
</RoleInstanceList>
<UpgradeDomainCount>1</UpgradeDomainCount>
</Deployment>

This deployment is currently Suspended and both its instances in the Stopped state.

WhiteSpiderConfiguration is a simple class representing the service configuration for the whitespider service. For demonstration purposes this service is in fact the service created by Visual Studio for a simple web role. This generated service configuration file comprises:

<?xml version=”1.0″?>
<ServiceConfiguration serviceName=”WhiteSpider”
xmlns=”http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration”&gt;
<Role name=”WebRole1″>
<Instances count=”1″ />
<ConfigurationSettings>
<Setting name=”DiagnosticsConnectionString”
value=”DefaultEndpointsProtocol=https;AccountName=pizbadile;AccountKey=abcdefghijklmnopqrstuvwxyz==” />
</ConfigurationSettings>
</Role>
</ServiceConfiguration>

WhiteSpiderConfiguration exposes as properties the service name, role name, instances count and DiagnosticsConnectionString from the service configuration as well as methods to read and write the XML for the service configuration. WhiteSpiderConfiguration is declared:

public class WhiteSpiderConfiguration
{
public WhiteSpiderConfiguration() { }
public String ServiceName { get; set; }
public String RoleName { get; set; }
public Int32 InstancesCount { get; set; }
public String DiagnosticsConnectionString { get; set; }

public static WhiteSpiderConfiguration ReadXml( String configuration)
{
WhiteSpiderConfiguration whiteSpiderConfiguration =
new WhiteSpiderConfiguration();
using (StringReader stringReader = new StringReader(configuration))
{
using (XmlReader xmlReader = XmlReader.Create(stringReader))
{
xmlReader.MoveToContent();

whiteSpiderConfiguration.ServiceName =
xmlReader["serviceName"];

xmlReader.ReadToFollowing(“Role”);
whiteSpiderConfiguration.RoleName = xmlReader["name"];

xmlReader.ReadToFollowing(“Setting”);
whiteSpiderConfiguration.DiagnosticsConnectionString =
xmlReader["value"];

xmlReader.ReadToFollowing(“Instances”);
String count = xmlReader["count"];
Int32 instancesCount;
Int32.TryParse( count, out instancesCount);
whiteSpiderConfiguration.InstancesCount = instancesCount;
}
}

return whiteSpiderConfiguration;
}

public String WriteXml()
{
String serviceConfigurationNamespace =
@”http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration&#8221;;

String configuration = String.Empty;
using (MemoryStream memoryStream = new MemoryStream())
{
using (XmlWriter xmlWriter =
XmlWriter.Create(memoryStream, null))
{
xmlWriter.WriteStartElement(
“ServiceConfiguration”, serviceConfigurationNamespace);
xmlWriter.WriteAttributeString(“serviceName”, ServiceName);
xmlWriter.WriteStartElement(“Role”);
xmlWriter.WriteAttributeString(“name”, RoleName);

xmlWriter.WriteStartElement(“Instances”);
xmlWriter.WriteAttributeString(
“count”, InstancesCount.ToString());
xmlWriter.WriteEndElement();

xmlWriter.WriteStartElement(“ConfigurationSettings”);
xmlWriter.WriteStartElement(“Setting”);
xmlWriter.WriteAttributeString(
“name”, “DiagnosticsConnectionString”);
xmlWriter.WriteAttributeString(
“value”, DiagnosticsConnectionString);
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
}

memoryStream.Seek(0, SeekOrigin.Begin);
using (StreamReader streamReader =
new StreamReader(memoryStream))
{
configuration = streamReader.ReadToEnd();
}
}
return configuration;
}
}

Change Deployment Configuration

The Change Deployment Configuration operation modifies a deployment in either the Staging or Production slot by uploading a new service configuration. This operation does not affect the service package.  Uses of this operation include modifying the numbers of running instances of the various roles in the deployment or changing the Azure Storage account keys associated with the deployed service.

Change Deployment Configuration is an asynchronous operation implemented as a POST to either of the following endpoints:

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

https://management.core.windows.net/<subscription-id>/services/hostedservices/<service-name>/deployments/<deployment-name>/?comp=config

The following is an example of a Change Deployment Configuration operation that changes the service configuration for the Staging slot of a hosted service named whitespider:

private String ChangeDeployment(
WhiteSpiderConfiguration configuration)
{
String requestId = String.Empty;
String uriString = “https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y493YYX4757X/services/hostedservices/whitespider/
deploymentslots/staging/?comp=config”;
Uri uri = new Uri(uriString);
HttpWebRequest httpWebRequest =
CreateHttpWebRequest(uri, “POST”);

using (Stream requestStream = httpWebRequest.GetRequestStream())
{
WriteChangeDeploymentRequest(requestStream, configuration);
}

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

WhiteSpiderConfiguration specifies the configuration.The returned requestId  is used to identify this particular operation in a Get Operation Status operation.

This ChangeDeployment() method may be used with the GetDeployment() and GetOperationStatus() methods defined earlier to modify the instance count of a deployed service to 3 as follows:

WhiteSpiderConfiguration whiteSpiderConfiguration =
GetDeployment(“whitespider”);
whiteSpiderConfiguration.InstancesCount = 3;
whiteSpiderConfiguration.ServiceName = Guid.NewGuid().ToString();
String requestId = ChangeDeployment(whiteSpiderConfiguration);
String operationStatus = GetOperationStatus(requestId);

This code fragment retrieves the current service configuration from the Azure Management Service as a WhiteSpiderConfiguration object, modifies it by setting the InstancesCount to 3 and setting a new ServiceName. Then it uploads the modified service configuration to the Azure Management Service and verifies the status of the deployment change. Somewhat surprisingly it all works as desired.

Delete Deployment

The Delete Deployment operation deletes a deployment from either the Staging or Production slot.

Delete Deployment is an asynchronous operation implemented as a POST to either of the following endpoints:

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

https://management.core.windows.net/<subscription-id>/services/hostedservices/<service-name>/deployments/<deployment-name&gt;

The following is an example of a Delete Deployment operation deleting a deployment from the Staging slot of a hosted service:

private String DeleteDeployment(String serviceName)
{
String requestId = String.Empty;
String uriString = String.Format(“https://management.core.windows.net/XY2XY2X5-5Y53-4772-9X6Y-X493YYX4757X/services/hostedservices/{0}/deploymentslots/staging”, serviceName);
Uri uri = new Uri(uriString);
HttpWebRequest httpWebRequest =
CreateHttpWebRequest(uri, “DELETE”);
using (HttpWebResponse response =
(HttpWebResponse)httpWebRequest.GetResponse())
{
requestId = response.Headers["x-ms-request-id"];
}
return requestId;
}

Thoughts

Hopefully, Microsoft will release a higher-level .NET API to supplement this low-level REST API.

UPDATE 2/10/2011: Reformatted code which got messed up during the automated migration to WordPress.

About these ads

About Neil Mackenzie

Azure Architect at Satory Global.
This entry was posted in Windows Azure and tagged , . Bookmark the permalink.

26 Responses to Service Management API in Windows Azure

  1. Fumio Mizobata says:

    very very useful!! thank you so much!!!!

  2. Pingback: Best Practices for Maximizing Scalability and Cost Effectiveness of Queue-Based Messaging Solutions on Windows Azure - Windows Server AppFabric Customer Advisory Team - Site Home - MSDN Blogs

  3. Pingback: AppFabric CAT | Best Practices for Maximizing Scalability and Cost Effectiveness of Queue-Based Messaging Solutions on Windows Azure

  4. Pingback: Ben Lobaugh Online » Generating Certificates for use with the Windows Azure Management API

  5. Pingback: AppFabric CAT | Leveraging the Windows Azure Management Service REST API to Create your Hosted Service Namespace

  6. Pingback: AppFabric CAT | Leveraging the Windows Azure Service Management REST API to Create your Hosted Service Namespace

  7. Naresh says:

    Hi, its very useful.
    I have create one web application to manage my Azure configuration using this concept. It works fine if I run it on default ports. It stops working if I create virtual directory and run.

    It gives me 403- forebidden error.
    By debugging I found that it does not find certificate from my local end while running on IIS VD. If I use exported certificate then again it gives me 403- forebidden error.

    Please help mme on this case.

  8. Naresh –

    It is not clear if this is a pure IIS issue or a Windows Azure web role issue. I know that it is possible to access the certificate store from the web role entry point code without using enhanced privileges – so assume, but am not sure, that it is possible from the IIS process itself. To access the certificate from a web role you do need to upload it twice – once as a Management Certificate used by the Service Management API, and once as a Service Certificate so that it is distributed to the role instances.

  9. Naresh Goradara says:

    Thanks Neil for your quick reply.

    01). As you said, “To access the certificate from a web role you do need to upload it twice – once as a Management Certificate used by the Service Management API, and once as a Service Certificate so that it is distributed to the role instances.”

    I have installed certificate on Windows Azure Management Certificate, but how to isnstall second one? Can you please give me some more details for this.

    And one more thing, that the same configuration- only one certificate – is working with Windows based application. So, it may be other issue.

    02). Under same environment thing are working once I start “Compute Emulator”, but he gives “The request was aborted: Could not create SSL/TLS secure channel.” error.

    Please give your ideas, where I am going wrong.

  10. You can follow the instructions here to associate the certificate to a service. You should probably look at the entire topic of How to Manage Service Certificates to get a better understanding of what to do.

  11. Naresh Goradara says:

    Hi Neil,

    I have follow all steps, but still facing same issue- “The request was aborted: Could not create SSL/TLS secure channel.”

    Pls give some idea on this.My code for this is given below:

    public void GetListHostServices1(String SubscriptionID, String CertificatePath)
    {
    string requestUrl = “https://management.core.windows.net/” + SubscriptionID + “/services/hostedservices”;

    string ReturnBody = string.Empty;
    WebResponse resp = null;
    try
    {
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
    NameValueCollection RequestHeaders = new NameValueCollection();
    RequestHeaders.Add(“x-ms-version”, x_ms_version);
    X509Certificate cert = X509Certificate.CreateFromCertFile(CertificatePath);
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUrl);
    request.Method = “GET”;
    request.ClientCertificates.Add(cert);
    request.KeepAlive = false;
    request.ProtocolVersion = HttpVersion.Version10;
    if (RequestHeaders != null)
    request.Headers.Add(RequestHeaders);
    resp = request.GetResponse();
    }
    catch (WebException webEx)
    {
    //ERROR: The request was aborted: Could not create SSL/TLS secure channel.” error.
    }
    catch (Exception excep)
    {

    }
    finally
    {
    if (resp != null) { resp.Close(); }
    resp = null;
    }
    }

  12. It is documented that you need to use HTTP version 1.1.

    • Naresh Goradara says:

      Still not working…. I have tried with SecurityProtocolType.Ssl3, TLS and without setting it. But not working… :(

  13. You should post your question on the Windows Azure forum.

  14. Pingback: SQL Azure Management REST API | Convective

  15. jag says:

    Iam using the following to update the instance count

    String requestId = String.Empty;
    String uriString = “https://management.core.windows.net/subscriptid/services/hostedservices/cygnusattacment/deployments/mydeploymentname/?comp=config”;
    Uri uri = new Uri(uriString);
    HttpWebRequest httpWebRequest = CreateHttpWebRequest(uri, “POST”);

    using (Stream requestStream = httpWebRequest.GetRequestStream())
    {
    WriteChangeDeploymentRequest(requestStream, configuration);
    }

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

    It throws up error in the using (HttpWebResponse response =
    (HttpWebResponse)httpWebRequest.GetResponse())..saying its a “400: bad request”.
    Tried various possibilities though no solution yet. Please point where i have gone bonkers…

  16. I usually use an endpoint similar the following:

    https://management.core.windows.net/SubscriptionId/services/hostedservices/ServiceName/deploymentslots/staging/?comp=config

    When I’ve run into problems it is usually in the construction of the XML payload, ensuring that things are in the proper sequence and in base-64 format where needed. I would run Fiddler to capture the request and verify that the payload is correct.

    • jag says:

      Hi Neil,

      I was using the same before and it did not work too…and here is the code that i used (from your msdn forum) for writeDeployement….
      public static void WriteChangeDeploymentRequest(Stream stream, WhiteSpiderConfiguration whiteSpiderConfiguration)
      {
      String configuration = whiteSpiderConfiguration.WriteXml();

      AzureServiceChangeConfiguration azureDeployment = new AzureServiceChangeConfiguration
      {
      Configuration = configuration,
      };

      XmlSerializer xmlSerializer = new XmlSerializer(typeof(AzureServiceChangeConfiguration));
      xmlSerializer.Serialize(stream, azureDeployment);
      }

  17. Were I doing this post now I would use XDocument throughout rather than using the XmlSerializer. The technique is similar to the one I used in the SQL Azure Management API post. You can navigate the XDocument tree and change the instance count.

  18. Jag –

    I’m sorry but I can’t spare the time to help further with this problem.

  19. jag says:

    hi Neil,

    Thanks for your help, sorted it out with the XDocument…will post the code here soon…I am enjoying your series of posts…

  20. Pingback: Best Practices for Maximizing Scalability and Cost Effectiveness of Queue-Based Messaging Solutions on Windows Azure | Windows Azure Customer Advisory Team (CAT)

  21. Pingback: Creating a Windows Azure hosted service | Convective

  22. Thayalan Sivapaleswararajah says:

    Thanks Neil. It is a very helpful article. I myself was able to try a sample web application to manage my Azure configuration by following your article. It works fine. However when it comes to api management including designing, publishing and it’s life cycle management, security & governance of artifacts is much more easier with WSO2 API Manager (http://wso2.com/products/api-manager/) as per my experience and straight forward too. Also WSO2 API Manager is 100% open source.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s