Skip to content

Commit 6b5bae1

Browse files
authored
feat: add terraform machine input w/ tf tests (#707)
* test: add terraform tests * test: terraform module testing * fix: add terraform required versions (tflint) * ci: fix terraform working dir * test: fix tf module source dir * test: add test-model * docs: add changelog * docs: fix typo
1 parent f69fb60 commit 6b5bae1

12 files changed

Lines changed: 311 additions & 3 deletions

File tree

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Copyright 2025 Canonical Ltd.
2+
# See LICENSE file for licensing details.
3+
4+
name: Terraform lint test
5+
6+
on:
7+
pull_request:
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
detect-changes:
14+
runs-on: ubuntu-latest
15+
outputs:
16+
terraform: ${{ steps.filter.outputs.terraform }}
17+
steps:
18+
- uses: actions/checkout@v6.0.1
19+
- uses: dorny/paths-filter@v3
20+
id: filter
21+
with:
22+
filters: |
23+
terraform:
24+
- "**/terraform/**"
25+
26+
validate:
27+
needs: detect-changes
28+
if: needs.detect-changes.outputs.terraform == 'true'
29+
name: Validate terraform configuration files
30+
runs-on: ubuntu-latest
31+
env:
32+
WORKING_DIR: "terraform/"
33+
steps:
34+
- name: Check out code
35+
uses: actions/checkout@v6.0.1
36+
37+
- name: Setup Terraform
38+
uses: hashicorp/setup-terraform@v3.1.2
39+
40+
- name: Run terraform fmt
41+
run: terraform fmt -check -recursive
42+
working-directory: ${{env.WORKING_DIR}}
43+
44+
- name: Setup Tflint
45+
uses: terraform-linters/setup-tflint@v6.2.1
46+
with:
47+
tflint_wrapper_enabled: true
48+
49+
- name: Run tflint
50+
run: |
51+
tflint --version
52+
tflint --init
53+
tflint -f compact --recursive
54+
working-directory: ${{env.WORKING_DIR}}
55+
56+
terraform-lint-status-check:
57+
runs-on: ubuntu-latest
58+
needs: [detect-changes, validate]
59+
if: always()
60+
steps:
61+
- name: Check terraform lint results
62+
run: |
63+
# If linting was skipped because no changes, that's success
64+
if [ "${{ needs.detect-changes.outputs.terraform }}" != "true" ]; then
65+
echo "No terraform changes detected, skipping lint is expected"
66+
exit 0
67+
fi
68+
69+
# If lint ran, check its results
70+
validate_result="${{ needs.validate.result }}"
71+
72+
echo "Terraform lint result: $validate_result"
73+
74+
# Fail if lint that ran actually failed (not skipped)
75+
if [ "$validate_result" = "failure" ]; then
76+
echo "Terraform lint failed"
77+
exit 1
78+
fi
79+
80+
echo "Terraform lint passed or was skipped appropriately"
81+
exit 0
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Copyright 2025 Canonical Ltd.
2+
# See LICENSE file for licensing details.
3+
4+
name: Terraform module tests
5+
6+
on:
7+
pull_request:
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
detect-changes:
14+
runs-on: ubuntu-latest
15+
outputs:
16+
terraform: ${{ steps.filter.outputs.terraform }}
17+
steps:
18+
- uses: actions/checkout@v6.0.1
19+
- uses: dorny/paths-filter@v3
20+
id: filter
21+
with:
22+
filters: |
23+
terraform:
24+
- "**/terraform/**"
25+
26+
test-terraform:
27+
needs: detect-changes
28+
if: needs.detect-changes.outputs.terraform == 'true'
29+
name: Test Terraform with Juju
30+
runs-on: self-hosted-linux-amd64-noble-edge
31+
env:
32+
WORKING_DIR: "terraform/charm/tests"
33+
steps:
34+
- uses: actions/checkout@v6.0.1
35+
- uses: charmed-kubernetes/actions-operator@main
36+
with:
37+
provider: "lxd"
38+
juju-channel: 3.6/stable
39+
- name: Prepare juju tf provider environment
40+
run: |
41+
set -e
42+
CONTROLLER=$(juju whoami | yq .Controller)
43+
JUJU_CONTROLLER_ADDRESSES="$(juju show-controller | yq '.[$CONTROLLER]'.details.\"api-endpoints\" | tr -d "[]' "|tr -d '"'|tr -d '\n')"
44+
JUJU_USERNAME="$(cat ~/.local/share/juju/accounts.yaml | yq .controllers.$CONTROLLER.user|tr -d '"')"
45+
JUJU_PASSWORD="$(cat ~/.local/share/juju/accounts.yaml | yq .controllers.$CONTROLLER.password|tr -d '"')"
46+
47+
echo "JUJU_CONTROLLER_ADDRESSES=$JUJU_CONTROLLER_ADDRESSES" >> "$GITHUB_ENV"
48+
echo "JUJU_USERNAME=$JUJU_USERNAME" >> "$GITHUB_ENV"
49+
echo "JUJU_PASSWORD=$JUJU_PASSWORD" >> "$GITHUB_ENV"
50+
{
51+
echo 'JUJU_CA_CERT<<EOF'
52+
juju show-controller $(echo $CONTROLLER|tr -d '"') | yq '.[$CONTROLLER]'.details.\"ca-cert\"|tr -d '"'
53+
echo EOF
54+
} >> "$GITHUB_ENV"
55+
- run: juju add-model test-github-runner
56+
- uses: hashicorp/setup-terraform@v3.1.2
57+
- run: terraform init
58+
working-directory: ${{env.WORKING_DIR}}
59+
- run: terraform validate
60+
working-directory: ${{env.WORKING_DIR}}
61+
- run: terraform plan -out=tfplan
62+
working-directory: ${{env.WORKING_DIR}}
63+
- run: terraform show tfplan
64+
working-directory: ${{env.WORKING_DIR}}
65+
- run: terraform test
66+
working-directory: ${{env.WORKING_DIR}}
67+
68+
terraform-status-check:
69+
runs-on: ubuntu-latest
70+
needs: [detect-changes, test-terraform]
71+
if: always()
72+
steps:
73+
- name: Check terraform test results
74+
run: |
75+
# If tests were skipped because no changes, that's success
76+
if [ "${{ needs.detect-changes.outputs.terraform }}" != "true" ]; then
77+
echo "No terraform changes detected, skipping tests is expected"
78+
exit 0
79+
fi
80+
81+
# If tests ran, check their results
82+
test_result="${{ needs.test-terraform.result }}"
83+
84+
echo "Terraform test result: $test_result"
85+
86+
# Fail if test that ran actually failed (not skipped)
87+
if [ "$test_result" = "failure" ]; then
88+
echo "Terraform tests failed"
89+
exit 1
90+
fi
91+
92+
echo "Terraform tests passed or were skipped appropriately"
93+
exit 0

docs/changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
This changelog documents user-relevant changes to the GitHub runner charm.
44

5+
## 2025-01-26
6+
7+
- Add machine input parameter for terraform charm module to allow targeting specific machines for
8+
GitHub runner application deployment.
9+
510
## 2025-01-14
611

712
- Add support for running up to 100 multiple GitHub runner applications on a single instance.

terraform/charm/main.tf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ resource "juju_application" "github_runner" {
1414

1515
config = var.config
1616
constraints = var.constraints
17-
units = var.units
17+
machines = var.machines
18+
units = var.machines == null ? var.units : null
1819
}

terraform/charm/outputs.tf

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,21 @@ output "app_name" {
66
value = juju_application.github_runner.name
77
}
88

9+
output "model" {
10+
description = "Model the application is deployed to."
11+
value = juju_application.github_runner.model
12+
}
13+
14+
output "machines" {
15+
description = "Set of machine IDs the application is placed on (if any)."
16+
value = juju_application.github_runner.machines
17+
}
18+
19+
output "units" {
20+
description = "Number of units to deploy when machines are not provided."
21+
value = juju_application.github_runner.units
22+
}
23+
924
output "requires" {
1025
value = {
1126
debug_ssh = "debug-ssh"

terraform/charm/tests/main.tf

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Copyright 2026 Canonical Ltd.
2+
# See LICENSE file for licensing details.
3+
4+
terraform {
5+
required_version = ">= 1.6.6"
6+
required_providers {
7+
juju = {
8+
source = "juju/juju"
9+
version = "0.23.3"
10+
}
11+
}
12+
}
13+
14+
provider "juju" {}
15+
16+
resource "juju_model" "test_model" {
17+
name = "test-model"
18+
}
19+
20+
# Provision a machine and reuse its ID in module placements
21+
resource "juju_machine" "m0" {
22+
model = juju_model.test_model.name
23+
base = "ubuntu@22.04"
24+
name = "machine_0"
25+
}
26+
27+
# Scenario: two applications deployed on a single machine
28+
module "runner_a" {
29+
source = "./.."
30+
app_name = "github-runner-a"
31+
model = juju_model.test_model.name
32+
channel = "latest/edge"
33+
revision = null
34+
base = "ubuntu@22.04"
35+
units = 1
36+
machines = [juju_machine.m0.machine_id]
37+
config = {}
38+
constraints = ""
39+
}
40+
41+
module "runner_b" {
42+
source = "./.."
43+
app_name = "github-runner-b"
44+
model = juju_model.test_model.name
45+
channel = "latest/edge"
46+
revision = null
47+
base = "ubuntu@22.04"
48+
units = 1
49+
machines = [juju_machine.m0.machine_id]
50+
config = {}
51+
constraints = ""
52+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright 2026 Canonical Ltd.
2+
# See LICENSE file for licensing details.
3+
4+
run "two_apps_one_machine" {
5+
module {
6+
source = "./."
7+
}
8+
command = apply
9+
10+
# runner_a assertions
11+
assert {
12+
condition = module.runner_a.app_name == "github-runner-a"
13+
error_message = "runner_a name should match"
14+
}
15+
16+
assert {
17+
condition = module.runner_a.model == "test-model"
18+
error_message = "runner_a model should pass through"
19+
}
20+
21+
assert {
22+
condition = module.runner_a.machines == toset([juju_machine.m0.machine_id])
23+
error_message = "runner_a should be placed on the created machine"
24+
}
25+
26+
assert {
27+
condition = module.runner_a.units == 1
28+
error_message = "units should be equal to number of machines are provided (runner_a)"
29+
}
30+
31+
# runner_b assertions
32+
assert {
33+
condition = module.runner_b.app_name == "github-runner-b"
34+
error_message = "runner_b name should match"
35+
}
36+
37+
assert {
38+
condition = module.runner_b.model == "test-model"
39+
error_message = "runner_b model should pass through"
40+
}
41+
42+
assert {
43+
condition = module.runner_b.machines == toset([juju_machine.m0.machine_id])
44+
error_message = "runner_b should be placed on the created machine"
45+
}
46+
47+
assert {
48+
condition = module.runner_b.units == 1
49+
error_message = "units should be equal to number of machines are provided (runner_b)"
50+
}
51+
}

terraform/charm/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,9 @@ variable "units" {
4848
type = number
4949
default = 1
5050
}
51+
52+
variable "machines" {
53+
description = "Optional set of target machine IDs to place units on. Mutually exclusive with units; if set, units is ignored."
54+
type = set(string)
55+
default = null
56+
}

terraform/charm/versions.tf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ terraform {
55
required_providers {
66
juju = {
77
source = "juju/juju"
8-
version = ">= 0.11.0"
8+
version = ">= 0.23.3, < 1.0.0"
99
}
1010
}
11+
required_version = ">= 1.0.0"
1112
}

terraform/product/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module "github_runner" {
1717
revision = each.value.revision
1818
base = each.value.base
1919
units = each.value.units
20+
machines = try(each.value.machines, null)
2021
}
2122

2223
module "github_runner_image_builder" {

0 commit comments

Comments
 (0)