Skip to content

Commit

Permalink
Add composite action for starting a JIMM environment
Browse files Browse the repository at this point in the history
- Use the composite action as part of a basic integration test
  • Loading branch information
kian99 committed Aug 21, 2024
1 parent 970ec0c commit 3be2941
Show file tree
Hide file tree
Showing 15 changed files with 265 additions and 342 deletions.
3 changes: 1 addition & 2 deletions .air.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ tmp_dir = "tmp"

[build]
args_bin = []
bin = "env $(cat /vault/vault.env | xargs) ./tmp/jimm"
cmd = "go build -gcflags='all=-N -l' -buildvcs=false -o ./tmp/jimm ./cmd/jimmsrv"
delay = 1000
exclude_dir = [".vscode", "assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = "env $(cat /vault/vault.env | xargs) dlv exec --accept-multiclient --log --headless --continue --listen :2345 --api-version 2 ./tmp/jimm"
full_bin = "set -a && . /vault/vault.env && . /jimm/test.env && set +a && dlv exec --accept-multiclient --log --headless --continue --listen :2345 --api-version 2 ./tmp/jimm"
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
kill_delay = "0s"
Expand Down
31 changes: 31 additions & 0 deletions .github/actions/test-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# test-server
An action to create a JIMM server with real dependencies for integration test purposes.

This action requires Docker to be installed to start JIMM and its related services.

The action performs the following steps:
- Starts JIMM's docker compose test environment.
- Uses https://github.com/charmed-kubernetes/actions-operator action to start a Juju controller and connects it to JIMM.
- Ensures the local Juju CLI is setup to communicate with JIMM authenticating as a test user.

Use the action by adding the following to a Github workflow:

```yaml
integration-test:
runs-on: ubuntu-latest
name: Integration testing with JIMM
steps:
- name: Setup JIMM environment
uses: canonical/[email protected]
with:
jimm-version: "v3.1.7"
juju-channel: "3/stable"
ghcr-pat: ${{ secrets.GHCR_PAT }}
```
Note that it's recommended to pin the action version to the same version as `jimm-version` to ensure the action works as expected for that specific version of JIMM.

The action accepts the following inputs:
- `jimm-version`: The version of JIMM you want to test against.
- `juju-channel`: The snap channel to use when installing and bootstrapping Juju.
- `ghcr-pat`: A PAT token with package:read access that has access to the `canonical/jimm` repo.
79 changes: 79 additions & 0 deletions .github/actions/test-server/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: JIMM Server Setup
description: "Create a JIMM environment"

inputs:
jimm-version:
description: 'JIMM version tag to use. This will decide the version of JIMM to start e.g. v3.1.7'
required: true
juju-version:
description: 'Juju snap channel to pass to charmed-kubernetes/actions-operator'
required: false
ghcr-pat:
description: 'PAT Token that has package:read access to canonical/JIMM'
required: true

output:
url:
description: 'URL where JIMM can be reached.'
value: "https://jimm.localhost"
client-id:
description: 'Test client ID to login to JIMM with a service account.'
value: "test-client-id"
client-secret:
description: 'Test client Secret to login to JIMM with a service account.'
value: "2M2blFbO4GX4zfggQpivQSxwWX1XGgNf"

runs:
using: "composite"
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ inputs.ghcr-pat }}
- name: Start server and dependencies
run: make integration-test-env
shell: bash
env:
JIMM_VERSION: ${{ inputs.jimm-version }}
- name: Initialise LXD
run: |
sudo lxd waitready && \
sudo lxd init --auto && \
sudo chmod a+wr /var/snap/lxd/common/lxd/unix.socket && \
lxc network set lxdbr0 ipv6.address none && \
sudo usermod -a -G lxd $USER
shell: bash
- name: Setup cloud-init script for bootstraping Juju controllers
run: ./local/jimm/setup-controller.sh
shell: bash
env:
SKIP_BOOTSTRAP: true
CLOUDINIT_FILE: "cloudinit.temp.yaml"
- name: Setup Juju Controller
uses: charmed-kubernetes/actions-operator@main
with:
provider: "lxd"
channel: "5.19/stable"
juju-channel: ${{ inputs.juju-channel }}
bootstrap-options: "--config cloudinit.temp.yaml --config login-token-refresh-url=https://jimm.localhost/.well-known/jwks.json"
- name: Save LXD controller name
id: lxd-controller
run: echo "name=$CONTROLLER_NAME" >> $GITHUB_OUTPUT
shell: bash
- name: Install jimmctl and yq
run: sudo snap install jimmctl --channel=3/stable && sudo snap install yq
shell: bash
- name: Authenticate Juju CLI
run: chmod -R 666 ~/.local/share/juju/*.yaml && ./local/jimm/setup-cli-auth.sh
shell: bash
# Below is a hardcoded JWT using the same test-secret used in JIMM's docker compose and allows the CLI to authenticate as the [email protected] user.
env:
JWT: ZXlKMGVYQWlPaUpLVjFRaUxDSmhiR2NpT2lKSVV6STFOaUo5LmV5SnBjM01pT2lKUGJteHBibVVnU2xkVUlFSjFhV3hrWlhJaUxDSnBZWFFpT2pFM01qUXlNamcyTmpBc0ltVjRjQ0k2TXprMk5EYzFNelEyTUN3aVlYVmtJam9pYW1sdGJTSXNJbk4xWWlJNkltcHBiVzB0ZEdWemRFQmpZVzV2Ym1sallXd3VZMjl0SW4wLkpTWVhXcGF6T0FnX1VFZ2hkbjlOZkVQdWxhWWlJQVdaX3BuSmRDbnJvWEk=
- name: Add LXD Juju controller to JIMM
run: ./local/jimm/add-controller.sh
shell: bash
env:
JIMM_CONTROLLER_NAME: "jimm"
CONTROLLER_NAME: ${{ steps.lxd-controller.outputs.name }}
30 changes: 30 additions & 0 deletions .github/workflows/integration-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Integration Test

on:
workflow_dispatch:
inputs:
jimm-version:
description: >
JIMM version tag to use. This will decide the version of JIMM to start e.g. v3.1.7.
View all available versions at https://github.com/canonical/jimm/pkgs/container/jimm.
required: true

jobs:
startjimm:
name: Start JIMM
runs-on: ubuntu-22.04
steps:
- name: Checkout JIMM repo
uses: actions/checkout@v4
- name: Start JIMM
uses: ./.github/actions/test-server
with:
jimm-version: ${{ inputs.jimm-version }}
juju-channel: "3/stable"
ghcr-pat: ${{ secrets.GITHUB_TOKEN }}
- name: Create a model, deploy an application and run juju status
run: |
juju add-model foo && \
juju deploy haproxy && \
sleep 5 && \
juju status
17 changes: 14 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ dev-env-setup: sys-deps certs
@make version/commit.txt && make version/version.txt

dev-env: dev-env-setup
@docker compose --profile dev up --force-recreate
@docker compose --profile dev up -d --force-recreate --wait

dev-env-cleanup:
@docker compose --profile dev down -v --remove-orphans

integration-test-env: dev-env-setup
@JIMM_VERSION=$(JIMM_VERSION) docker compose --profile test up -d --force-recreate --wait

# Reformat all source files.
format:
gofmt -w -l .
Expand Down Expand Up @@ -116,17 +119,25 @@ define check_dep
fi
endef

# Install packages required to develop JIMM and run tests.
# Install packages required to develop JIMM and/or run tests.
APT_BASED := $(shell command -v apt-get >/dev/null; echo $$?)
sys-deps:
ifeq ($(APT_BASED),0)
# golangci-lint is necessary for linting.
@$(call check_dep,golangci-lint,Missing Golangci-lint - install from https://golangci-lint.run/welcome/install/)
# Go acts as the test runner.
@$(call check_dep,go,Missing Go - install from https://go.dev/doc/install or 'sudo snap install go --classic')
# Git is useful to have.
@$(call check_dep,git,Missing Git - install with 'sudo apt install git')
# GCC is required for the compilation process.
@$(call check_dep,gcc,Missing gcc - install with 'sudo apt install build-essential')
# yq is necessary for some scripts that process controller-info yaml files.
@$(call check_dep,yq,Missing yq - install with 'sudo snap install yq')
@$(call check_dep,gcc,Missing microk8s - install latest none-classic from snapstore')
# Microk8s is required if you want to start a Juju controller on Microk8s.
@$(call check_dep,microk8s,Missing microk8s - install with 'sudo snap install microk8s')
# Docker is required to start the test dependencies in containers.
@$(call check_dep,docker,Missing Docker - install from https://docs.docker.com/engine/install/)
# juju-db is required for tests that use Juju's test fixture, requiring MongoDB.
@$(call check_dep,juju-db.mongo,Missing juju-db - install with 'sudo snap install juju-db --channel=4.4/stable')
else
@echo sys-deps runs only on systems with apt-get
Expand Down
82 changes: 41 additions & 41 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ services:
traefik:
image: "traefik:2.9"
container_name: traefik
profiles: ["dev"]
profiles: ["dev", "test"]
ports:
- "80:80"
- "443:443"
Expand All @@ -19,7 +19,46 @@ services:
interval: 10s
timeout: 5s
retries: 3

# An instance of JIMM used in integration tests, pulled from a tag.
jimm-test:
image: ghcr.io/canonical/jimm:${JIMM_VERSION}
profiles: ["test"]
container_name: jimm-test
ports:
- 17070:80
entrypoint:
- bash
- -c
- >-
apt update && apt install curl -y
&& set -a && . /test.env && . /vault/vault.env && set +a && /usr/local/bin/jimmsrv
volumes:
- ./local/vault/vault.env:/vault/vault.env:rw
- ./test.env:/test.env
healthcheck:
test: [ "CMD", "curl", "http://jimm.localhost:80" ]
interval: 5s
timeout: 5s
retries: 5 # Should fail after approximately (interval*retry) seconds
depends_on:
db:
condition: service_healthy
openfga:
condition: service_healthy
traefik:
condition: service_healthy
insert-hardcoded-auth-model:
condition: service_completed_successfully
keycloak:
condition: service_healthy
labels:
traefik.enable: true
traefik.http.routers.jimm.rule: Host(`jimm.localhost`)
traefik.http.routers.jimm.entrypoints: websecure
traefik.http.routers.jimm.tls: true

# An instance of JIMM used for dev, built from source.
jimm:
image: cosmtrek/air:latest
profiles: ["dev"]
Expand All @@ -36,47 +75,8 @@ services:
ports:
- 17070:80
- 2345:2345
environment:
JIMM_LOG_LEVEL: "debug"
JIMM_UUID: "3217dbc9-8ea9-4381-9e97-01eab0b3f6bb"
JIMM_DSN: "postgresql://jimm:jimm@db/jimm"
# Not needed for local test (yet).
# BAKERY_AGENT_FILE: ""
JIMM_ADMINS: "[email protected]"
# Note: You can comment out the Vault ENV vars below and instead use INSECURE_SECRET_STORAGE to place secrets in Postgres.
VAULT_ADDR: "http://vault:8200"
VAULT_PATH: "/jimm-kv/"
# Note: By default we should use Vault as that is the primary means of secret storage.
# INSECURE_SECRET_STORAGE: "enabled"
# JIMM_DASHBOARD_LOCATION: ""
JIMM_DNS_NAME: "jimm.localhost"
JIMM_LISTEN_ADDR: "0.0.0.0:80"
JIMM_TEST_PGXDSN: "postgresql://jimm:jimm@db/jimm"
JIMM_JWT_EXPIRY: 30s
JIMM_AUDIT_LOG_RETENTION_PERIOD_IN_DAYS: "1"
TEST_LOGGING_CONFIG: ""
BAKERY_PUBLIC_KEY: "izcYsQy3TePp6bLjqOo3IRPFvkQd2IKtyODGqC6SdFk="
BAKERY_PRIVATE_KEY: "ly/dzsI9Nt/4JxUILQeAX79qZ4mygDiuYGqc2ZEiDEc="
OPENFGA_SCHEME: "http"
OPENFGA_HOST: "openfga"
OPENFGA_PORT: 8080
OPENFGA_STORE: "01GP1254CHWJC1MNGVB0WDG1T0"
OPENFGA_AUTH_MODEL: "01GP1EC038KHGB6JJ2XXXXCXKB"
OPENFGA_TOKEN: "jimm"
JIMM_IS_LEADER: true
JIMM_OAUTH_ISSUER_URL: "http://keycloak.localhost:8082/realms/jimm" # Scheme required
JIMM_OAUTH_CLIENT_ID: "jimm-device"
JIMM_OAUTH_CLIENT_SECRET: "SwjDofnbDzJDm9iyfUhEp67FfUFMY8L4"
JIMM_OAUTH_SCOPES: "openid profile email" # Space separated list of scopes
JIMM_DASHBOARD_FINAL_REDIRECT_URL: "https://jaas.ai" # Example URL
JIMM_ACCESS_TOKEN_EXPIRY_DURATION: 1h
JIMM_SECURE_SESSION_COOKIES: false
JIMM_SESSION_COOKIE_MAX_AGE: 86400
JIMM_SESSION_SECRET_KEY: Xz2RkR9g87M75xfoumhEs5OmGziIX8D88Rk5YW8FSvkBPSgeK9t5AS9IvPDJ3NnB
volumes:
- ./:/jimm/
- ./local/vault/approle.json:/vault/approle.json:rw
- ./local/vault/roleid.txt:/vault/roleid.txt:rw
- ./local/vault/vault.env:/vault/vault.env:rw
healthcheck:
test: [ "CMD", "curl", "http://jimm.localhost:80" ]
Expand Down Expand Up @@ -193,7 +193,7 @@ services:
# Adds the auth model and updates its authorisation model id to be the expected hard-coded id such that our local JIMM can utilise it for queries.
# The auth model json is retrieved from file via volume mount.
insert-hardcoded-auth-model:
profiles: ["dev"]
profiles: ["dev", "test"]
image: governmentpaas/psql
container_name: insert-hardcoded-auth-model
volumes:
Expand Down
25 changes: 18 additions & 7 deletions local/jimm/add-controller.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,27 @@ echo "JIMM controller name is: $JIMM_CONTROLLER_NAME"
echo "Target controller name is: $CONTROLLER_NAME"
echo "Target controller path is: $CONTROLLER_YAML_PATH"
echo
echo "Building jimmctl..."
# Build jimmctl so we may add a controller.
go build ./cmd/jimmctl
echo "Built."
echo
which jimmctl
jimmctlAvailable=$?
if [ $jimmctlAvailable -ne 0 ]; then
echo "Building jimmctl..."
# Build jimmctl so we may add a controller.
go build ./cmd/jimmctl
echo "Built jimmctl."
echo
else
echo "jimmctl available, skipping build"
fi
if which jimmctl | grep -q 'snap'; then
CONTROLLER_YAML_PATH="$HOME/snap/jimmctl/common/$CONTROLLER_YAML_PATH"
echo "jimmctl is installed as a snap"
echo "placing controller info file at $CONTROLLER_YAML_PATH"
fi
echo "Switching juju controller to $JIMM_CONTROLLER_NAME"
juju switch "$JIMM_CONTROLLER_NAME"
echo
echo "Retrieving controller info for $CONTROLLER_NAME"
./jimmctl controller-info --local "$CONTROLLER_NAME" "$CONTROLLER_YAML_PATH" --tls-hostname juju-apiserver
jimmctl controller-info --local "$CONTROLLER_NAME" "$CONTROLLER_YAML_PATH" --tls-hostname juju-apiserver
if [[ -f "$CONTROLLER_YAML_PATH" ]]; then
echo "Controller info retrieved."
else
Expand All @@ -38,7 +49,7 @@ else
fi
echo
echo "Adding controller from path: $CONTROLLER_YAML_PATH"
./jimmctl add-controller "$CONTROLLER_YAML_PATH"
jimmctl add-controller "$CONTROLLER_YAML_PATH"
echo
echo "Updating cloud credentials for: $JIMM_CONTROLLER_NAME, from client credential: $CLIENT_CREDENTIAL_NAME"
juju update-credentials "$CLIENT_CREDENTIAL_NAME" --controller "$JIMM_CONTROLLER_NAME"
10 changes: 10 additions & 0 deletions local/jimm/setup-cli-auth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# This script is used to setup a Juju CLI to be authenticated with JIMM without going through login.
# This is particularly useful in headless environments like CI/CD.

set -eux

# Note that we are working around the fact that yq is a snap and doesn't have permission to hidden folders due to snap confinement.
cat ~/.local/share/juju/accounts.yaml | yq '.controllers += {"jimm":{"type": "oauth2-device", "user": "[email protected]", "access-token": strenv(JWT)}}' | cat > temp-accounts.yaml && mv temp-accounts.yaml ~/.local/share/juju/accounts.yaml
cat ~/.local/share/juju/controllers.yaml | yq '.controllers += {"jimm":{"uuid": "3217dbc9-8ea9-4381-9e97-01eab0b3f6bb", "api-endpoints": ["jimm.localhost:443"]}}' | cat > temp-controllers.yaml && mv temp-controllers.yaml ~/.local/share/juju/controllers.yaml
Loading

0 comments on commit 3be2941

Please sign in to comment.