Splitting or adding a frontend application

Warning

Introducing a new application will increase the amount of maintenance for the dev team. Make sure the team has discussed and agreed whether a new app is really necessary before following the steps below.

Prerequisites

Each new frontend application needs to meet some common requirements:

  • All routes have a shared prefix that is not used by any other frontend app (eg /suppliers or /opportunities). The best way to ensure this is to use a Blueprint with a url_prefix='/...' argument.

  • Make sure links to application static files start with /<prefix>/static. This is usually done by setting Flask static URL path with Flask(..., static_url_path=configs[config_name].STATIC_URL_PATH) in app/__init__.py and adding STATIC_URL_PATH = '/<prefix>/static' and ASSET_PATH = STATIC_URL_PATH + '/' to config.py.

  • Application has a status endpoint at /<prefix>/_status

  • Application uses a unique port when running locally with a dev server (eg 5000, 5001, … used by existing apps)

Setting up infrastructure

Setting up a repo

Follow the steps in Adding a new repository to create a GitHub repository for the new app. The repo name should follow the digitalmarketplace-<application-name> pattern.

Setting up a release pipeline

  1. Add application name to the list in the Jenkins dm_application variable.

  2. Add application jobs to the relevant Jenkins job views (eg add release-<application name> to the Release jobs list).

  3. Apply changes to the Jenkins jobs and config.

Setting up PaaS and AWS environment

  1. Add the application name to the end of the list in Terraform app_names variable (in modules/application-logs).

  2. Apply Terraform changes to all environments to create CloudWatch log groups and set up log streaming for the new app.

  3. Define application variables in the digitalmarketplace-aws/vars/common.yml file. For most apps the only things you’ll need are the subdomain and path (the common route prefix) for the new app.

  4. Create a manifest file in digitalmarketplace-aws/paas with the name of the app.

Setting up a local environment

Add the app to digitalmarketplace-runner so that devs can run the app locally.

First deployment

At this point you should be able to run the new Jenkins release job ([Pipeline] <application name>) to deploy the app to the preview environment. You can do this by either running the job manually or merging a PR.

If the application is being split from an existing app then any new requests for the prefixed routes will be handled by the new app.

Once the app is deployed you should check that:

  • App is responding to health checks and status endpoint requests as expected

  • Functional tests are passing

  • Logs are being streamed to CloudWatch and Kibana

  • App functionality that requires specific environment variables to be set is working as expected

Once you’ve confirmed that the app is working as intended you can deploy it to staging and production and remove the routes from the old application.

Once the app is deployed to production for the first time you can add it to the list of apps in the team’s Deploy Lag Radiator.

You should add a Pingdom healthcheck to the app.

Subdomains

The new PaaS app should be automatically assigned a *.cloudapps.digital domain which is mostly intended for internal access but should also be accessible from external IP addresses. New apps that require a publicly accessible subdomain (e.g. for receiving callbacks from external services) should have these requests handled and delegated through the router app so that all regular inbound requests get similar treatment (access control, logging, tracing, sampling behaviour). A few steps will need to be followed for setting up the new subdomain.

  1. Add a new env var to the router app’s paas manifest template pointing to the new app’s *.cloudapps.digital domain.

  2. Add a new server { ... section to the router app’s nginx configuration. This can probably be cloned from the most similar existing app’s section and adapted to needs, but should restrict itself to server_name new-app-name.*; and make any access restrictions it wants to place on its exposed routes. The template should get fed a variable based on the env var previously set in the manifest. This should be used to tell proxy_pass where to direct the new subdomain’s traffic.

  3. Add the subdomain’s DNS record by giving it a section in our terraform config for route53. Again, this will probably be extremely similar to its sibling entries in that file. plan and apply the changes for each environment.

  4. Add the new subdomains to the router’s routes: “vars” so this is picked up when generating the router’s paas manifest.

  5. Add the new subdomain to the CDN_ROUTE_SERVICE_CONF setting in digitalmarketplace-router’s Makefile’s and run make update-cdn-route-service for each environment’s domains. There are a number of other more minor places the subdomains are enumerated in the router app, at time of writing the make test-nginx docker command, the README, docker-compose.yml.example. These should be updated too.

Smoke tests

Add a check of the app’s /_status endpoint to the smoke tests. Unless the app is a frontend, this will require propagating the new app’s domain through the functional tests’ env and jenkins’ ansible vars.