Upgrading a Windows Azure Cloud Service with Azure Publisher

In this blog post I am presenting a video of how a 3 party plugin for my Azure Publisher is used to upgrade a Azure Cloud Service. The blog post goes in more details about the code used from a 3party providers viewpoint.

The video is 5mins and shows how it all works. Watch it and tweet this post if you like it.

The application uses Myget as distribution of plugins, meaning all nuget packages put in my feed will be installable from inside the application. More about that later.

In the video I run over the model from the 3party provider quickly and here I will go alittle more in details about it. What you saw in the video can be found here: https://gist.github.com/s093294/8336236. The model class can use properties and methods to make the application generate the wanted view and validaton from the user. The DisplayName attribute on model classes will be used for the name in the menues.

[DisplayName("CWAW - Stable")]
    public class CWAWStable : ICloudServiceDeploymentModel, ICanUpgrade

And here is an example for a property that is mapped directly to a user input view. The DeploymentSetting attribute maps the setting name to the property, meaning that when ever a user presses deploy or upgrade, a Cloud Service Configuration file will be generated and the setting will be included under settings. The Display Attribute is used for linking a Resource type or just setting the label for the user view. And Required simply adds validation that the user need to specify this, otherwise he gets a red ugly alert around the input. The writable = true means that when the user want to load the configuration from a already running cloud service, then this view input will be populated with the matching setting from the loaded configuration. This makes what I did in the video easy to do a upgrade of a webrole.

        [DeploymentSetting(SettingName = "Composite.WindowsAzure.WebRole.DeploymentName", Writable=true)]
        [Display(Name = "DeploymentName", Order = 1, ResourceType = typeof(Resources.Resource))]
        [Required]
        public string DeploymentName { get; set; }

In this example a more advanced way is also used for creating input fields for the connection string. In this model two identical connection strings was needed at two difference settingnames. Again two properties are used to create the input views but without the DeploymentSetting Attribute. Now we use a method together with the DeploymentSetting Attribute to generate two settings from these values. We saw above how the writable = true could be used to set values in the view when loading a configuration. This is ofcause not possible on a method so an additional method is needed as seen in the code. The arguments are a settingvalue for the settingname specified in the DeploymentSettingsConverter Attribute and a callback taking a string and a object. This callback can be used to set values on the view by giving the name of the models property that should be set and also the object to set. This way we can set both the name and key from this method.

        [Display(Name = "BlobStorageAccountName", ResourceType = typeof(Resources.Resource), Order = 2)]
        [Required]
        public string BlobStorageAccountName { get; set; }
 
        [Display(Name = "BlobStorageAccountKey", Description = "The shared access key for the blob storage", Order = 3, ResourceType = typeof(Resources.Resource))]
        [Required]
        [DataType(DataType.Password)]
        public string BlobStorageAccountKey { get; set; }
 
        [DeploymentSetting(SettingName = "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString")]
        [DeploymentSetting(SettingName = "Composite.WindowsAzure.WebRole.Storage.ConnectionString")]
        public string ConnectionString()
        {
            if (string.IsNullOrEmpty(BlobStorageAccountName) || string.IsNullOrEmpty(BlobStorageAccountKey))
                return null;
            return string.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", BlobStorageAccountName, BlobStorageAccountKey);
        }
 
        [DeploymentSettingsConverterAttribute( SettingName="Composite.WindowsAzure.WebRole.Storage.ConnectionString")]
        public void ParseConnectionString(string settingValue, Action<string,object> parser)
        {
 
            parser(GetName(() => BlobStorageAccountName), Regex.Match(settingValue, "AccountName=(.*);").Groups[1].Value);
            parser(GetName(() => BlobStorageAccountKey), Regex.Match(settingValue, "AccountKey=(.*)").Groups[1].Value);
           
        }

At the end when the user presses upgrade or deploy, the GetPackageUri is called with the generated Cloud Service Configuration file and the task of finding a Uri for the package is delegated to the 3 party provider. This way, clients do not need to download large cloud service packages and you can deploy any cloud services from any blob storage as long as the uri is given with a Shared Access Signature. I hope you liked it and I will be pushing for a release very soon and if you come back later this post was written for the alpha release, so a few changes might happen. I will ofcause update those here if anything changes.

Thanks Guys for reading.

Update 2014-01-14

Guessing some things will be more used then others and wanted an trying to make the models simpler I made a base model for a BlobStorage Connection String.

    public class BlobStorageConnectionString : WindowsAzureBlobStorageCredentional
    {
        
        [DeploymentSettingsConverterAttribute(SettingName = "Composite.WindowsAzure.WebRole.Storage.ConnectionString")]
        public override void ParseDeploymentSettings(string settingValue, Action<string, object> parser)
        {
            base.ParseDeploymentSettings(settingValue, parser);
       
        }
        [DeploymentSetting(SettingName = "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", IgnoreWhenParsing = true)]
        [DeploymentSetting(SettingName = "Composite.WindowsAzure.WebRole.Storage.ConnectionString")]
        public override string ConnectionString()
        {
            return base.ConnectionString();

        }
    }

and using it in a model like this

        [Display(Name = "Blob Storage Connection String", Order = 2)]
        public BlobStorageConnectionString ConnectionString { get; set; }

will give the user a input for account name, key and http usage. Further more the ... and + let them select one from their subscription or create a new one.

Caption: The input generated from a model class for S-Innovations Windows Azure Publisher



comments powered by Disqus