Wednesday, November 2, 2011

Windows Azure Service Management API to deploy an application in Azure Hosted Service using c#

We had requirement to deploy azure cloud service on a button click of a website. The main hurdle was, client should not be required to use Azure Management Portal to deploy azure cloud service. In such case you can use Windows Azure Service Management API to perform administrative tasks like deploying an application, deleting a deployment etc on windows azure portal.
Following are the details how we can achieve this.
The size of cspkg file was bit large therefore I kept the cscfg and cspkg file both on blob storage. Hence package to be deployed on azure is present in your blob storage and you have public URL of cscfg and cspkg file.
Also make sure that the certificate you want to use is added in hosted service on azure portal and in your machine in “Personal” store as well as “Trusted Root Certification Authority”.

First of all add your subscription ID, azure account details, blob endpoint URL, certificate thumbprint, and certificate physical path to configuration file ServiceConfiguration.cscfg as shown –
<ConfigurationSettings>
<Setting name="AccountName" value="YourAccountName" />
      <Setting name="SharedKey" value="YourStorageKey" />           
<Setting name="SubscriptionId" value="YourSubscription ID" />     
      <Setting name="CertificatePassword" value="YourCertificatePassword " />
      <Setting name="CertificatePath" value="/Certificates/mycert.pfx" />
<Setting name="PackageFileURL" value="package file blob URL - https://YourAccountName.blob.core.windows.net/SampleApp.cspkg" />
<Setting name="ConfigFileURL" value="config file URL - https://YourAccountName.blob.core.windows.net/ServiceConfiguration.cscfg" />

</ConfigurationSettings>

<Certificates>
      <Certificate name="mycert" thumbprint="mycert thumbprint" thumbprintAlgorithm="sha1" />
    </Certificates>

Add reference of azure management API dll to your application. The DLL name is – Microsoft.Samples.Windows Azure.ServiceManagement.dll
To retrieve memory stream from blob write following method –
/// <summary>
/// Downloads the file from the blob to the given file path
/// </summary>
/// <param name="blobContainers">Container name</param>
/// <param name="filepath">Location where file to be downloaded</param>
/// <param name="blobName">Blob name</param>
public static MemoryStream GetBlobItem(BlobContainers blobContainer, MemoryStream ms, string blobName)
{
try
{
var container = GetContainer(blobContainer);

var blob = container.GetBlobReference(blobName);
blob.DownloadToStream(ms);
return ms;
}
catch (Exception ex)
{
       Throw ex;
}
}

Enum declaration –
public enum BlobContainers
{
/// <summary>
/// TODO: write here your blob container name which contains config and package files
/// </summary>
YourBlobContainerName
}

Following complete code will go in button click event. Now on button click event of your web site page read above configuration values as shown –
CertificatePath = RoleEnvironment.GetConfigurationSettingValue("CertificatePath").ToString();
CertificatePassword = RoleEnvironment.GetConfigurationSettingValue("CertificatePassword").ToString();
AccountName = RoleEnvironment.GetConfigurationSettingValue("AccountName");
SharedKey = RoleEnvironment.GetConfigurationSettingValue("SharedKey");
PackageFileURL = RoleEnvironment.GetConfigurationSettingValue("PackageFile");
ConfigFileURL = RoleEnvironment.GetConfigurationSettingValue("PackageFile");
SubscriptionId = RoleEnvironment.GetConfigurationSettingValue("SubscriptionId");


To deploy cspkg file in hosted service, you need to use cscfg fileand package file first –
//variables
string config = string.Empty;
string EndpointConfigurationName = "WindowsAzureEndPoint";
string hostedServiceName = “Hosted Service Name under which you want to deploy”;
string deploymentStatus = string.Empty;

//read configuration file details in memory stream

MemoryStream ms = new MemoryStream();
X509Certificate2 cert = new X509Certificate2(Server.MapPath(CertificatePath), CertificatePassword);
ms = GetBlobItem(BlobContainers.deploycontainer, ms, ConfigFileURL);
ms.Seek(0, SeekOrigin.Begin);
using (StreamReader reader = new StreamReader(ms))
{
config = reader.ReadToEnd();
}

//create service management object
X509Certificate2 certificate = new X509Certificate2(Server.MapPath(CertificatePath), CertificatePassword);
var serviceManagment = ServiceManagementHelper.CreateServiceManagementChannel(EndpointConfigurationName, certificate);


//assign deployment properties
CreateDeploymentInput deploymentInput = new CreateDeploymentInput();
deploymentInput.Configuration = ServiceManagementHelper.EncodeToBase64String(config);
deploymentInput.PackageUrl = new Uri(PackageFileURL);
deploymentInput.Name = NameOfYourChoice;
deploymentInput.Label = ServiceManagementHelper.EncodeToBase64String(hostedServiceName);

//upload deployment              
serviceManagment.CreateOrUpdateDeployment(SubscriptionId, hostedServiceName.ToLower(), "production", deploymentInput);

//this statement brings deployment in Suspended status, we need to make it running //therefore following code will be required

//retrieve hosted service which is under current deployment
HostedService hostedService = serviceManagment.GetHostedServiceWithDetails(SubscriptionId, hostedServiceName, true);

//wait till status changes to suspended and then update status to running
foreach (Deployment deployment in hostedService.Deployments)
{
while (deploymentStatus != "Suspended")
       {
              Thread.Sleep(20000);
HostedService tempHostedService = serviceManagment.GetHostedServiceWithDetails(SubscriptionId, hostedService.ServiceName, true);
              //retrieve current deployment to know its latest status
Deployment tempDeployment = tempHostedService.Deployments.Find(delegate(Deployment d) { return d.Name == deployment.Name; });
              deploymentStatus = tempDeployment.Status;
}

UpdateDeploymentStatusInput updateDeploymentStatus = new UpdateDeploymentStatusInput();
       updateDeploymentStatus.Status = "Running";
serviceManagment.UpdateDeploymentStatus(SubscriptionId, hostedService.ServiceName, deployment.Name, updateDeploymentStatus);

       while (deploymentStatus != "Running")
       {
              Thread.Sleep(10000);
HostedService tempHostedService = serviceManagment.GetHostedServiceWithDetails(SubscriptionId, hostedService.ServiceName, true);
              //retrieve current deployment to know its latest status
Deployment tempDeployment = tempHostedService.Deployments.Find(delegate(Deployment d) { return d.Name == deployment.Name; });
              deploymentStatus = tempDeployment.Status;
        }
}

That’s it. This is how you can use Azure Management API to deploy an application on windows azure hosted service.
Cheers…
Happy Coding!!!

1 comment: