Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++

How to use the preview of the new Azure Management APIs, SDK 2.2

4.67/5 (2 votes)
7 Nov 2013CPOL7 min read 15.9K  
How to use the preview of the new Azure Management APIs, SDK 2.2.

A few days ago, the new Azure SDK 2.2 was announced by Scott Guthrie. Jeff Wilcox is currently working on the Azure Team and he is working on the code for the new managed management API, which is still in preview. Let me show you how easy it is to use this API. Have fun!

Downloading and compiling the code

First of all I downloaded the current Azure-SDK source from GitHub.  After the download you open the solution from within the  libraries folder. Visual Studio will not build the solution, until you restore the NuGet packages used in the solution.

Installing the new management API using NuGet

If you don’t want to use the latest sources, you can save some time and install the management API using NuGet:

C#
Install-Package Microsoft.WindowsAzure.Management.Libraries -IncludePrerelease

If you are not familiar with NuGet, you can learn how to use it here: NuGet Overview

Creating a new Azure Management Certificate

To be able to use the management API, you need to create a management certificate. The certificate is used to establish a secure connection to your Azure subscription and to identify you. Here is how the management certificate is created using makecert (It is part of the Windows SDK. Download it here):

C#
makecert -r -pe -a sha1 -n "CN=YOURCN" -ss my -len 2048 -sp "Microsoft Enhanced RSA and AES Crypt
ographic Provider" -sy 24 ManagementTestCert.cer

After you have created the certificate, you need to upload the .CER file to Azure. Login to the portal and click on Settings => Certificates. You will find the upload button in the bottom center of the screen:

portalUploadCert

Export the certificate containing the private key using certmgr on your pc. Open a command prompt with administrative rights (Run as administrator) and execute certmgr:

certmgr

Select the certificate you created recently, and click on “Export” to start the wizard. Click next, choose “Yes, export the private key”, click next, click next, tick the password box and enter a SOLID password here. Another tip: Save that exported file in a save place, even if you have given this thing a password! This is the key to all of your Azure services! Click next and save the file. Give it the .pfx extension. Click next and again next and finish the wizard.

Create a sample application

Since the new management API is a PCL, you can use it  with Silverlight, .NET in general, Windows Phone and Windows 8. So it is you choice which kind of project to use. For quick testing I prefer WPF.

Add a folder to your project and add the certificate

Add a new folder to your project, and name it something like “Certificates”. Right click the folder and choose to add an existing item. Browse to the folder where you have saved the .pfx file and add it to the certificates folder. Once you have done that, right click the certificate file, choose “properties” and set the build action to “Content” and copy to output directory to “Copy always”.

Loading the certificate from your project folder

To be able to create a new CertificateCloudCredentials instance, we need to pass a instance of the X509Certificate2 class. Add the following using statement to your code:

C#
using System.Security.Cryptography.X509Certificates;

We use constructor overload 8 of 13 of the X509Certificate2 class to pass a path and a password to the constructor. The path is a relative path to the certificate, residing in the certificates folder you created previously and the password is the one you used to secure the certificate and private key (the .pfx file) when you exported the certificate using certmgr.

C#
//Create a new instance of the X509 certificate
X509Certificate2 cert = new X509Certificate2(
  @"Certificates\YOUR CERTIFICATE FILE NAME","YOUR PASSWORD");

//Pass your subscription id and the certificate to the CertificateCloudCredentials class constructor
CertificateCloudCredentials creds = new CertificateCloudCredentials(
  "YOUR AZURE SUBSCRIPTION ID", cert);

Creating the management client

Another piece of information, besides the certificate is needed, to create an instance of the ManagmentClient class. You need the id of you Windows Azure subscription. You can get this information from the portal. Just click on settings, and copy the subscription id you want to use for testing.

A word of warning: Please consider, that the management API is very powerful and that you could  accidentally delete existing services or generate additional costs creating new services!

Ok. With that said and all the other things in place, you can create an instance of the management client. Since the client implements the IDisposable interface, it can be instantiated from within a using-statement:

C#
using (ManagementClient client = CloudContext.Clients.CreateManagementClient(creds))
{
    //Just listing the availabe manamgent certificates
    foreach (var manCert in await client.ManagementCertificates.ListAsync())
    {
        await AddOutput(string.Format("Cert Thumbprint:{0}," + 
              " Cert Created:{1}", manCert.Thumbprint, manCert.Created));
    }

    await AddOutput("Performed operations since 10/01/2013.....");
    await AddOutput("////////////////////////");

    var utcStart = new DateTime(2013, 10, 01, 0, 0, 0).ToUniversalTime();

    //Now list the operations since 10/01/2013
    var operations = await client.Subscriptions.ListOperationsAsync(
        new SubscriptionListOperationsParameters() { StartTime = utcStart, EndTime = DateTime.UtcNow });

    foreach (var op in operations.SubscriptionOperations)
    {
        await AddOutput(string.Format("Operation name:{0}, " + 
          "Operation id:{1}", op.OperationName, op.OperationId));
    }

    await AddOutput("Affinity groups and their locations.....");
    await AddOutput("////////////////////////");

    //List the available affinity groups
    foreach (var ag in await client.AffinityGroups.ListAsync())
    {
        await AddOutput(string.Format("Affiniy group name:{0}, Location:{1}", ag.Name, ag.Location));
    }
}

Now we are ready to explore the fresh Management API!

The logic behind the API

How to use the API, if there is no documentation (or very little) ? Well, in this case Jeff has done excellent work, creating a very simple to use logic, so that you can figure out on how to use the API very easily.  Just open the Object Explorer in Visual Studio and  expand all the management assemblies like I did:

apilogic1

If you take a closer look, for example at the Microsoft.WindowsAzure.Management.Compute assembly and the src\NetworkManagement assembly, you can see, that there is always a class that ends with “…Client” . These classes are instantiated using the static CloudContext.Clients.[THE CLIENT YOU NEED] …Client methods and passing the cloud credentials previously created. The pattern used here is called Factory pattern. I suggest to read through the source and learn how to develop a clean API.

apilogic2

The ManagemetClient class

This is the class with the base functions covered. You can perform the following operations:

  • Create, Delete and List Affinity Groups
  • Create, Delete and List management-certificates
  • List Locations, and the available services from within those locations, read the locations display names and names
  • List the operation’s that have been performed on a subscription within a specific timeframe
  • Register resources with your subscriptions

In this short snippet I will show you how to list management certificates, the last operations performed within a month and the affinity groups in your subscription:

C#
using (ManagementClient client = CloudContext.Clients.CreateManagementClient(creds))
{
    //Just listing the availabe manamgent certificates
    foreach (var manCert in await client.ManagementCertificates.ListAsync())
    {
        await AddOutput(string.Format(
          "Cert Thumbprint:{0}, Cert Created:{1}", manCert.Thumbprint, manCert.Created));
    }

    await AddOutput("Performed operations since 10/01/2013.....");
    await AddOutput("////////////////////////");

    var utcStart = new DateTime(2013, 10, 01, 0, 0, 0).ToUniversalTime();

    //Now list the operations since 10/01/2013
    var operations = await client.Subscriptions.ListOperationsAsync(
        new SubscriptionListOperationsParameters() { StartTime = utcStart, EndTime = DateTime.UtcNow });

    foreach (var op in operations.SubscriptionOperations)
    {
        await AddOutput(string.Format("Operation name:{0}, Operation id:{1}", 
              op.OperationName, op.OperationId));
    }

    await AddOutput("Affinity groups and their locations.....");
    await AddOutput("////////////////////////");

    //List the available affinity groups
    foreach (var ag in await client.AffinityGroups.ListAsync())
    {
        await AddOutput(string.Format("Affiniy group name:{0}," + 
              " Location:{1}", ag.Name, ag.Location));
    }
}

Before any operation can start, we need to load the management certificate, and create the CertificateCloudCredentials. The next step is to create an instance of the ManagementClient class.

In the next few lines you can see, that I am calling the ListAsync method, every time I need to list entries, like certificates, SubscriptionOperations or AffinityGroups.

To list the SubscriptionOperations, it is necessary to pass an instance of the SubscriptionListOperationsParameters class to the ListOperationsAsync method of the Subscriptions.ListOperationsAsync method.

To do that, we define the start and the end-date of the timespan to filter the amount of the operations returned. The time values passed need to be UTC values to avoid time-zone related quirks.

The StorageManagementClient class

This class allows you to manage everything related to storage within your Windows Azure subscription. You can perform the following operations:

  • Create storage accounts
  • List the available storage accounts and their system properties
  • Delete storage accounts
  • Check the availability of a storage account name, that you want to create
  • Get the primary and secondary access keys for a specific storage account
  • Re-generate the primary or secondary access key
  • Update label and description of the storage account
  • Enable or disable geo-replication for a storage account

Well, that’s a bunch of stuff that can be done. Let’s see now how that works.

C#
using (StorageManagementClient client = CloudContext.Clients.CreateStorageManagementClient(creds))
{
    await AddOutput("Available storage accounts.....");
    await AddOutput("////////////////////////");
    //Listing the storage accounts
    foreach (var storageAccount in await client.StorageAccounts.ListAsync())
    {
        await AddOutput(string.Format("Storage account name:{0}", storageAccount.ServiceName));

        #region Storage Account properties

        //Now list the properties of this storage account
        await AddOutput(string.Format(
          "Properties for storage account {0}:", storageAccount.ServiceName));

        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Affinity Group:", storageAccount.Properties.AffinityGroup));
        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Description:", storageAccount.Properties.Description));

        await AddOutput(string.Format("Endpoint properties for each endpoint " + 
              "(part of properties) for storage account {0}:", storageAccount.ServiceName));

        foreach (var ep in storageAccount.Properties.Endpoints)
        {
            //Endpoint properties
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Absolute Path", ep.AbsolutePath));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Absolute URI", ep.AbsoluteUri));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "DNS safehost", ep.DnsSafeHost));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Escaped Uri fragment", ep.Fragment));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Host", ep.Host));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Hostname type", ep.HostNameType));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Is absolute Uri", ep.IsAbsoluteUri));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Is absolute Uri", ep.IsAbsoluteUri));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Is default port", ep.IsDefaultPort));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Is file", ep.IsFile));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Is loopback", ep.IsLoopback));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Is UNC", ep.IsUnc));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Is wellformed", ep.IsWellFormedOriginalString()));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Local Path", ep.LocalPath));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Original string", ep.OriginalString));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Path and query", ep.PathAndQuery));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Port", ep.Port));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Query", ep.Query));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "Scheme", ep.Scheme));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "User escaped", ep.UserEscaped));
            await AddOutput(string.Format("Endpoint property name:{0}, Value:{1}", 
                            "User Info", ep.UserInfo));

            //Endpoint segments
            await AddOutput(string.Format("Segments, " + 
                  "for Endpoint {0} (part of properties):", ep.AbsolutePath));

            foreach (var segment in ep.Segments)
            {
                await AddOutput(string.Format("Segment {0}", segment));
            }
        }

        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Geo primary region:", storageAccount.Properties.GeoPrimaryRegion));
        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Geo replication enabled:", storageAccount.Properties.GeoReplicationEnabled));
        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Geo secondary region:", storageAccount.Properties.GeoSecondaryRegion));
        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Label", storageAccount.Properties.Label));
        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Last failover time", storageAccount.Properties.LastGeoFailoverTime));
        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Location", storageAccount.Properties.Location));
        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Status", storageAccount.Properties.Status));
        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Status of geo primary region", storageAccount.Properties.StatusOfGeoPrimaryRegion));
        await AddOutput(string.Format("Property name:{0}, Value:{1}", 
          "Status of geo secondary region", storageAccount.Properties.StatusOfGeoSecondaryRegion));

        await AddOutput(string.Format("Extended, for Endpoint {0} " + 
          "(part of properties):", storageAccount.ServiceName));
        //Extended properties
        foreach (var extProp in storageAccount.ExtendedProperties)
        {
            await AddOutput(string.Format("Extended proptery key: {0}, value: {1}", extProp.Key, extProp.Value));
        }

        #endregion
    }
    //Create a storage account, commented out, to avoid users creating this account
    //StorageAccountCreateParameters accountParameters = 
    //   new StorageAccountCreateParameters() {ServiceName = 
    //   "DataStore", Location = LocationNames.WestUS};
    //await client.StorageAccounts.CreateAsync(accountParameters);
    //Update storage account, commented out
    //StorageAccountUpdateParameters updParameters = 
    //  new StorageAccountUpdateParameters(){GeoReplicationEnabled = true,Label=Convert.ToBase64String(
    //  System.Text.Encoding.UTF8.GetBytes("NewName"))};
    //await  client.StorageAccounts.UpdateAsync("DataStore", updParameters);
    //Delete storage account, commented out!
    //await client.StorageAccounts.DeleteAsync("DataStore");
}

Like in the first sample, we request a specific type of client from the CloudContext. The first thing you see here, is the “foreaching” through every single storage account available in your subscription.

Then the properties and the extended properties of the storage account are requested. Operations like adding a new storage account, deleting and updating are commented out, to allow you to execute the example safely without messing up your subscription.

The WebSiteManagmentClient class

Websites on Windows Azure are very popular because of the easy deployment, and the wide range of API’s that can be used to develop cool websites. The Visual Studio tooling is excellent as well (like the rest for Azure tooling in VS). And lot’s of other good reasons!

Now let’s see what this management client has to offer:

  • Create websites
  • Delete websites
  • Create GIT repositories for deployment
  • Delete GIT repositories
  • Get website details
  • Generate new random publishing passwords
  • Get the configuration for a specific website
  • Get the historical usage metrics for a website
  • Get the current usage metrics for a website
  • Get the publish profile for a specific website
  • Restart a website
  • Update the website
  • Update the website configuration
  • Manage server farms

I will demonstrate you how to list webspaces and websites from within those webspaces and how to list all of their properties. Creating new websites, restarting and deleting depend on all those values. All repository operations as well.

C#
foreach (var webspace in await client.WebSpaces.ListAsync(token))
{
    await AddOutput(string.Format("Listing all properties for webspace {0}", webspace.Name));
    await AddOutput(string.Format("Property name:{0}, property value {1}", "Name", webspace.Name));
    await AddOutput(string.Format("Property name:{0}, property value {1}", 
                    "Availability state", webspace.AvailabilityState));
    await AddOutput(string.Format("Property name:{0}, property value {1}", 
                    "Current number of workers", webspace.CurrentNumberOfWorkers));
    await AddOutput(string.Format("Property name:{0}, property value {1}", 
                    "Current worker size", webspace.CurrentWorkerSize));
    await AddOutput(string.Format("Property name:{0}, property value {1}", 
                    "Geo location", webspace.GeoLocation));
    await AddOutput(string.Format("Property name:{0}, property value {1}", 
                    "Geo region", webspace.GeoRegion));
    await AddOutput(string.Format("Property name:{0}, property value {1}", "Plan", webspace.Plan));
    await AddOutput(string.Format("Property name:{0}, property value {1}", "Status", webspace.Status));
    await AddOutput(string.Format("Property name:{0}, property value {1}", 
                    "Subscription", webspace.Subscription));
    await AddOutput(string.Format("Property name:{0}, property value {1}", 
                    "Worker Size", webspace.WorkerSize));

    //Now get all the websites within the current webspace
    WebSiteListParameters websListParameters = new WebSiteListParameters();
    await AddOutput(string.Format("Listing available websites in webspace {0}", webspace.Name));
    foreach (var website in await client.WebSpaces.ListWebSitesAsync(webspace.Name, websListParameters, token))
    {
        await AddOutput(string.Format("Listing properties for website " + 
          "{0} in webspace {1}", website.Name, webspace.Name));

        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "Admin enabled", website.AdminEnabled));
        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "Availability state", website.AvailabilityState));
        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "ComputeMode", website.ComputeMode));
        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "Enabled", website.Enabled));

        await AddOutput(string.Format("Listing enabled hostnames " + 
          "(part of properties) for website {0} in webspace {1}", website.Name, webspace.Name));

        foreach (var enHostname in website.EnabledHostNames)
        {
            await AddOutput(string.Format("Enaabled hostname {0} for website {1}", enHostname, website.Name));
        }

        await AddOutput(string.Format("Listing  hostnames (part of properties) " + 
           "for website {0} in webspace {1}", website.Name, webspace.Name));

        foreach (var enHostname in website.HostNames)
        {
            await AddOutput(string.Format("Hostname {0} for website {1}", enHostname, website.Name));
        }

        await AddOutput(string.Format("Property name:{0}, property value {1}", "Owner", website.Owner));
        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "Repository Sitename", website.RepositorySiteName));
        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "Runtime availability state", website.RuntimeAvailabilityState));
        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "Server Farm", website.ServerFarm));
        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "Site mode", website.SiteMode));

        await AddOutput(string.Format(
          "Listing  site-properties (part of properties) for website {0} in webspace {1}", 
          website.Name, webspace.Name));
        await AddOutput(string.Format(
          "Listing AppSettings in  site-properties (part of properties) for website {0} in webspace {1}", 
          website.Name, webspace.Name));

        foreach (var appSettings in website.SiteProperties.AppSettings)
        {
            await AddOutput(string.Format("Key:{0}, value {1}", appSettings.Key, appSettings.Value));
        }

        await AddOutput(string.Format(
          "Listing metadata in  site-properties (part of properties) for website {0} in webspace {1}", 
          website.Name, webspace.Name));
        foreach (var metadata in website.SiteProperties.Metadata)
        {
            await AddOutput(string.Format("Key:{0}, value {1}", metadata.Key, metadata.Value));
        }

        await AddOutput(string.Format(
          "Listing properties (part of properties) for website {0} in webspace {1}", 
          website.Name, webspace.Name));

        foreach (var property in website.SiteProperties.Properties)
        {
            await AddOutput(string.Format("Key:{0}, value {1}", property.Key, property.Value));
        }

        await AddOutput(string.Format(
          "Listing ssl-certificates (part of properties) for website {0} in webspace {1}", 
          website.Name, webspace.Name));

        //Not listing all properties here. Like the ssl-blob, please investigate further 
        foreach (var sslcert in website.SslCertificates)
        {
            await AddOutput(string.Format("Cert property:{0}, property value {1}", 
                            "ExpirationDate", sslcert.ExpirationDate));
            await AddOutput(string.Format("Cert property:{0}, property value {1}", 
                            "Friendly name", sslcert.FriendlyName));
            await AddOutput(string.Format("Cert property:{0}, property value {1}", 
                            "SiteName", sslcert.SiteName));
            await AddOutput(string.Format("Cert property:{0}, property value {1}", 
                            "Subject name", sslcert.SubjectName));
            await AddOutput(string.Format("Cert property:{0}, property value {1}", 
                            "Thumbprint", sslcert.Thumbprint));
            await AddOutput(string.Format("Cert property:{0}, property value {1}", 
                            "Selflink uri", sslcert.SelfLinkUri.AbsoluteUri));
        }

        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "State", website.State));
        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "Uri", website.Uri.AbsolutePath));
        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "Usage State", website.UsageState));
        await AddOutput(string.Format("Property name:{0}, property value {1}", 
                        "Webspace", website.WebSpace));
    }
}

That should be enough to dive into the new Azure management API. I will write a second blog-post and cover the the other services, like the Scheduler (which seems to have two classes currently) as well.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)