• FabrikamShipping: the provisioning machinery built with Windows Azure

    Published by on October 29th, 2010 3:21 pm under Access Control Service, Azure, Emerging Technology, FabrikamShipping, Provisioning

    No Comments

    This is a series of posts, read the introduction to FabrikamShipping for more information about this sample application and Vittorio’s blog for latest updates.

    One of the first challenges we had to solve in FabrikamShipping was the provisioning/on boarding of new customers. If you look at FabrikamShipping subscription page you can see there are 3 different subscription types: Personal, Small Business and Enterprise. Each subscription type consists of different input, output and processing steps. However, there are aspects that are shared between them, for instance sending an email to the customer when we’re done, create the subscription info, create rules in Access Control Service, etc.

    We wanted to have something lightweight that could run in a Windows Azure worker role waiting for queue messages and perform a set of tasks. Keep reading to understand what this is about….

    Provisioning API

    With those things in mind we wanted a Provisioning API would allow us:

    • to define different type of provisioning flows (ie: small biz has a different provisioning workflow compared to enterprise)
    • to handle manual steps (for things that don’t have an API)
    • to compensate in case of failure
    • to retry a failed provisioning

    On the non-functional side we wanted:

    • Reusability and composability of tasks between the different workflows
    • Resiliency
    • Nice DX (developer experience)
    • Testability

    With that in mind and based on previous experiences in BidNow and the patterns & practices cloud guide, we sketched the following API:

    Task.TriggeredBy(Message.In("deploy-queue"))
        .Do(
            new CreateSelfSignedCert(),
            new CreateSqlAzureDb(),
            new ConfigurePackageAndMetadata(),
            new SetupFederation(),
            new DeployApp() });

    Which in essence is:

    Task.TriggeredBy(() => condition)
        .Do(params ICommand[] commands)
    And allow us to define time based conditions like
    Task.TriggeredBy(Schedule.Every(30 * 1000))
        .Do(...);
    After a couple of days we had a prototype working and this is what you can find today in the FabrikamShipping source code.
    Task.TriggeredBy(Message.OfType<SmallBizProvisioningMessage>(new AzureQueue(account)))
        .SetupContext((message, context) =>
        {
            context.Add("TenantAlias", message.CompanyAlias);
            context.Add("SubscriptionId", message.SubscriptionId);
            context.Add("SmallBizApplicationUrl", smallBizApplicationUrl);
            context.Add("DatabaseName", "fs-" + message.CompanyAlias);
        })
        .Do(
            new UpdateSubscriptionStatus(...),
            new CreateSigningCertificate(...),
            new CreateSqlAzureDb(...),
            new CreateSqlAzureDb(...),
            new CreateUsers(...),
            new ConfigureTrustRelationshipForSmallBiz(...),
            new UploadTenantMetadata(...),
            new NotifyUserCreated(...)
        .OnError(logException)
        .Start();
    These kind of workflows can be implemented with this API. This is the actual workflow for the FabrikamShipping enterprise provisioning and small business provisioning:
    Enterprise Provisioning Small Business Provisioning
    image image
    So in short, the API supports the following
    • Queue message based triggers
    • Time based triggers for tasks that require manual or long running operations
    • Commands with Do and Undo for compensation and retry
    • Sharing context between commands
    • Handling errors

    Commands

    Every command derives from an interface ICommand that has Do and Undo and takes a dictionary that has contextual information. This is a sample command that deploys a package to a hosted service.
    public class DeployAzureService : ICommand
    {
          private readonly ProvisioningLogger logger;
          private readonly ServiceManagementWrapper azureApi;
    
          public DeployAzureService(ProvisioningLogger logger, ServiceManagementWrapper azureApi)
          {
              this.logger = logger;
              this.azureApi = azureApi;
          }
    
          public void Do(IDictionary<string, object> context)
          {
              // use azure Service Management API to deploy the package
          }
    
          public void Undo(IDictionary<string, object> context)
          {
             // remove the package
          }
    }
    There are commands for a bunch of things:
    • Create SQL Azure DB
    • Send emails
    • Create a trust relationship with Access Control Service
    • Create x509 certificates
    • Running SQL scripts
    • Create tenant metadata

    Logging

    You can also use a logger (see the ProvisioningLogger dependency on the command above) that will push log entries to an Azure table that later on we use to print a nice looking status for both the subscriber and the admin
    image
    If something went wrong you can click on View Log and look at the actual steps and values
    image
    Finally, this comes with the usual disclaimer. This is sample code and is provided as-is… But if you are an ISV creating apps in Azure, you should definitely check this out!

Tags