Freigeben über


Hosting Deployment Slots into Windows Azure – Where my slot is deployed?

by Néstor Guadarrama

 

Working with Azure Websites is always a learning path. Few days ago, a Customer required information about how to know where the deployment slots for an Azure websites are created. I’ve been working with deployment slots for a while, but I never realized if, when I’ve an standard Azure website and I create a staged deployment, this deployment also will be created in the same instance where my original website is already running or is created in another place. So, let’s find out!

In order to test this scenario, I created a basic ASP.NET form application called hrportal. Running locally, the web application looks like this:

HRPortalLocal.png

Figure 1. HRPortal Website running locally

I’ll create a new tab on my website called “Configuration”. This new tab will let me show information about website properties and how this website is hosted on Azure (hosting plans, availability, geographic location, etc.).

In order to get this information, I’ll be using the Management Libraries for .NET APIs. These libraries are so useful to handle administrative task through several .NET module extensions in an easy way. The Management Libraries for .NET include managed wrappers around the Microsoft Azure Service Management REST APIs. These libraries give .NET developers a client-side SDK written as Portable Class Libraries (PCL), so if you’re writing applications for desktop applications in .NET, Windows 8.1 Store applications, or Windows Phone 8 applications, you can automate the provisioning or management of Microsoft Azure assets. You can use the Management Libraries for .NET to write integration tests that provision environments in Microsoft Azure (and destroy them when your tests complete), enable Software-as-a-Service (SaaS) solutions to spin up new Web Sites or Cloud Services, or to get deep information about the running state of their assets.

 

FIRST STEP: GETTING THE LIBRARIES

For this project, I’ll use Visual Studio Ultimate 2013 Update 4. In order to get Management Libraries for .NET, you can retrieve it from Nuget, following next procedure:

· Right-click on “References”. Select “Manage Nuget Packages…”

manageNuget

Figure 2. “Manage Nuget Packages…” window

 

· Search online for “Microsoft Azure Management Libraries”. Install it.

manageNugetWindow

Figure 3. Getting Microsoft Azure Management Libraries from Nuget Management window.

· Once you already have installed libraries, you should see all Microsoft.Windows.Azure.* libraries references available:

References

Figure 4. After install libraries, you should have access to these references into your project.

At this point, you can start using the references inside your project.

Note: For this project, I just will use Microsoft.WindowsAzure.Management.WebSites and Microsoft.WindowsAzure.Management.WebSites.Models. If you just want to play with Azure Websites task, you can just install Microsoft Azure Web Sites Management Library.

ManagementLibrary

Figure 5. Microsoft Azure Web Sites Management Library

 

SECOND STEP: PLAYING WITH THE LIBRARIES – AUTHENTICATION AND AUTHORIZATION

Once you already have referenced Azure Management libraries, you need to understand a couple of things:

· In order to use the libraries and effectively, retrieve information from your Azure subscription, you need to authenticate yourself (as a valid user with access to your Azure account) and authorize this user for getting access to specific resources inside your subscription account.

· Azure authentication and authorization is based on X509 Certificates, so you'll use those to initially talk to your Azure instance.

On our website project, I opened web.config file and added three (3) application settings parameters to this configuration:

· SubscriptionID: GUID of Azure Subscription account.

· Certificate-Path: Path where I’ll put the .pfx file (certificate) that will let me authenticate with my Windows Azure portal.

· Certificate-Password: Password assigned to certificate file (.pfx) that let me authenticate with my Windows Azure portal.

webconfig

Figure 6. App Settings added to web.config file

 

Now, I will need to create an X509 certificate that let me connect with my Windows Azure account. I’ll use use MakeCert. The MakeCert tool creates an X.509 certificate, signed by the test root key or other specified key that binds your name to the public part of the key pair. The certificate is saved to a file, a system certificate store, or both. The tool is installed in the \Bin folder of the Microsoft Windows Software Development Kit (SDK) installation path. MakeCert syntax is pretty straight forward:

makecert.exe -r -pe -n CN={CertificateName} -ss my -sr localmachine -eku 1.3.6.1.5.5.7.3.2 -len 2048 -e 01/01/2016 {CertificateName}.cer

where {CertificateName} will be the name that you want to put to your CER file. For this exercise, I used:

selfsignedcert

Figure 7. Azure self-signed certificate created using MakeCert

Looking for certificate created on Certificates console (local computer), you should see the certificate already installed on Certificates’ root:

selfsignedcertInstalled

Figure 8. Azure self-signed certificate installed

Now, we will export the certificate to creating a PFX file required for our application. Using the Certificate’s console, I exported the certificate, including the private key and adding a strong security password for it:

ExportWizard

Figure 9. Certificate Export Wizard

With the PFX file exported, it’d be a good time to drop that into the web site. Drop the PFX file into the App_Data folder and modify web.config file with new location:

cert1

cert2

Figure 10. Certificate up and running

and finally, on Azure Web Management portal, I uploaded the CER file into “Management Certificates” (Settings):

CertUploaded

Figure 11. Certificate already uploaded into Azure Management portal

 

THIRD STEP: THE CODE TO RETRIEVE WEBSITE SETTINGS

Once CER file is already uploaded into my Azure account, is time to create some basic code in order to use both, Management Libraries for .NET and PFX file uploaded into my App_Data folder. First, adding the new ASP.NET web form named configuration.aspx. Then, I used WebSiteManagementClient namespace to connect my web application with my Azure account. The constructor requires a SubscriptionCloudCredentials type that can be defined creating a new CertificateCloudCredentials object and finally, CertificateCloudCredentials requires a X509Certificate2 type to create a secure connection using certificate credentials encrypted:

First, a public method to write information retrieved from Azure Website:

public void RetriveWebSiteConfiguration() {

try {

using (WebSiteManagementClient client = new WebSiteManagementClient(GetCredentials())) {

// Defining WebSiteListParameter to be retrieved by API

WebSiteListParameters webParameters = new WebSiteListParameters();

// LinQ to retrieve information about WebSpace where WebSite is located

WebSpacesListResponse.WebSpace _webspace = client.WebSpaces.List().Where

(lws=> lws.Name.Contains(

ConfigurationManager.AppSettings["WebSite"].ToString())).FirstOrDefault();

Using WebSiteManagementClient, I created a client object with information about credentials stored on my certificate, then, using this client, I created a WebSpacesListWebSitesResponse object to retrieve information about WebSpace property where my portal is running (by default):

##region WebSpace

if (_webspace != null) {

// In order to check how many websites are already grouped by an specific WebSpace, code is using

// WebSpacesListWebSitesResponse extension to retrieve all websites attached to a specific WebSpace.

// Because when a deployment stage is created for an specific Website, this stage is created in the

// WebSpace and ResourceGroup where the original Website is already hosted, once you retrieve websites

// annexed to a WebSpace, also you should retrieve the stage attached to its own Website (as a Child

// Resouce)

WebSpacesListWebSitesResponse _websitelist = client.WebSpaces.ListWebSites(

_webspace.Name, webParameters);

#region WebSiteList

if (_websitelist != null) {

foreach(WebSite _website in _websitelist) {

#region WebSite

if (_website != null) {

#region WriteWebSiteParameters

// Listing WebSpaces & WebSite configuration settings

WriteHistoryMessage("WebSpace(s):" + _webspace.Name.ToString(), string.Empty, string.Empty, string.Empty, string.Empty, RowType.SubHeader);

WriteHistoryMessage("", "Plan:", _webspace.Plan.ToString());

WriteHistoryMessage("", "", "Enabled Host Names: " + _website.EnabledHostNames.Count.ToString(), "");

foreach (string _hostname in _website.EnabledHostNames) {

WriteHistoryMessage("", "", "", _hostname.ToString());

}

#endregion

}

else {

WriteHistoryMessage("WebSite Error");

WriteHistoryMessage("", "Error message:", "The API management couldn't find configuration settings for this Web Site. Operation aborted.", "WebSpace count in 0", "", RowType.Error);

Trace.Write("The API management couldn't find configuration settings for this Web Site. Operation aborted.");

}

#endregion

}

}

else {

with WebSpace object created, I validated if I could retrieve information from WebSpace and then, I created a WebSite object for retrieving all information from my website running. Finally, I used some write helpers to write information retrieved from Azure account subscription for this site.

Method GetCredentials is a function that returns a SubscriptionCloudCredentials object. I used my subscription ID and the certificate retrieved using function GetCertificate():

private SubscriptionCloudCredentials GetCredentials(){

try {

return new CertificateCloudCredentials(

ConfigurationManager.AppSettings["SubscriptionID"].ToString(), GetCertificate());

}

catch (Exception ex)

{

WriteHistoryMessage("Certificate Cloud Credentials Error");

WriteHistoryMessage("Handled Exception:", ex.Message.ToString(), ex.Source.ToString(), ex.StackTrace.ToString(), string.Empty, RowType.Error);

Trace.Write("Handled Exception:" + ex.Message.ToString());

return null;

}

]

 

private X509Certificate2 GetCertificate() {

try {

// Path where certificate (.PFX file) is located

string _certPath = Server.MapPath(ConfigurationManager.AppSettings["Certificate-Path"]);

// Creating a new x509Certificate2 objecy with information about .PFX file and

//password stored on web.config file

var _x509Certificate = new X509Certificate2(_certPath,

ConfigurationManager.AppSettings["Certificate-Password"]);

// Returning new x509Certificate2

return _x509Certificate;

}

catch (Exception ex)

{

WriteHistoryMessage("Certificate Error");

WriteHistoryMessage("Handled Exception:", ex.Message.ToString(), ex.Source.ToString(), ex.StackTrace.ToString(), string.Empty, RowType.Error);

Trace.Write("Handled Exception:" + ex.Message.ToString());

return null;

}

 

With code already done, this is how it looks like:

InfoAzurePortal

Figure 12. Information retrieved from Azure account subscription for site “hrportal”

Notice that “Enabled Host Name” property retrieves actually a collection of WebSite objects, one for the main website “hrportal” and one for its own administrative console (Kudu).

 

FORTH STEP: ADDING A NEW DEPLOYMENT SLOT AND TEST!

So far, my project is up and running. Now, I’ll add a new deployment slot to my portal. From the Azure Management Portal, on the dashboard, I can add a new deployment slot called “Dev”:

DeploymentSlot

Figure 13. Adding a new deployment slot to “hrportal”

Once deployment slot is created, you should see it on your main portal, below your main website:

DevDeplSlot

Figure 14. Deployment slot “Dev” created under main “hrportal”

Now, the “moment of truth”. What happen if I run my portal again? Take a look:

webspace

Figure 15. “hrportal (Dev)” is already hosted in the same WebSpace

As you can see, once the deployment slot is created, it looks like another instance of the same Azure website (parent). Actually, the new deployment slot is created on the same WebSpace, same Region (in my case, South Central) and using the same web hosting plan. Everything fit perfectly!!

‘till next time!