Add azure-ts-appservice example
ADD
azure-ts-appservice/Pulumi.yaml
+name: azure-appservice
+runtime: nodejs

ADD
azure-ts-appservice/README.md
+# Azure App Service with SQL Database and Application Insights
+
+Starting point for building web application hosted in Azure App Service.
+
+Provisions Azure SQL Database and Azure Application Insights to be used in combination
+with App Service.
+
+## Running the App
+
+1. Create a new stack:
+
+ ```
+ $ pulumi stack init azure-appservice
+ ```
+
+1. Login to Azure CLI (you will be prompted to do this during deployment if you forget this step):
+
+ ```
+ $ az login
+ ```
+
+1. Restore NPM dependencies:
+
+ ```
+ $ npm install
+ ```
+
+1. Build the Typescript project:
+
+ ```
+ $ npm run build
+ ```
+
+1. Define SQL Server password (make it complex enough to satisfy Azure policy):
+
+ ```
+ pulumi config set <stack>:sqlPassword <value>
+ ```
+
+
+1. Run `pulumi update` to preview and deploy changes:
+
+ ```
+ $ pulumi update
+ Previewing changes:
+ ...
+
+ Performing changes:
+ ...
+ info: 10 changes performed:
+ + 10 resources created
+ Update duration: 1m14.59910109s
+ ```
+
+1. Check the deployed website endpoint:
+
+ ```
+ $ pulumi stack output endpoint
+ https://azpulumi-as0ef47193.azurewebsites.net
+ $ curl "$(pulumi stack output endpoint)"
+ Greetings from Azure App Service!
+ ```

ADD
azure-ts-appservice/index.ts
+import * as pulumi from "@pulumi/pulumi";
+import * as azure from "@pulumi/azure";
+import { signedBlobReadUrl } from "./sas";
+
+const name = pulumi.getStack();
+
+const resourceGroup = new azure.core.ResourceGroup(`${name}-rg`, {
+ location: "West US 2",
+ });
+
+const resourceGroupArgs = {
+ resourceGroupName: resourceGroup.name,
+ location: resourceGroup.location,
+};
+
+const storageAccount = new azure.storage.Account(`${name}sa`, {
+ ...resourceGroupArgs,
+
+ accountKind: "StorageV2",
+ accountTier: "Standard",
+ accountReplicationType: "LRS",
+});
+
+
+const appServicePlan = new azure.appservice.Plan(`${name}-asp`, {
+ ...resourceGroupArgs,
+
+ kind: "App",
+
+ sku: {
+ tier: "Basic",
+ size: "B1",
+ },
+});
+
+const storageContainer = new azure.storage.Container(`${name}-c`, {
+ resourceGroupName: resourceGroup.name,
+ storageAccountName: storageAccount.name,
+ containerAccessType: "private",
+});
+
+const blob = new azure.storage.ZipBlob(`${name}-b`, {
+ resourceGroupName: resourceGroup.name,
+ storageAccountName: storageAccount.name,
+ storageContainerName: storageContainer.name,
+ type: "block",
+
+ content: new pulumi.asset.FileArchive("wwwroot")
+});
+
+const codeBlobUrl = signedBlobReadUrl(blob, storageAccount, storageContainer);
+
+const appInsights = new azure.appinsights.Insights(`${name}-ai`, {
+ ...resourceGroupArgs,
+
+ applicationType: "Web"
+});
+
+const username = "pulumi";
+
+// Get the password to use for SQL from config.
+const config = new pulumi.Config(name);
+const pwd = config.require("sqlPassword");
+
+const sqlServer = new azure.sql.SqlServer(`${name}-sql`, {
+ ...resourceGroupArgs,
+
+ administratorLogin: username,
+ administratorLoginPassword: pwd,
+ version: "12.0",
+});
+
+const database = new azure.sql.Database(`${name}-db`, {
+ ...resourceGroupArgs,
+ serverName: sqlServer.name,
+ requestedServiceObjectiveName: "S0"
+});
+
+const app = new azure.appservice.AppService(`${name}-as`, {
+ ...resourceGroupArgs,
+
+ appServicePlanId: appServicePlan.id,
+
+
+ appSettings: {
+ "WEBSITE_RUN_FROM_ZIP": codeBlobUrl,
+ "ApplicationInsights:InstrumentationKey": appInsights.instrumentationKey,
+ "APPINSIGHTS_INSTRUMENTATIONKEY": appInsights.instrumentationKey
+ },
+
+ connectionStrings: [{
+ name: "db",
+ value:
+ pulumi.all([sqlServer, database]).apply(([server, db]) =>
+ `Server=tcp:${server}.database.windows.net;initial catalog=${db};user ID=${username};password=${pwd};Min Pool Size=0;Max Pool Size=30;Persist Security Info=true;`),
+ type: "SQLAzure"
+ }]
+});
+
+exports.endpoint = app.defaultSiteHostname.apply(n => `https://${n}`);

ADD
azure-ts-appservice/package.json
+{
+ "name": "azure-ts-appservice",
+ "version": "1.0.0",
+ "main": "bin/index.js",
+ "typings": "bin/index.d.ts",
+ "scripts": {
+ "build": "tsc"
+ },
+ "devDependencies": {
+ "@types/node": "^10.3.3",
+ "typescript": "^2.9.2"
+ },
+ "dependencies": {
+ "@pulumi/azure": "^0.14.0",
+ "@pulumi/pulumi": "^0.14.0",
+ "azure-storage": "^2.9.0-preview"
+ }
+}

ADD
azure-ts-appservice/sas.ts
+import * as pulumi from "@pulumi/pulumi";
+import * as azure from "@pulumi/azure";
+
+import * as azurestorage from "azure-storage";
+
+// Given an Azure blob, create a SAS URL that can read it.
+export function signedBlobReadUrl(
+ blob: azure.storage.Blob | azure.storage.ZipBlob,
+ account: azure.storage.Account,
+ container: azure.storage.Container,
+): pulumi.Output<string> {
+ // Choose a fixed, far-future expiration date for signed blob URLs.
+ // The shared access signature (SAS) we generate for the Azure storage blob must remain valid for as long as the
+ // Function App is deployed, since new instances will download the code on startup. By using a fixed date, rather
+ // than (e.g.) "today plus ten years", the signing operation is idempotent.
+ const signatureExpiration = new Date(2100, 1);
+
+ return pulumi.all([
+ account.primaryConnectionString,
+ container.name,
+ blob.name,
+ ]).apply(([connectionString, containerName, blobName]) => {
+ let blobService = new azurestorage.BlobService(connectionString);
+ let signature = blobService.generateSharedAccessSignature(
+ containerName,
+ blobName,
+ {
+ AccessPolicy: {
+ Expiry: signatureExpiration,
+ Permissions: azurestorage.BlobUtilities.SharedAccessPermissions.READ,
+ },
+ }
+ );
+
+ return blobService.getUrl(containerName, blobName, signature);
+ });
+}

ADD
azure-ts-appservice/tsconfig.json
+{
+ "compilerOptions": {
+ "outDir": "bin",
+ "target": "es6",
+ "lib": [
+ "es6"
+ ],
+ "module": "commonjs",
+ "moduleResolution": "node",
+ "declaration": true,
+ "sourceMap": true,
+ "stripInternal": true,
+ "experimentalDecorators": true,
+ "pretty": true,
+ "noFallthroughCasesInSwitch": true,
+ "noImplicitAny": true,
+ "noImplicitReturns": true,
+ "forceConsistentCasingInFileNames": true,
+ "strictNullChecks": true
+ },
+ "files": [
+ "index.ts",
+ "sas.ts"
+ ]
+}

ADD
azure-ts-appservice/wwwroot/index.html
+<html>
+ <body>
+ <h1>Greetings from Azure App Service!</h1>
+ </body>
+</html>
\ No newline at end of file

Add azure-ts-appservice example (#88)