Skip to content

Commit

Permalink
Added support to wait for instance not busy (#2)
Browse files Browse the repository at this point in the history
* extended github action by adding multiple labels and multiple self-hosted ec2 capability

* test 1 of new action

* added new input

* solved comments

* added support to wait for instance not busy

* moved the waiting for not busy

* added logging to debug code

* index.js synthetized

* Update gh

* Update dist

* Update runnersNotBusy

* Update AreRunnersOnline

* update index

* .

* .

* .

* .

* Add hash (#3)

* Add hash

* test16

* update dist

* release 18

* update substr

* update dist

* fix lint error

---------

Co-authored-by: marcosmicJack <[email protected]>
Co-authored-by: Marcos Alarcón <[email protected]>
  • Loading branch information
3 people authored Dec 6, 2024
1 parent b79c677 commit fc130f4
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 48 deletions.
97 changes: 73 additions & 24 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62932,14 +62932,19 @@ const github = __webpack_require__(95438);

class Config {
constructor() {
let label_list = JSON.parse(core.getInput('labels'));
let mode_option = core.getInput('mode')
if (mode_option === 'start'){
label_list.push(this.generateUniqueLabel())
}
this.input = {
mode: core.getInput('mode'),
mode: mode_option,
githubToken: core.getInput('github-token'),
ec2ImageId: core.getInput('ec2-image-id'),
ec2InstanceType: core.getInput('ec2-instance-type'),
subnetId: core.getInput('subnet-id'),
securityGroupId: core.getInput('security-group-id'),
labels: core.getInput('labels'),
labels: label_list,
ec2InstanceIds: core.getInput('ec2-instance-ids'),
iamRoleName: core.getInput('iam-role-name'),
runnerHomeDir: core.getInput('runner-home-dir'),
Expand Down Expand Up @@ -62990,7 +62995,7 @@ class Config {
return Math.random().toString(36).substr(2, 5);
}
getLabels() {
return JSON.parse(this.input.labels)
return this.input.labels
}
getEc2InstanceIds(){
return JSON.parse(this.input.ec2InstanceIds)
Expand All @@ -63014,8 +63019,6 @@ const core = __webpack_require__(42186);
const github = __webpack_require__(95438);
const _ = __webpack_require__(90250);
const config = __webpack_require__(34570);


function separateArrayWithCommas(arr) {
if (!Array.isArray(arr)) {
return "Input is not an array";
Expand All @@ -63024,27 +63027,45 @@ function separateArrayWithCommas(arr) {
return arr.join(",");
}

function areRunnersOnline(runners){
function areRunnersOnline(runners) {
core.info("Here at areRunnersOnline")
core.info(runners)
if(runners){
if (runners){
core.info("Critical logger")
var result = true
runners.forEach((runner) => {
if (runner.status !== 'online'){
result = false
if (runner.status !== 'online'){
core.info(`GitHub self-hosted runner number ${runner.name}, is not online yet`);
return false
}
});
return result
return true
} else {
return false
}
}

function areRunnersNotBusy(runners) {
core.info("Here at areRunnersNotBusy")
core.info(runners)
if (runners){
core.info(`Checking if runners are not busy`);
runners.forEach((runner) => {
if (runner.busy){
core.info(`GitHub self-hosted runner number ${runner.name}, is still busy`);
return false
}
});
core.info(`All runners are not busy`);
return true
} else {
core.info(`There are no more runners`);
return false
}
}
// use the unique label to find the runner
// as we don't have the runner's id, it's not possible to get it in any other way
async function getRunners(multiple_labels) {
const octokit = github.getOctokit(config.input.githubToken);

try {
var foundRunners = await octokit.paginate('GET /repos/{owner}/{repo}/actions/runners', config.githubContext);
multiple_labels.forEach((label) => {
Expand All @@ -63056,11 +63077,9 @@ async function getRunners(multiple_labels) {
return null;
}
}

// get GitHub Registration Token for registering a self-hosted runner
async function getRegistrationToken() {
const octokit = github.getOctokit(config.input.githubToken);

try {
const response = await octokit.request('POST /repos/{owner}/{repo}/actions/runners/registration-token', config.githubContext);
core.info('GitHub Registration Token is received');
Expand All @@ -63070,16 +63089,51 @@ async function getRegistrationToken() {
throw error;
}
}

async function waitForRunnersNotBusy(labels) {
const timeoutMinutes = 5;
const retryIntervalSeconds = 10;
const quietPeriodSeconds = 30;
let waitSeconds = 0;

core.info(`Waiting ${quietPeriodSeconds}s for the AWS EC2 instances be not busy in GitHut`);
await new Promise(r => setTimeout(r, quietPeriodSeconds * 1000));
core.info(`Checking every ${retryIntervalSeconds}s if the GitHub self-hosted runners are not busy`);

return new Promise((resolve, reject) => {
const interval = setInterval(async () => {
const runners = await getRunners(labels);

if (waitSeconds > timeoutMinutes * 60) {
core.error('GitHub self-hosted runners failed to be not busy -> TIMEOUT');
clearInterval(interval);
reject(`A timeout of ${timeoutMinutes} minutes is exceeded. Your AWS EC2 instances were not able to be not busy.`);
}

if (areRunnersNotBusy(runners)) {
runners.forEach((runner, index ) => {
core.info(`GitHub self-hosted runner number ${index}, ${runner.name}, is not busy`);
});
clearInterval(interval);
resolve();
} else {
waitSeconds += retryIntervalSeconds;
core.info('Checking...');
}
}, retryIntervalSeconds * 1000);
});
}

async function removeRunners() {
const runners = await getRunners(config.getLabels());
const octokit = github.getOctokit(config.input.githubToken);

// skip the runner removal process if no runners are found
if (!runners || runners.length === 0) {
core.info(`No GitHub self-hosted runners with labels ${separateArrayWithCommas(config.getLabels())} found, so the removal is skipped`);
return;
}

// Wait until all runner are not in busy state
await waitForRunnersNotBusy(config.getLabels())
// Use Promise.all to remove runners asynchronously
const removalPromises = runners.map(async (runner) => {
try {
Expand All @@ -63090,7 +63144,6 @@ async function removeRunners() {
throw error;
}
});

try {
await Promise.all(removalPromises);
core.info('All GitHub self-hosted runners are removed');
Expand All @@ -63099,30 +63152,25 @@ async function removeRunners() {
throw error;
}
}

async function waitForRunnersRegistered(labels) {
const timeoutMinutes = 5;
const retryIntervalSeconds = 10;
const quietPeriodSeconds = 30;
let waitSeconds = 0;

core.info(`Waiting ${quietPeriodSeconds}s for the AWS EC2 instances to be registered in GitHub as a new self-hosted runner`);
await new Promise(r => setTimeout(r, quietPeriodSeconds * 1000));
core.info(`Checking every ${retryIntervalSeconds}s if the GitHub self-hosted runner is registered`);

return new Promise((resolve, reject) => {
const interval = setInterval(async () => {
core.info(`Labels: ${labels}`)
const runners = await getRunners(labels);
core.info("After getRunners")
core.info(runners)

if (waitSeconds > timeoutMinutes * 60) {
core.error('GitHub self-hosted runner registration error');
clearInterval(interval);
reject(`A timeout of ${timeoutMinutes} minutes is exceeded. Your AWS EC2 instance was not able to register itself in GitHub as a new self-hosted runner.`);
}

if (areRunnersOnline(runners)) {
core.info("Are Runners Online")
runners.forEach((runner, index ) => {
core.info(`GitHub self-hosted runner number ${index}, ${runner.name}, is registered and ready to use`);
});
Expand All @@ -63138,6 +63186,7 @@ async function waitForRunnersRegistered(labels) {

module.exports = {
getRegistrationToken,
waitForRunnersNotBusy,
removeRunners,
waitForRunnersRegistered,
};
Expand Down
11 changes: 8 additions & 3 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ const github = require('@actions/github');

class Config {
constructor() {
const label_list = JSON.parse(core.getInput('labels'));
const mode_option = core.getInput('mode')
if (mode_option === 'start'){
label_list.push(this.generateUniqueLabel())
}
this.input = {
mode: core.getInput('mode'),
mode: mode_option,
githubToken: core.getInput('github-token'),
ec2ImageId: core.getInput('ec2-image-id'),
ec2InstanceType: core.getInput('ec2-instance-type'),
subnetId: core.getInput('subnet-id'),
securityGroupId: core.getInput('security-group-id'),
labels: core.getInput('labels'),
labels: label_list,
ec2InstanceIds: core.getInput('ec2-instance-ids'),
iamRoleName: core.getInput('iam-role-name'),
runnerHomeDir: core.getInput('runner-home-dir'),
Expand Down Expand Up @@ -61,7 +66,7 @@ class Config {
return Math.random().toString(36).substr(2, 5);
}
getLabels() {
return JSON.parse(this.input.labels)
return this.input.labels
}
getEc2InstanceIds(){
return JSON.parse(this.input.ec2InstanceIds)
Expand Down
Loading

0 comments on commit fc130f4

Please sign in to comment.