How to Setup Git Deployment of Azure Web Apps

The Azure Portal (https://portal.azure.com/) has had me stumped on an apparently simple task for the past couple of days. I became lost in the UI of are trying to create a new Azure Web App that I could deploy changes to by pushing to a git repository. Here are the steps you actually need to get this done…

  1. Login to https://portal.azure.com/
  2. Top left of the screen click “Create a resource”
  3. In the search box type for “node empty” and pick the “Node JS Empty Web App”
    2018-04-20 07_47_22-Everything - Microsoft Azure

  4. Fill in details for the new web app and optionally click “App service plan/location” if you want to change the size, and therefore cost, of the instance, and where it is located in the world

  5. Press “Create” and wait for your app to deploy
  6. Open the app and click the URL to make sure the deployment is actually now serving web pages
    2018-04-19 07_55_02-Dashboard - Microsoft Azure
  7. This is where I became stuck. Just how do you get the git deployment working from here?
  8. In the “Deployment” sidebar menu click “Deployment credentials” and make sure you have a username and password set up
  9. Click the “Deployment options” two menus down. Pick “Choose source” then “Local Git Repository”. You may have to disconnect any existing options using the button on the top menu of the deployment options tile
    2018-04-19 07_58_45-Choose source - Microsoft Azure
  10. Now you need to scroll halfway down the sidebar menu to find the “Properties” title. In that tile is the git url for your web app
    2018-04-19 08_01_01-Properties - Microsoft Azure
  11. On your local PC git clone that git url. You’ll need the username and password you created earlier to login
  12. Git should then clone you a directory structure something like this:
    2018-04-20 07_39_48-sleepsuntil-web
  13. Edit the file server.js changing the text res.end('Hello, world!'); to something of your choosing
  14. Commit the change in git then do a git push
  15. Reload the URL of Azure app and you should see your changes

Exercise: Test Driven Development With Azure Functions

Challenge

Use a unit test framework to create a test driven development (TDD) pipeline for the “Sleeps Until” Azure Function we’ve been building.

Solution

The main feature of a good unit test is that it must be fast. You need to be running the tests repeatedly while developing and if your tests are slow you won’t keep up the discipline. Fast implies that you can’t wait on a network call to run the tests; they must run locally.

The Azure team has created a set of tools to allow you to run your functions locally (here are the docs), but this is too heavyweight. We’re trying to set up unit tests. We don’t need to integrate the whole functions stack. All we need to do is run a little JavaScript code.

Working Example

Let’s try and use TDD to refactor some candidate code from the Sleepsuntil code base.

Example code to refactor:

code_to_refactor

We want to pull that into a single function, has_correct_params(), and we want to develop the test first.

We need to write a test test_has_correct_params() that asserts some things about how the code should work and then refactor out the existing code into a new function. The problem is how to have a separate test file and have that call the function under test. Azure functions won’t let us export more than the one function from a single file, see here:

All JavaScript functions must export a single function via module.exports for the runtime to find the function and run it. This function must always include a context object.

As a solution we will pull the code to refactor into a separate file, sleeps.js, and then export the functions we need back to both the test files and the Azure HTTP Trigger function.

Steps to Write the Code

We’re going to need a unit testing framework to build with. There are several available. We’re picking the AVA unit test framework https://github.com/avajs/ava for its simplicity.

  • Let’s start writing the testing function in test_sleeps.js
"use strict";

import test from 'ava';
  • That should be enough to have a breaking test. On the console run npm test. This of course fails since we’ve not installed AVA yet:

ava_not_installed

  • npm install --save-dev ava@next
  • Update the package.json file to run the AVA tests: `”test”: “ava”
  • npm test now complains, correctly, that it can’t find any test files
  • Add a section to package.json to tell AVA where to find the tests:
  "ava": {
    "files": ["test_*.js"]
  }
  • Now AVA runs fine but complains it has no tests.
  • Add some simple test code. Remember we’re testing whether the correct parameters have been passed to the function. These parameters will be in the Azure Functions request object:
import sleeps from "./sleeps.js";

test("Request has required parameters", 
    function (t) {
        const req = { "query" : {}};
        t.false(sleeps.has_required_params(req));
    });
  • This now fails since we haven’t written the sleeps.js code yet. Let’s start with the simplest thing that changes the test result:
"use strict";

function has_required_params(req) {
    return false;
}

module.exports.has_required_params = has_required_params;
  • Now for the first time we have a passing test!
  • What remains is to iteratively add test cases until we have test coverage:
test("Request has required parameters", 
    function (t) {
        const req = { "query" : {}};
        t.false(sleeps.has_required_params(req));

        req.query = {"year": "1234"};
        t.false(sleeps.has_required_params(req));

        req.query = {
            "year": "1234",
            "month" : "56",
            "day": "78"};
        t.true(sleeps.has_required_params(req));        

    });

…and the associated implementation in sleeps.js

function has_required_params(req) {
    return Boolean(req.query.year) 
        && Boolean(req.query.month)
        && Boolean(req.query.day);
}

module.exports.has_required_params = has_required_params;
  • The last step is to plug that back into the Azure Functions code:
import sleeps from "./sleeps.js";

...

    if (sleeps.has_required_params(req)) {
        const target = moment({year: req.query.year,
            month: (parseInt(req.query.month) - 1), // JS Dates are zero indexed!!!
            day: req.query.day });

...

…and git push to deploy up to the Azure Portal and test.

deploy_sleeps

  • Except that didn’t work because Azure Functions don’t support ES6 imports yet:

import_error

  • Modify the code to use the node require() form of module import. Of course changing the test code first and then the Azure Function.
const sleeps = require("./sleeps.js");

Conclusion

We’ve created a unit testing pipeline for Azure functions allowing us to develop in a test-first style. In the process we have factored application logic out of the Azure Functions code nicely separating concerns of application logic vs. handling web requests.

Exercise: Git Push Deployment of Azure Functions

Challenge

Make updates to Azure Functions code by pushing to a git repository. Use the code created in the previous exercise and modify it and deploy the changes with a git push.

Solution – Step 1: Set Up Git Credentials to Use With Azure Functions Code

  1. Log in to portal.azure.com and open the panel for your Functions app
  2. Set up a username and password for accessing the Functions code using the “Deployment credentials” section of “Platform features”
  3. Choose the “Deployment options” panel and set up a local git connector
  4. Now choose the “Properties” panel and find the “GIT URL”
  5. User the Git URL to clone the repository locally with git clone URL-just-created
  6. That created a local copy of the Functions App folder structure

Solution – Step 2: Link a Git Push to Updating the Azure Function

  1. First let’s try a simple change followed by a push to Azure. I’m going to change the “sleepsuntil” function that I had before to return “9999” regardless of input and push that to Azure

test_9999

…then git push…

commit_changes

Testing this change in the browser has no luck:

fail_update

  1. …and then I went down a rabbit hole of trying to figure out why the push didn’t update the function until…

HAVE YOU TRIED TURING IT OFF AND ON AGAIN?

…the fix was to disconnect the local git option in the Azure portal…

fixing_azure

…and then connect again. It all worked fine after that!

Exercise: Use a JavaScript Library in Azure Functions

Challenge

Take the Azure function created in Exercise: Write an Azure Function in JavaScript to Return the Current Date and modify it to tell you the number of sleeps until a date in the future. Use a third-party JS library to do the date arithmetic.

Solution Steps

I’m going to use the Moment.js library to do date manipulation. With Moment.js installed the calculation of dates between two dates is relatively simple:

function sleepsuntil(target_date) {
// target_date should be a moment.js object
const today = (new moment()).startOf("day");
result = target_date.diff(today, "days");
return Math.max(0, result); // No sleeps to a date in the past
}

The challenge comes in how to use Moment.js from an Azure function.

      1. The Microsoft documentation briefly touches on JS package management in Azure
      2. You need to add a npm style package.json file into the folder on Azure that holds the code for your function
      3. To access the Azure Functions folders you need to open the “Advanced Tools (Kudu)” menu. Like this…open_kudu
      4. Using a local console with node installed use the npm tools to create a package.json file with the dependency to moment.js:
        npm init
        npm install moment --save
      5. That results in a package.json file like this:
        {
          "name": "sleepsuntil",
          "version": "1.0.0",
          "description": "How many sleeps until a given date",
          "main": "index.js",
          "scripts": {
            "test": "echo \"Error: no test specified\" && exit 1"
          },
          "author": "",
          "license": "ISC",
          "dependencies": {
            "moment": "^2.21.0"
          }
        }
        
      6. You can now navigate in the Kudu console to the folder containing the HTTP Trigger. To do this after starting Kudu you click: Debug console -> CMD -> site -> wwwroot -> HttpTriggerJS1
      7. You now drag-and-drop your package.json file from your local machine up into the Azure Portal. The folder should end up looking like this:kudu-folder
      8. In the command window at the bottom of the Kudu screen type:
         npm install
      9. The system should report back that it has installed moment for you. It will probably also complain you haven’t set up the repository field.
      10. We’re nearly there. All is left to do is update the function to use input from the browser and return the number of days calculated by moment:
        module.exports = function (context, req) {
            var moment = require("moment");
            function sleepsuntil(target_date) {
                // target_date should be a moment.js object
                const today = (new moment()).startOf("day");
                result = target_date.diff(today, "days");
                return Math.max(0, result); // No sleeps to a date in the past
            }
        
            if (req.query.year &&
                req.query.month &&
                req.query.day) {
        
                    const target = moment({year: req.query.year,
                                           month: (parseInt(req.query.month) - 1), // JS Dates are zero indexed!!!
                                           day: req.query.day });
        
                    context.res = {
                        body: sleepsuntil(target)
                    };
            }
            else {
                context.res = {
                    status: 400,
                    body: "Please pass a year, month, and day."
                };
            }
            context.done();
        };
        

Exercise: Write an Azure Function in JavaScript to Return the Current Date

Challenge

Here’s a starter exercise for Azure Functions: write a function to return the current date.

Solution Steps

  1. The first set of tasks are all around getting a function set up on https://portal.azure.com/
  2. Log in to the Azure portal
  3. Make a resource group “learning”. We’ll use this in the future to organise all Azure resources associated with throw-away learning tasks
  4. Add a “Function App” called “datenow”
    • OS = Windows
    • Located = UK West
    • Create new storage
  5. In the function app create new function of type “HTTP Trigger” and language JavaScript
  6. When the app is created it adds a helpful example function. A small amount of modification results in the function returning the current date:
    module.exports = function (context, req) {
        context.log('JavaScript HTTP trigger function processed a request.');
        const now = new Date()
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: now
        };
        context.done();
    };
    

     

  7. Notice how the Azure functions framework handles the encoding of the JavaScript Date object correctly based on the content negotiated with the requestor. Using a HTTP testing tool, like Postman for Chrome, if you specify “Accept: text/json” then you get a JSON represnation back; specifcy “Accept: text/xml” and XML is returned

 

Python Snippet to Hash Email Addresses

I wanted to process some email address data today but hide the real email addresses. To do that I chose to run the SHA-256 hash over the email address data. Here’s the python snippet I used to convert the plain emails to the hashed versions (ignoring any emails with anything other than ASCII characters for simplicity):


import hashlib

plain_emails = ["user1@address1",
                "user2@address2"]

hashed_emails = [hashlib.sha256(bytes(mail.lower(), "ascii")).hexdigest()
                 for mail
                 in plain_emails]