In this lab, you will extend the statusapp
project to add an HTML frontend application that displays drone status data. You will deploy a static website to a new Storage Account, including the HTML and JavaScipt files.
Azure NextGen provider is designed to expose the API of Azure Resource Manager (ARM). Currently, ARM does not contain operations required to setup a static website on a Storage Account: those operations belong to the data plane and storage-specific SDKs. Therefore, the Azure NextGen provider doesn't suppose them either.
However, the Terraform-based "Azure" provider does support Storage Static Websites.
Make sure you are still in the statusapp
folder with the same files that you created in Lab 4. Go ahead and run the following command to install the Azure provider to the project.
npm install @pulumi/azure
Create a new file called website.ts
in the same statusapp
folder where index.ts
exists. Add the following lines to it:
import * as azure from "@pulumi/azure";
import { appName, resourceGroupName } from "./common";
export const storageAccount = new azure.storage.Account(`${appName}fe`, {
resourceGroupName: resourceGroupName,
tags: {
displayName: "Drone Front End Storage Account",
},
accountTier: "Standard",
accountReplicationType: "LRS",
staticWebsite: {
indexDocument: "index.html",
error404Document: "404.html",
},
});
export const storageAccountUrl = storageAccount.primaryWebEndpoint;
You defined yet another Storage Account. This time, it has an extra property staticWebsite
which makes Azure create a special blob container called $web
. Any files in that container will be served as a static website.
You also exported the URL that can be used as the website endpoint.
Add an import line and an export line to index.ts
:
import * as website from "./website";
export const storageAccountUrl = website.storageAccountUrl;
✅ After these changes, your files should look like this.
Download the zip archive from https://mikhailworkshop.blob.core.windows.net/zips/droneapp-noauth.zip.
Extract the contents into the folder droneapp-noauth
under the folder statusapp
. Make sure that the HTML and JavaScript files are located directly inside statusapp/droneapp-noauth
(not in a subfolder below).
These files are a React-basd web application built with Webpack. That's why the file names are a bit odd. noauth
means there's no authentication built-in yet: you will add authentication in Lab 8.
The source for this application is available here.
The next step relies of several NPM packages to be present. Run the following command to install the to the statusapp
:
npm install mime node-dir @types/mime @types/node-dir
✅ After these changes, your
package.json
file should look like this.
Create a new file called websiteFiles.ts
in the same statusapp
folder. Add the following lines to it:
import * as pulumi from "@pulumi/pulumi";
import * as azure from "@pulumi/azure";
import * as website from "./website";
import * as functionApp from "./functionApp";
import * as mime from "mime";
import * as nodedir from "node-dir";
import * as fs from "fs";
const folderName = "droneapp-noauth";
const files = nodedir.files(folderName, { sync: true });
for (const file of files) {
const name = file.substring(folderName.length+1);
const contentType = mime.getType(file) || undefined;
const rawText = fs.readFileSync(file, "utf8").toString();
const asset = functionApp.functionUrl
.apply(url => rawText.replace("[API_URL]", url))
.apply(text => new pulumi.asset.StringAsset(text));
const myObject = new azure.storage.Blob(name, {
name,
storageAccountName: website.storageAccount.name,
storageContainerName: "$web",
type: "Block",
source: asset,
contentType,
}, { parent: website.storageAccount });
}
Here is what happens in this snippet:
- You list the files inside the
droneapp-noauth
folder and iterate through them with afor
loop. - You extract the file
name
from the path. - You determine the
contentType
of the file. - You load the file contents to
rawText
. - Some files have a placeholder for the backend URL. In real apps, you'd probably bake this URL at the Webpack build time, but here we simply replace it at deployment time.
- The placeholder
[API_URL]
is replaced with the URL of the Function App from Lab 4. - You deploy the file with the
Blob
resource to the$web
container of the storage account.
Add an import line to index.ts
:
import "./websiteFiles";
✅ After these changes, your files should look like this.
Deploy the stack
$ pulumi up
...
Updating (dev):
Type Name Status
+ pulumi:pulumi:Stack statusapp-dev created
+ └─ azure:storage:Account statusfe created
+ ├─ azure:storage:Blob chunk-map.json created
...
Outputs:
+ storageAccountUrl: "https://statusfe1267cccd.z6.web.core.windows.net/"
Resources:
+ 21 created
6 unchanged
Navigate to the storageAccountUrl
in a browser, enter your sample drone name to the search box, and hit Enter. You should be able to see the drone data:
If needed, replace drone-543
with a name of drone as seen in lab 3.
Congratulations! 🎉 You have successfully provisioned a static website and linked it to the Azure Function backend connected to Azure Cosmos DB.
Next, you will deploy an API Management service in front of the Azure Function.