Provisioning Teams with Azure Functions and Microsoft Flow Part 4: Looking at the Code

This is the another article in a blog series explaining a new open source solution (located here) for provisioning Microsoft Teams. The solution is based on Azure Functions which communicate with Microsoft Flow (or really anything) using Azure queues. This allows a Flow, PowerApps, or Logic Apps developer to use whatever logic they wish and, when a Team is to be created, queue a message to an Azure Function which will do the work.

This is Part 4 of the series, which reviews some key areas of the Azure Functions code as well as the Azure Resource Manager (ARM) Template which provisions it.

  1. Solution Overview
  2. Installing the solution
  3. Building a Flow for the solution
  4. Looking at the code (this post)
  5. A Change in Direction

The Azure Functions are “version 2” functions written in Node JS. I could’ve used C# and that would be fine, but since I’m working in SharePoint Framework a lot lately, and I’m finding it easier to stay in JavaScript/TypeScript for back-end code as well.

Handling app settings

App settings can be read using

process.env["name"]

The environment is smart enough to pull the settings from your local.settings.json file when debugging, or from the Azure Function Application settings in Azure. The file Services/Settings/settings.js reads in these values and also includes a few constants that are used throughout the solution.

Running with App Permissions in Node

One of the design goals of this project was to use application permissions rather than relying on a user account. This sample shows how to do that in Node. I considered using the spiffy new Graph API Auth input binding, but they don’t work in the client tools, which make it difficult to debug. So instead I coded it up myself.

If you look at the package.json file, you’ll notice that we have two dependencies on npm packages:

  "dependencies": {
    "adal-node": "^0.1.28",
    "request": "^2.88.0"
  },
  • adal-node is the package that obtains an access token using app permissions (client credential flow). This token is included in all Graph API calls to authenticate our application
  • request is a package that lets us make web service calls from Node

Now check out the file Services/Token/getToken.js. This function returns a promise of an access token which can be used in every Graph call. There’s not a lot of code here – very simple!

  return new Promise((resolve, reject) => {

    // Get the ADAL client
    const authContext = new adal.AuthenticationContext(
      settings().AUTH_URL + settings().TENANT);
      
    authContext.acquireTokenWithClientCredentials(
      settings().GRAPH_URL, settings().CLIENT_ID, settings().CLIENT_SECRET, 
      (err, tokenRes) => {
        if (err) {
          reject(err); 
        } else {
          resolve(tokenRes.accessToken);
        }
    });
  });

Then, to call the Graph, this token is added to the heading:

request.get(url, {
    'auth': {
        'bearer': token
    }
}, (error, response, body) => {
    // ... callback from request
}

The right way to Create or Clone

The Create and Clone calls in Graph are long-running – that is, they probably won’t finish immediately. Rather than return a result, these calls return an “operation URL” which you’re supposed to call periodically until the operation is done.

I’ve noticed many examples that call the Clone or Create API and then they move on without checking the operation URL. This might be OK sometimes, but it’s like ordering online and not checking the confirmation page … maybe it worked, maybe not!

Check out Services/Team/createTeam.js (or cloneTeam.js). There you will see a function called PollUntilDone() (actually I need to extract it into a shared function). It’s called by the callback from the create or clone request, and it calls itself recursively until it gets a completion (success or failure), or until it exceeds a retry count.

Reading a file from SharePoint

If you’ve never read a SharePoint file from the Graph API, you’ve never lived! When you’re running on a SharePoint page, this is trivial (just request the URL). But in the Graph API I found myself going through quite a number of steps:

  1. Given the site URL, get the SharePoint site ID
  2. Given the SharePoint Site ID and library name, get a Drive ID
  3. Given the Drive ID and the filename, get the Item, which includes a download URL
  4. Reuqest the download URL and get the contents of the file

See Services/Template/getTemplate.js for the code.

Azure Resource Manager

I wanted to make it easy for people to install the Azure functions in new tenants, and for new environments in a tenant (dev, test, production, etc.). The way to do that is using an Azure Resource Manager Template. The ARM template is a JSON file containing all the details of what you want to provision; in this project that file is called azuredeploy.json.

The file begins with a list of parameters, some of which are specified on the command line, some in the parameters file, and some may not be specified and a default value is used. Next there are some variable declarations, which build out more values – for example, the storage account name and function apps name.

Then it gets interesting with the actual resources:

  • The Azure storage account, which holds the Azure Function files and also the Azure queues
  • The App Service Plan (called a “serverFarm” – which is more descriptive of what it is!) which builds the VM’s that run the Function App under the covers
  • The App Service (called a “site”) and the Function App, which is the IIS web site and the application within to run your Azure Functions. This is where the Function App settings are set, including the queue names, tenant ID, client ID and secret, etc. (If you follow the installation instructions, the client secret will actually be a reference to Key Vault, so your actual Client Secret is protected and not laying around in n app setting).
  • The Source Controls, which is actually a sub-resource of the App Service, and which sets up continuous integration from Github (set the isManualIntegration flag to false if you want to automatically rebuild when a new version is published to Github)
  • Application Insights, which will monitor your solution

All this is contained in a single Resource Group (RG), so you can delete it all by just deleting the RG. Also – like SharePoint Site Scripts, Resource Manager templates are idempotent so you can run them over and over again and it will update the resources as needed to bring them to the desired state.

Improving and Evolving the Code

The good news is that the PnP team has provided a repository and is now on board with this effort! More importantly, this will now be part of a greater feature set for provisioning in Office 365. When I originally wrote this, I overlooked a key option – PnP Tenant Templates – for the project. This new approach will allow building templates which provision not only a Team, but the SharePoint and other content that is associated with the Team.

Please check out the next post in this continuing series for more information!

 

5 thoughts on “Provisioning Teams with Azure Functions and Microsoft Flow Part 4: Looking at the Code

Leave a comment