Skip to content

Commit

Permalink
Add azure-ts-appservice example (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikhailshilkov authored and lukehoban committed Jun 22, 2018
1 parent 31febdc commit c5f5339
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 0 deletions.
2 changes: 2 additions & 0 deletions azure-ts-appservice/Pulumi.yaml
@@ -0,0 +1,2 @@
name: azure-appservice
runtime: nodejs
62 changes: 62 additions & 0 deletions azure-ts-appservice/README.md
@@ -0,0 +1,62 @@
# 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!
```
100 changes: 100 additions & 0 deletions azure-ts-appservice/index.ts
@@ -0,0 +1,100 @@
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}`);
18 changes: 18 additions & 0 deletions azure-ts-appservice/package.json
@@ -0,0 +1,18 @@
{
"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"
}
}
37 changes: 37 additions & 0 deletions azure-ts-appservice/sas.ts
@@ -0,0 +1,37 @@
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);
});
}
25 changes: 25 additions & 0 deletions azure-ts-appservice/tsconfig.json
@@ -0,0 +1,25 @@
{
"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"
]
}
5 changes: 5 additions & 0 deletions azure-ts-appservice/wwwroot/index.html
@@ -0,0 +1,5 @@
<html>
<body>
<h1>Greetings from Azure App Service!</h1>
</body>
</html>

0 comments on commit c5f5339

Please sign in to comment.