Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: unregister runner using its unique id #39

Merged
merged 1 commit into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .github/workflows/test_spawn_terminate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ jobs:
fail-fast: false
outputs:
runner-aws: ${{ steps.gen-output.outputs.runner_aws }}
runner-aws-id: ${{ steps.gen-output.outputs.runner_aws_id }}
runner-hyperstack: ${{ steps.gen-output.outputs.runner_hyperstack }}
runner-hyperstack-id: ${{ steps.gen-output.outputs.runner_hyperstack_id }}
steps:
- name: Checkout
id: checkout
Expand All @@ -42,6 +44,7 @@ jobs:
id: gen-output
run: |
echo "runner_${{ matrix.provider }}=${{ steps.test-start.outputs.label }}" >> "${GITHUB_OUTPUT}"
echo "runner_${{ matrix.provider }}_id=${{ steps.test-start.outputs.id }}" >> "${GITHUB_OUTPUT}"
test-runner-alive-aws:
name: Test runner is alive (AWS)
Expand All @@ -64,8 +67,8 @@ jobs:
if: ${{ always() && needs.action-start.result != 'skipped' }}
strategy:
matrix:
runner: [ "${{ needs.action-start.outputs.runner-aws }}",
"${{ needs.action-start.outputs.runner-hyperstack }}" ]
runner-id: [ "${{ needs.action-start.outputs.runner-aws-id }}",
"${{ needs.action-start.outputs.runner-hyperstack-id }}" ]
fail-fast: false
steps:
- name: Checkout
Expand All @@ -80,7 +83,7 @@ jobs:
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL_PRE_PROD }}
job-secret: ${{ secrets.JOB_SECRET }}
label: ${{ matrix.runner }}
runner-id: ${{ matrix.runner-id }}

test-runner-removed-aws:
name: Test runner is removed (AWS)
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/test_start_stop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ jobs:
name: GitHub Actions Test (start)
runs-on: ubuntu-latest
needs: [ test-runner-exist ]
outputs:
runner-id: ${{ steps.test-start.outputs.id }}
steps:
- name: Checkout
id: checkout
Expand Down Expand Up @@ -66,7 +68,7 @@ jobs:
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL_PRE_PROD }}
job-secret: ${{ secrets.JOB_SECRET }}
label: ci-persistent-runner
runner-id: ${{ needs.action-start.outputs.runner-id}}

test-runner-persist:
name: Test runner is still registered
Expand Down
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,22 @@ See [below](#example) the YAML code of the depicted workflow.

### Inputs

| Name | Required | Description |
|----------------|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `mode` | Always required. | Specify here which mode you want to use: `start` to start a new runner, `stop` to stop the previously created runner. |
| `github-token` | Always required. | GitHub Personal Access Token with the `repo` scope assigned. |
| `slab-url` | Always required. | URL to Slab CI server. |
| `job-secret` | Always required. | Secret key used by Slab to perform HMAC computation. |
| `backend` | Required with `start` mode. | Backend provider name to look for in slab.toml file in repository that uses the action. |
| `profile` | Required with `start` mode. | Profile to use as described slab.toml file in repository that uses the action. |
| `label` | Required with `stop` mode. | Name of the unique label assigned to the runner.The label is provided by the output of the action in the `start` mode.The label is used to remove the runner from GitHub when the runner is not needed anymore. |
| Name | Required | Description |
|----------------|-----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `mode` | Always required. | Specify here which mode you want to use: `start` to start a new runner, `stop` to stop the previously created runner. |
| `github-token` | Always required. | GitHub Personal Access Token with the `repo` scope assigned. |
| `slab-url` | Always required. | URL to Slab CI server. |
| `job-secret` | Always required. | Secret key used by Slab to perform HMAC computation. |
| `backend` | Required with `start` mode. | Backend provider name to look for in slab.toml file in repository that uses the action. |
| `profile` | Required with `start` mode. | Profile to use as described slab.toml file in repository that uses the action. |
| `runner-id` | Required with `stop` mode. | Unique ID assigned to the runner.The ID is provided by the output of the action in the `start` mode. The ID is used to remove the runner from GitHub when the runner is not needed anymore. |

### Outputs

| Name | Description |
|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `label` | Name of the unique label assigned to the runner. The label is used in two cases: to use as the input of `runs-on` property for the following jobs and to remove the runner from GitHub when it is not needed anymore. |
| Name | Description |
|---------|-------------------------------------------------------------------------------------------------------------------------------------------------|
| `label` | Name of the unique label assigned to the runner. Use `label` as the input of `runs-on` workflow property to run subsequent jobs. |
| `id` | Unique ID assigned to the runner. Use `id` as input of `runner-id` action property remove the runner from GitHub when it is not needed anymore. |

### Examples

Expand All @@ -50,7 +51,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
label: ${{ steps.start-ec2-runner.outputs.label }}
ec2-instance-id: ${{ steps.start-ec2-runner.outputs.ec2-instance-id }}
id: ${{ steps.start-ec2-runner.outputs.id }}
steps:
- name: Start EC2 runner
id: start-ec2-runner
Expand All @@ -62,6 +63,9 @@ jobs:
profile: cpu-test

do-the-job:
needs: start-runner
runs-on: ${{ needs.start-runner.outputs.label }}
steps:
# ... #

stop-runner:
Expand All @@ -77,7 +81,7 @@ jobs:
with:
mode: stop
github-token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}
label: ${{ needs.start-runner.outputs.label }}
runner-id: ${{ needs.start-runner.outputs.id }}
```
## License Summary
Expand Down
14 changes: 8 additions & 6 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,22 @@ inputs:
Profile to use as described slab.toml file in repository that uses the action.
This input is required if you use the 'start' mode.
required: false
label:
runner-id:
description: >-
Name of the unique label assigned to the runner.
The label is used to remove the runner from GitHub when the runner is not needed anymore.
Unique ID assigned to the runner.
The runner ID is used to remove the runner from GitHub when the runner is not needed anymore.
This input is required if you use the 'stop' mode.
required: false

outputs:
label:
description: >-
Name of the unique label assigned to the runner.
The label is used in two cases:
- to use as the input of 'runs-on' property for the following jobs;
- to remove the runner from GitHub when it is not needed anymore.
Use `label` as the input of `runs-on` workflow property to run subsequent jobs.
id:
description: >-
Unique ID assigned to the runner.
Use `id` as input of `runner-id` action property remove the runner from GitHub when it is not needed anymore.
runs:
using: node20
main: ./dist/index.js
23 changes: 13 additions & 10 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Config {
jobSecret: core.getInput('job-secret'),
backend: core.getInput('backend').toLowerCase(),
profile: core.getInput('profile').toLowerCase(),
label: core.getInput('label')
runnerId: core.getInput('runner-id')
}

// the values of github.context.repo.owner and github.context.repo.repo are taken from
Expand Down Expand Up @@ -50,7 +50,7 @@ class Config {
)
}
} else if (this.input.mode === 'stop') {
if (!this.input.label) {
if (!this.input.runnerId) {
throw new Error(
`Not all the required inputs are provided for the 'stop' mode`
)
Expand Down
2 changes: 1 addition & 1 deletion src/gh.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ async function waitForRunnerRegistered(label) {
core.info(
`GitHub self-hosted runner ${runner.name} is registered and ready to use`
)
return
return runner.id
} else {
waitSeconds += retryIntervalSeconds
core.info('Checking...')
Expand Down
11 changes: 7 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ const config = require('./config')
const core = require('@actions/core')
const { waitForRunnerRegistered } = require('./gh')

function setOutput(label) {
function setOutput(label, id) {
core.setOutput('label', label)
core.setOutput('id', id)
}

async function start() {
Expand All @@ -18,14 +19,16 @@ async function start() {
const instance_id = wait_instance_response.start.instance_id
core.info(`${provider} instance started with ID: ${instance_id}`)

setOutput(start_instance_response.runner_name)
const runner_id = await waitForRunnerRegistered(
start_instance_response.runner_name
)

await waitForRunnerRegistered(start_instance_response.runner_name)
setOutput(start_instance_response.runner_name, runner_id)
}

async function stop() {
const stop_instance_response = await slab.terminateInstanceRequest(
config.input.label
config.input.runnerId
)
await slab.waitForInstance(stop_instance_response.task_id, 'stop')
Comment on lines 29 to 33
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's fully breaking, is that what we discussed ?

Copy link
Contributor Author

@soonum soonum Dec 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fully breaking but older version of the action can still be used. It's breaking from action point of view but Slab handle the backward compatibility.


Expand Down
6 changes: 3 additions & 3 deletions src/slab.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ async function waitForInstance(taskId, taskName) {
}
}

async function terminateInstanceRequest(runnerName) {
async function terminateInstanceRequest(runnerId) {
const url = config.input.slabUrl

const payload = {
runner_name: runnerName,
runner_id: parseInt(runnerId, 10),
action: 'terminate',
sha: config.githubContext.sha,
git_ref: config.githubContext.ref
Expand All @@ -117,7 +117,7 @@ async function terminateInstanceRequest(runnerName) {
const signature = getSignature(body)

try {
core.info(`Request instance termination (runner: ${runnerName})`)
core.info(`Request instance termination (runner ID: ${runnerId})`)

const response = await fetch(concat_path(url, 'job'), {
method: 'POST',
Expand Down
Loading