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:
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…”
Figure 2. “Manage Nuget Packages…” window
· Search online for “Microsoft Azure Management Libraries”. Install it.
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:
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.
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.
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:
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:
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:
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:
Figure 10. Certificate up and running
and finally, on Azure Web Management portal, I uploaded the CER file into “Management Certificates” (Settings):
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:
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”:
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:
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:
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!