1. Docs
  2. Infrastructure as Code
  3. Get Started
  4. Azure
  5. Make an update

Get started with Pulumi and Azure

    Make an update

    Now you will update your project to serve a static website out of your Azure storage account. You will change your code and then re-run pulumi up which will update your infrastructure.

    Add new resources

    Pulumi knows how to evolve your current infrastructure to your project’s new desired state, both for the first deployment as well as subsequent updates.

    To turn your storage account into a static website, you will add two new Azure resources:

    1. StorageAccountStaticWebsite: enables static website support on your storage account
    2. Blob: uploads your website content to the storage container

    Add an index.html

    First, from within your project directory, create a new index.html file with some content in it.

    cat <<EOT > index.html
    <html>
        <body>
            <h1>Hello, Pulumi!</h1>
        </body>
    </html>
    EOT
    
    cat <<EOT > index.html
    <html>
        <body>
            <h1>Hello, Pulumi!</h1>
        </body>
    </html>
    EOT
    
    @"
    <html>
      <body>
        <h1>Hello, Pulumi!</h1>
      </body>
    </html>
    "@ | Out-File -FilePath index.html
    

    Now open index.js index.ts __main__.py main.go Program.cs Program.fs Program.vb App.java Pulumi.yaml in your editor and enable static website support by adding a StorageAccountStaticWebsite resource right after the storage account is created:

    // Create an Azure resource (Storage Account)
    const storageAccount = new storage.StorageAccount("sa", {
        /* existing storage account configuration */
    });
    
    // Enable static website support - add this code
    const staticWebsite = new storage.StorageAccountStaticWebsite("staticWebsite", {
        accountName: storageAccount.name,
        resourceGroupName: resourceGroup.name,
        indexDocument: "index.html",
    });
    
    # Create an Azure resource (Storage Account)
    account = storage.StorageAccount(
        "sa",
        # existing storage account configuration
    )
    
    # Enable static website support - add this code
    static_website = storage.StorageAccountStaticWebsite(
        "staticWebsite",
        account_name=account.name,
        resource_group_name=resource_group.name,
        index_document="index.html",
    )
    
    // Create an Azure resource (Storage Account)
    account, err := storage.NewStorageAccount(ctx, "sa", &storage.StorageAccountArgs{
        // existing storage account configuration
    })
    if err != nil {
        return err
    }
    
    // Enable static website support - add this code
    staticWebsite, err := storage.NewStorageAccountStaticWebsite(ctx, "staticWebsite", &storage.StorageAccountStaticWebsiteArgs{
        AccountName:       account.Name,
        ResourceGroupName: resourceGroup.Name,
        IndexDocument:     pulumi.String("index.html"),
    })
    if err != nil {
        return err
    }
    
    // Create an Azure resource (Storage Account)
    var storageAccount = new StorageAccount("sa", new StorageAccountArgs
    {
        /* existing storage account configuration */
    });
    
    // Enable static website support - add this code
    var staticWebsite = new StorageAccountStaticWebsite("staticWebsite", new StorageAccountStaticWebsiteArgs
    {
        AccountName = storageAccount.Name,
        ResourceGroupName = resourceGroup.Name,
        IndexDocument = "index.html",
    });
    

    First, add the following imports at the top of App.java:

    import com.pulumi.azurenative.storage.StorageAccountStaticWebsite;
    import com.pulumi.azurenative.storage.StorageAccountStaticWebsiteArgs;
    import com.pulumi.azurenative.storage.Blob;
    import com.pulumi.azurenative.storage.BlobArgs;
    import com.pulumi.azurenative.storage.outputs.EndpointsResponse;
    import com.pulumi.asset.FileAsset;
    

    Then add the following right after the storage account creation:

    // Create an Azure resource (Storage Account)
    var storageAccount = new StorageAccount("sa", StorageAccountArgs.builder()
        // existing storage account configuration
        .build());
    
    // Enable static website support - add this code
    var staticWebsite = new StorageAccountStaticWebsite("staticWebsite",
                        StorageAccountStaticWebsiteArgs.builder()
                                .accountName(storageAccount.name())
                                .resourceGroupName(resourceGroup.name())
                                .indexDocument("index.html")
                                .build());
    
    resources:
      # Create an Azure resource (Storage Account)
      sa:
        type: azure-native:storage:StorageAccount
        # existing storage account configuration
    
      # Enable static website support - add this code
      staticWebsite:
        type: azure-native:storage:StorageAccountStaticWebsite
        properties:
          accountName: ${sa.name}
          resourceGroupName: ${resourceGroup.name}
          indexDocument: index.html
    

    Notice that resources can reference each other, which forms automatic dependencies between them. Pulumi uses this information to parallelize deployments safely.

    Now use all of these cloud resources and a local FileAsset resource to upload index.html into your storage container by adding a Blob at the end of the file (after enabling the static website support):

    // Upload the file
    const indexHtml = new storage.Blob("index.html", {
        resourceGroupName: resourceGroup.name,
        accountName: storageAccount.name,
        containerName: staticWebsite.containerName,
        source: new pulumi.asset.FileAsset("index.html"),
        contentType: "text/html",
    });
    
    # Upload the file
    index_html = storage.Blob(
        "index.html",
        resource_group_name=resource_group.name,
        account_name=account.name,
        container_name=static_website.container_name,
        source=pulumi.FileAsset("index.html"),
        content_type="text/html",
    )
    
    // Upload the file
    _, err = storage.NewBlob(ctx, "index.html", &storage.BlobArgs{
        ResourceGroupName: resourceGroup.Name,
        AccountName:       account.Name,
        ContainerName:     staticWebsite.ContainerName,
        Source:            pulumi.NewFileAsset("index.html"),
        ContentType:       pulumi.String("text/html"),
    })
    if err != nil {
        return err
    }
    
    // Upload the file
    var indexHtml = new Blob("index.html", new BlobArgs
    {
        ResourceGroupName = resourceGroup.Name,
        AccountName = storageAccount.Name,
        ContainerName = staticWebsite.ContainerName,
        Source = new FileAsset("./index.html"),
        ContentType = "text/html",
    });
    
    // Upload the file
    var index_html = new Blob("index.html", BlobArgs.builder()
                        .resourceGroupName(resourceGroup.name())
                        .accountName(storageAccount.name())
                        .containerName(staticWebsite.containerName())
                        .source(new FileAsset("index.html"))
                        .contentType("text/html")
                        .build());
    
    resources:
      # ...
      # Upload the file
      index-html:
        type: azure-native:storage:Blob
        properties:
          resourceGroupName: ${resourceGroup.name}
          accountName: ${sa.name}
          containerName: ${staticWebsite.containerName}
          source:
            fn::fileAsset: ./index.html
          contentType: text/html
          blobName: index.html
          type: Block
    

    This uploads the index.html file to your storage container using a Pulumi concept called an asset.

    Export the website URL

    Now to export the website’s URL for easy access, add the staticEndpoint export to your return statement as shown in this example:

    // Export the storage account name
    export const storageAccountName = storageAccount.name;
    
    // Web endpoint to the website
    export const staticEndpoint = storageAccount.primaryEndpoints.web;
    
    # Export the storage account name
    pulumi.export("storage_account_name", account.name)
    
    # Web endpoint to the website
    pulumi.export("staticEndpoint", account.primary_endpoints.web)
    
    // Export the storage account name
    ctx.Export("storageAccountName", account.Name)
    
    // Web endpoint to the website
    ctx.Export("staticEndpoint", account.PrimaryEndpoints.Web())
    
    // Export outputs
    return new Dictionary<string, object?>
    {
        ["storageAccountName"] = storageAccount.Name,
        ["staticEndpoint"] = storageAccount.PrimaryEndpoints.Apply(primaryEndpoints => primaryEndpoints.Web)
    };
    
    // Export the storage account name
    ctx.export("storageAccountName", storageAccount.name());
    
    // Web endpoint to the website
    ctx.export("staticEndpoint", storageAccount.primaryEndpoints()
            .applyValue(EndpointsResponse::web));
    
    outputs:
      # Export the storage account name
      storageAccountName: ${sa.name}
    
      # Web endpoint to the website
      staticEndpoint: ${sa.primaryEndpoints.web}
    

    The storage account’s endpoint is an output property that Azure assigns at deployment time, not a raw string, meaning its value is not known in advance.

    Deploy the changes

    To deploy the changes, run pulumi up again and it will figure out the deltas:

    $ pulumi up
    
    > pulumi up
    

    Just like the first time you will see a preview of the changes before they happen:

    Previewing update (dev):
    
         Type                                                   Name                 Plan
         pulumi:pulumi:Stack                                    quickstart-dev
     +   ├─ azure-native:storage:StorageAccountStaticWebsite    staticWebsite        create
     +   └─ azure-native:storage:Blob                           index.html           create
    
    Outputs:
      + staticEndpoint   : "https://sa8dd8af62.z22.web.core.windows.net/"
    
    Resources:
        + 2 to create
        3 unchanged
    
    Do you want to perform this update?
    > yes
      no
      details
    

    Choose yes to perform the deployment:

    Do you want to perform this update? yes
    Updating (dev):
    
         Type                                                   Name                Status
         pulumi:pulumi:Stack                                    quickstart-dev
     +   ├─ azure-native:storage:StorageAccountStaticWebsite    staticWebsite       created
     +   └─ azure-native:storage:Blob                           index.html          created
    
    Outputs:
        storageAccountName: "sa8deefa78"
      + staticEndpoint   : "https://sa8dd8af62.z22.web.core.windows.net/"
    
    Resources:
        + 2 created
        3 unchanged
    
    Duration: 4s
    

    In just a few seconds, your new website will be ready. Curl the endpoint to see it live:

    $ curl $(pulumi stack output staticEndpoint)
    
    > curl (pulumi stack output staticEndpoint)
    

    This will reveal your new website!

    <html>
        <body>
            <h1>Hello, Pulumi!</h1>
        </body>
    </html>
    

    Feel free to experiment, such as changing the contents of index.html and redeploying.

    Next, wrap the website into an infrastructure abstraction.

      Neo just got smarter about infrastructure policy automation