From bcc8f32498ad2ed89929ed7f082ec21ef8707d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Test=C3=A9?= Date: Thu, 14 Nov 2024 16:11:42 +0100 Subject: [PATCH] feat!: unregister runner using its unique id BREAKING CHANGE: runner name cannot be used anymore to remove it from GitHub platform. A runner can be removed directly, through the REST API, using its ID. This change has been made to avoid Slab server to fetch all registered runners before being able to filter by name and finally find ID of the runner to remove. --- .github/workflows/ci.yml | 2 +- README.md | 32 ++++++++++++++++++-------------- action.yaml | 14 ++++++++------ dist/index.js | 27 +++++++++++++++------------ src/config.js | 4 ++-- src/gh.js | 6 +++--- src/index.js | 11 +++++++---- src/slab.js | 6 +++--- 8 files changed, 57 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7a8789..97205de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,4 +75,4 @@ jobs: github-token: ${{ secrets.SLAB_ACTION_TOKEN }} slab-url: ${{ secrets.SLAB_BASE_URL_PRE_PROD }} job-secret: ${{ secrets.JOB_SECRET }} - label: ${{ steps.test-start.outputs.label }} + runner-id: ${{ steps.test-start.outputs.id }} diff --git a/README.md b/README.md index b60db35..6708695 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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 @@ -62,6 +63,9 @@ jobs: profile: cpu-test do-the-job: + needs: start-runner + runs-on: ${{ needs.start-runner.outputs.label }} + steps: # ... # stop-runner: @@ -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 diff --git a/action.yaml b/action.yaml index 041f8d3..8707557 100644 --- a/action.yaml +++ b/action.yaml @@ -33,10 +33,10 @@ 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 @@ -44,9 +44,11 @@ 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 diff --git a/dist/index.js b/dist/index.js index ea7be2e..296e699 100644 --- a/dist/index.js +++ b/dist/index.js @@ -49570,7 +49570,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 @@ -49610,7 +49610,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` ) @@ -49653,7 +49653,7 @@ async function getRunner(label) { repo: config.githubContext.repo } ) - const foundRunners = _.filter(runners, { labels: [{ name: label }] }) + const foundRunners = _.filter(runners, { name: label }) return foundRunners.length > 0 ? foundRunners[0] : null } catch (error) { return null @@ -49671,7 +49671,7 @@ async function waitForRunnerRegistered(label) { ) await utils.sleep(quietPeriodSeconds) core.info( - `Checking every ${retryIntervalSeconds}s if the GitHub self-hosted runner is registered` + `Checking every ${retryIntervalSeconds}s if the GitHub self-hosted runner ${label} is registered` ) while (waitSeconds < timeoutSeconds) { @@ -49681,7 +49681,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...') @@ -49811,11 +49811,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: runnerId, action: 'terminate', sha: config.githubContext.sha, git_ref: config.githubContext.ref @@ -49825,7 +49825,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', @@ -51851,8 +51851,9 @@ const config = __nccwpck_require__(4570) const core = __nccwpck_require__(2186) const { waitForRunnerRegistered } = __nccwpck_require__(6989) -function setOutput(label) { +function setOutput(label, id) { core.setOutput('label', label) + core.setOutput('id', id) } async function start() { @@ -51866,14 +51867,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') diff --git a/src/config.js b/src/config.js index 6518b4a..3158444 100644 --- a/src/config.js +++ b/src/config.js @@ -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 @@ -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` ) diff --git a/src/gh.js b/src/gh.js index 0f1455e..e72a9c3 100644 --- a/src/gh.js +++ b/src/gh.js @@ -17,7 +17,7 @@ async function getRunner(label) { repo: config.githubContext.repo } ) - const foundRunners = _.filter(runners, { labels: [{ name: label }] }) + const foundRunners = _.filter(runners, { name: label }) return foundRunners.length > 0 ? foundRunners[0] : null } catch (error) { return null @@ -35,7 +35,7 @@ async function waitForRunnerRegistered(label) { ) await utils.sleep(quietPeriodSeconds) core.info( - `Checking every ${retryIntervalSeconds}s if the GitHub self-hosted runner is registered` + `Checking every ${retryIntervalSeconds}s if the GitHub self-hosted runner ${label} is registered` ) while (waitSeconds < timeoutSeconds) { @@ -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...') diff --git a/src/index.js b/src/index.js index 145c921..c9e45e5 100644 --- a/src/index.js +++ b/src/index.js @@ -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() { @@ -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') diff --git a/src/slab.js b/src/slab.js index faee347..d031c2e 100644 --- a/src/slab.js +++ b/src/slab.js @@ -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: runnerId, action: 'terminate', sha: config.githubContext.sha, git_ref: config.githubContext.ref @@ -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',