Skip to content

Commit

Permalink
2024-update (#32)
Browse files Browse the repository at this point in the history
* Most packages updated

* Switch from Azure AD to Entra

* Switch testing to httpyac

* CI woes

* Test output woes

* Updating GH actions

* Fix forced test fail

* Azure deploy fixes

* Updates to release

* Some more polish

* Readme fixes

* Turned out prettier was never configured correctly
  • Loading branch information
benc-uk authored Oct 10, 2024
1 parent 3777659 commit a59a8b4
Show file tree
Hide file tree
Showing 30 changed files with 4,302 additions and 8,631 deletions.
25 changes: 13 additions & 12 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
{
"name": "Node.js",
"image": "mcr.microsoft.com/vscode/devcontainers/javascript-node:16-bullseye",
"image": "mcr.microsoft.com/vscode/devcontainers/javascript-node:20-bullseye",

// Set *default* container specific settings.json values on container create.
"settings": {},

// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"mikestead.dotenv",
"ms-azuretools.vscode-bicep",
"github.vscode-pull-request-github"
],
"customizations": {
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"mikestead.dotenv",
"ms-azuretools.vscode-bicep",
"github.vscode-pull-request-github"
]
}
},

// Optional features, uncomment to enable.
// See https://code.visualstudio.com/docs/remote/containers#_dev-container-features-preview
Expand Down
11 changes: 5 additions & 6 deletions .github/workflows/cd-release-aks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:

steps:
- name: 'Checkout'
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: 'Set kubeconfig'
uses: azure/k8s-set-context@v1
Expand All @@ -49,7 +49,7 @@ jobs:
helm upgrade ${{ env.HELM_RELEASE }} benc-uk/webapp \
--install \
--namespace ${{ env.HELM_NAMESPACE }} \
--values deploy/kubernetes/aks-live.yaml \
--values deploy/kubernetes/aks-mine.yaml \
--set image.tag=${{ github.event.inputs.IMAGE_TAG }},ingress.host=${{ env.INGRESS_DNS_HOST }},env.AAD_REDIRECT_URL_BASE=https://${{ env.INGRESS_DNS_HOST }}
#
Expand All @@ -65,12 +65,11 @@ jobs:

steps:
- name: 'Checkout'
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: 'Validate site is running'
run: .github/scripts/url-check.sh -u https://${{ env.INGRESS_DNS_HOST }} -s "Node.js Demo App" -t 200

- name: 'Run API tests'
- name: 'Integration tests'
run: |
npm install newman --silent
node_modules/newman/bin/newman.js run src/tests/postman_collection.json --global-var apphost=${{ env.INGRESS_DNS_HOST }}
make test TEST_BASE_URL=https://${{ env.INGRESS_DNS_HOST }} "TEST_FILES={base-tests,weather-tests}.http"
35 changes: 24 additions & 11 deletions .github/workflows/ci-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,50 @@ env:

permissions:
packages: write
statuses: write
checks: write

jobs:
test:
name: 'Tests & Linting'
runs-on: ubuntu-latest
steps:
- name: 'Checkout'
uses: actions/checkout@v2
uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: 'Run linting'
run: make lint

- name: 'Run service'
run: make run &

- name: 'Run tests'
run: make test-report
run: |
sleep 5
make test-report
- name: 'Upload test results'
uses: actions/upload-artifact@v2
# Disabled when running locally with the nektos/act tool
if: ${{ always() }}
- name: 'Test reporting'
uses: phoenix-actions/test-reporting@v8
id: test-report
if: success() || failure()
with:
name: test-results
path: ./src/mochawesome-report
name: Integration Test Report
path: test-results.xml
reporter: java-junit
fail-on-error: false

build:
name: 'Build & Push Image'
name: 'Build & push image'
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
steps:
- name: 'Checkout'
uses: actions/checkout@v2
uses: actions/checkout@v4

# Nicer than using github runid, I think, will be picked up automatically by make
- name: 'Create datestamp image tag'
Expand All @@ -54,7 +68,6 @@ jobs:

# Only when pushing to default branch (e.g. master or main), then push image to registry
- name: 'Push to container registry'
if: github.ref == 'refs/heads/master' && github.event_name == 'push'
run: |
echo ${{ secrets.GITHUB_TOKEN }} | docker login $IMAGE_REG -u $GITHUB_ACTOR --password-stdin
make push
Expand Down
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
node_modules/
*.log
.env
src/test-*.xml
src/test-*.json
**/test-*.xml
mochawesome-report/
myvalues.yaml
secrets.sh
Expand Down
95 changes: 53 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Node.js - Demo Web Application
# Node.js - Sample Web Application

This is a simple Node.js web app using the Express framework and EJS templates.
This is a sample Node.js web app using the Express framework and EJS templates.

The app has been designed with cloud native demos & containers in mind, in order to provide a real working application for deployment, something more than "hello-world" but with the minimum of pre-reqs. It is not intended as a complete example of a fully functioning architecture or complex software design.

Expand All @@ -15,19 +15,15 @@ The app has several basic pages accessed from the top navigation menu, some of w
- **'Todo'** - (Optional) This is a small todo/task-list app which uses MongoDB as a database.
- **'User Account'** - (Optional) When configured with Azure AD (application client id) user login button will be enabled, and an user-account details page enabled, which calls the Microsoft Graph API

![screen](https://user-images.githubusercontent.com/14982936/55620043-dfe96480-5791-11e9-9746-3b42a3a41e5f.png)
![screen](https://user-images.githubusercontent.com/14982936/55620045-dfe96480-5791-11e9-94f3-6d788ed447c1.png)
![screen](https://user-images.githubusercontent.com/14982936/58764072-d8102b80-855a-11e9-993f-21ef0344d5e0.png)

# Status

![](https://img.shields.io/github/last-commit/benc-uk/nodejs-demoapp) ![](https://img.shields.io/github/release-date/benc-uk/nodejs-demoapp) ![](https://img.shields.io/github/v/release/benc-uk/nodejs-demoapp) ![](https://img.shields.io/github/commit-activity/y/benc-uk/nodejs-demoapp)

Live instance:
## Screens

[![](https://img.shields.io/website?label=Hosted%3A%20Kubernetes&up_message=online&url=https%3A%2F%2Fnodejs-demoapp.kube.benco.io%2F)](https://nodejs-demoapp.kube.benco.io/)
![screen](https://user-images.githubusercontent.com/14982936/55620043-dfe96480-5791-11e9-9746-3b42a3a41e5f.png)
![screen](https://user-images.githubusercontent.com/14982936/55620045-dfe96480-5791-11e9-94f3-6d788ed447c1.png)
![screen](https://user-images.githubusercontent.com/14982936/58764072-d8102b80-855a-11e9-993f-21ef0344d5e0.png)

# Running and Testing Locally
# 🧑‍💻 Running and Testing Locally

### Pre-reqs

Expand Down Expand Up @@ -57,25 +53,26 @@ push 📤 Push container image to registry
run 🏃 Run locally using Node.js
deploy 🚀 Deploy to Azure Container App
undeploy 💀 Remove from Azure
test 🎯 Unit tests with Jest
test-report 🤡 Unit tests with Jest & Junit output
test-api 🚦 Run integration API tests, server must be running
test 🚦 Run integration tests, server must be running
test-report 🤡 Tests but with JUnit output, server must be running
clean 🧹 Clean up project
```

Make file variables and default values, pass these in when calling `make`, e.g. `make image IMAGE_REPO=blah/foo`

| Makefile Variable | Default |
| ----------------- | ---------------------- |
| IMAGE_REG | ghcr<span>.</span>io |
| IMAGE_REPO | benc-uk/nodejs-demoapp |
| IMAGE_TAG | latest |
| AZURE_RES_GROUP | demoapps |
| AZURE_REGION | northeurope |
| Makefile Variable | Default |
| ----------------- | ---------------------------------- |
| IMAGE_REG | ghcr<span>.</span>io |
| IMAGE_REPO | benc-uk/nodejs-demoapp |
| IMAGE_TAG | latest |
| AZURE_RES_GROUP | demoapps |
| AZURE_REGION | northeurope |
| TEST_BASE_URL | http://<span>localhost</span>:3000 |
| TEST_FILES | base-tests.http |

Web app will be listening on the standard Express port of 3000, but this can be changed by setting the `PORT` environmental variable.
The web app will be listening on the standard Express port of 3000, but this can be changed by setting the `PORT` environmental variable.

# Containers
# 📦 Containers

Public container image is [available on GitHub Container Registry](https://github.com/users/benc-uk/packages/container/package/nodejs-demoapp).

Expand All @@ -91,21 +88,33 @@ Should you want to build your own container, use `make image` and the above vari

The app can easily be deployed to Kubernetes using Helm, see [deploy/kubernetes/readme.md](deploy/kubernetes/readme.md) for details

# GitHub Actions CI/CD
# 🏗️ GitHub Actions CI/CD

A set of GitHub Actions workflows are included for CI / CD. Automated builds for PRs are run in GitHub hosted runners validating the code (linting and tests) and building dev images. When code is merged into main, then automated deployment to AKS is done using Helm.

[![CD Release - AKS](https://github.com/benc-uk/nodejs-demoapp/actions/workflows/cd-release-aks.yaml/badge.svg)](https://github.com/benc-uk/nodejs-demoapp/actions/workflows/cd-release-aks.yaml)

# 🧪 Testing

This project uses a HTTP files located in `src/tests/` that can be used a few different ways, you can install the [VSCode REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) or [httpYac](https://marketplace.visualstudio.com/items?itemName=anweber.vscode-httpyac) allowing you to interactively run requests from VSCode

You can interactively run & send the requests in the `src/tests` file using these extensions, but the main reason to use _httpYac_, is it has a much richer language & the support of assertions which can turn the request files into integration tests too 👌

_httpYac_ has a command line tool for running tests and .http files which forms the basis of the `make test` and `make test-report` makefile targets.

A set of GitHub Actions workflows are included for CI / CD. Automated builds for PRs are run in GitHub hosted runners validating the code (linting and tests) and building dev images. When code is merged into master, then automated deployment to AKS is done using Helm.
## Running Tests

[![](https://img.shields.io/github/workflow/status/benc-uk/nodejs-demoapp/CI%20Build%20App)](https://github.com/benc-uk/nodejs-demoapp/actions?query=workflow%3A%22CI+Build+App%22) [![](https://img.shields.io/github/workflow/status/benc-uk/nodejs-demoapp/CD%20Release%20-%20AKS?label=release-kubernetes)](https://github.com/benc-uk/nodejs-demoapp/actions?query=workflow%3A%22CD+Release+-+AKS%22)
To run the tests, in one shell session run `make run` and open a second separate shell run `make test`. You can set `TEST_BASE_URL` to point the tests at a different URL, host or port, and set `TEST_FILES` to a glob that matches the files you want to run from the src/tests/ directory.

# Optional Features
# 🎂 Optional Features

The app will start up and run with zero configuration, however the only features that will be available will be the INFO and TOOLS views. The following optional features can be enabled:
The app will start up and run with zero configuration, however the following optional features can be enabled with various settings

### Application Insights
### Monitoring - Azure Application Insights

Enable this by setting `APPLICATIONINSIGHTS_CONNECTION_STRING`

The app has been instrumented with the Application Insights SDK, it will however need to be configured to point to your App Insights instance/workspace. All requests will be tracked, as well as dependant calls to MongoDB or other APIs (if configured), exceptions & error will also be logged
The app has been instrumented with the Application Insights SDK, it will however need to be configured to point to your App Insights instance/workspace. All requests will be tracked, as well as dependant calls to MongoDB or other APIs (if configured), exceptions & error will also be logged.

[This article](https://docs.microsoft.com/azure/application-insights/app-insights-nodejs) has more information on monitoring Node.js with App Insights

Expand All @@ -116,19 +125,19 @@ Enable this by setting `WEATHER_API_KEY`
This will require a API key from OpenWeather, you can [sign up for free and get one here](https://openweathermap.org/price). The page uses a browser API for geolocation to fetch the user's location.
However, the `geolocation.getCurrentPosition()` browser API will only work when the site is served via HTTPS or from localhost. As a fallback, weather for London, UK will be show if the current position can not be obtained

### User Authentication with Azure AD
### Authentication with Microsoft Entra ID (was Azure AD)

Enable this by setting `AAD_APP_ID`
Enable this by setting `ENTRA_APP_ID`

This uses [Microsoft Authentication Library (MSAL) for Node](https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/lib/msal-node) to authenticate via MSAL with OIDC and OAuth 2.0. The flow it uses is the "Authorization Code Grant (PKCE)", which means we can sign in users without needing client secrets

In addition the user account page shows details & photo retrieved from the Microsoft Graph API
When enabled a user account page becomes available in the UI, this shows logged in user details & photo retrieved from the Microsoft Graph API.

You will need to register an app in your Azure AD tenant. The app should be configured for the PKCE flow, if creating the app via the portal select **_Public client/native (mobile & desktop)_** (ignore the fact this doesn't seem the right option for a web app)
You will need to register an app in your Entra ID tenant. The app should be configured for the PKCE flow, if creating the app via the portal select **_Public client/native (mobile & desktop)_** (ignore the fact this doesn't seem the right option for a web app)

When configuring authentication the redirect URL will be the host where the app is running with `/signin` as the URL path, e.g. `https://myapp.azurewebsites.net/signin`, for local testing use `http://localhost:3000/signin`

For the signin audience select **_Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)_**
For the sign-in audience (also called account types) select **_Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)_**

To simplify the registration, the Azure CLI can be used with the following bash snippet:

Expand All @@ -143,7 +152,7 @@ clientId=$(az ad app create \
--query appId -o tsv)
# Create a service principal for the application
az ad sp create --id $clientId -o json
echo -e "\n### Set env var AAD_APP_ID to '$clientId'"
echo -e "\n### Set env var ENTRA_APP_ID to '$clientId'"
```

### Todo App
Expand All @@ -154,31 +163,33 @@ A mini todo & task tracking app can be enabled if a MongoDB backend is provided

The default database name is `todoDb` but you can change this by setting `TODO_MONGO_DB`

You can stand up MongoDB in a container instance or in Cosmos DB (using the Mongo API). Note. When using Cosmos DB and the _per database provisioned RU/s_ option, you must manually create the collection called `todos` in the relevant database and set the shard key to `_id`
When working locally and if you have Docker, you can easily run MongoDB with `docker run --network host mongo`
You can also use Azure Cosmos DB (using the Mongo API). Note. When using Cosmos DB and the _per database provisioned RU/s_ option, you must manually create the collection called `todos` in the relevant database and set the shard key to `_id`

# Configuration
# 🛠️ Configuration

The following configuration environmental variables are supported, however none are mandatory. These can be set directly or when running locally will be picked up from an `.env` file if it is present. A sample `.env` file called `.env.sample` is provided for you to copy

If running in an Azure Web App, all of these values can be injected as application settings in Azure.
If running in an Azure Web App or Azure Container App, all of these values can be injected as application settings in Azure.

| Environmental Variable | Default | Description |
| ------------------------------------- | ------- | -------------------------------------------------------------------------------- |
| PORT | 3000 | Port the server will listen on |
| TODO_MONGO_CONNSTR | _none_ | Connect to specified MongoDB instance, when set the todo feature will be enabled |
| TODO_MONGO_DB | todoDb | Name of the database in MongoDB to use (optional) |
| APPINSIGHTS_CONNECTION_STRING | _none_ | Enable AZure Application Insights monitoring |
| APPLICATIONINSIGHTS_CONNECTION_STRING | _none_ | Enable Azure Application Insights monitoring |
| WEATHER_API_KEY | _none_ | OpenWeather API key. [Info here](https://openweathermap.org/api) |
| AAD_APP_ID | _none_ | Client ID of app registered in Azure AD |
| ENTRA_APP_ID | _none_ | Client ID of app registered in Microsoft Entra |
| DISABLE_METRICS | _none_ | Set to truthy value if you want to switch off Prometheus metrics |
| REDIS_SESSION_HOST | _none_ | Point to a Redis host to hold/persist session cache |

## Deployment

See [deployment folder](./deploy) for deploying into Kubernetes with Helm or into Azure with Bicep and Container Apps.

# Updates
# 📆 Updates

- Oct 2024 - Major package refresh & compatibility updates
- Oct 2022 - Update App Insights, track custom events
- Sept 2022 - Add Prometheus metrics
- Aug 2022 - Switch to PKCE for auth & login flow
Expand Down
4 changes: 2 additions & 2 deletions build/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
ARG ARCH=
ARG IMAGE_BASE=16-alpine
ARG IMAGE_BASE=20-alpine

FROM ${ARCH}node:$IMAGE_BASE
LABEL Name="Node.js Demo App" Version=4.8.5
LABEL Name="Node.js Demo App" Version=4.9.8
LABEL org.opencontainers.image.source = "https://github.com/benc-uk/nodejs-demoapp"
ENV NODE_ENV production
WORKDIR /app
Expand Down
Loading

0 comments on commit a59a8b4

Please sign in to comment.