Skip to content

Commit b6da65f

Browse files
committed
OPS-3199: Adding packaged dist file
1 parent 849ee37 commit b6da65f

File tree

1 file changed

+87
-53
lines changed

1 file changed

+87
-53
lines changed

dist/index.js

Lines changed: 87 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -62811,7 +62811,12 @@ function buildUserDataScript(githubRegistrationToken, label) {
6281162811
'#!/bin/bash',
6281262812
`cd "${config.input.runnerHomeDir}"`,
6281362813
'export RUNNER_ALLOW_RUNASROOT=1',
62814-
`./config.sh --url https://github.com/${config.githubContext.owner}/${config.githubContext.repo} --token ${githubRegistrationToken} --labels ${label}`,
62814+
'sudo echo "export RUNNER_ALLOW_RUNASROOT=1" >> /etc/profile.d/env.sh',
62815+
'export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1',
62816+
'sudo echo "export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1" >> /etc/profile.d/env.sh',
62817+
'export DOTNET_SYSTEM_GLOBALIZATION_PREDEFINED_CULTURES_ONLY=false',
62818+
'sudo echo "export DOTNET_SYSTEM_GLOBALIZATION_PREDEFINED_CULTURES_ONLY=false" >> /etc/profile.d/env.sh',
62819+
`./config.sh --unattended --url https://github.com/${config.githubContext.owner}/${config.githubContext.repo} --token ${githubRegistrationToken} --labels ${label}`,
6281562820
'./run.sh',
6281662821
];
6281762822
} else {
@@ -62822,78 +62827,86 @@ function buildUserDataScript(githubRegistrationToken, label) {
6282262827
'curl -O -L https://github.com/actions/runner/releases/download/v2.299.1/actions-runner-linux-${RUNNER_ARCH}-2.299.1.tar.gz',
6282362828
'tar xzf ./actions-runner-linux-${RUNNER_ARCH}-2.299.1.tar.gz',
6282462829
'export RUNNER_ALLOW_RUNASROOT=1',
62825-
`./config.sh --url https://github.com/${config.githubContext.owner}/${config.githubContext.repo} --token ${githubRegistrationToken} --labels ${label}`,
62830+
'sudo echo "export RUNNER_ALLOW_RUNASROOT=1" >> /etc/profile.d/env.sh',
62831+
'export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1',
62832+
'sudo echo "export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1" >> /etc/profile.d/env.sh',
62833+
'export DOTNET_SYSTEM_GLOBALIZATION_PREDEFINED_CULTURES_ONLY=false',
62834+
'sudo echo "export DOTNET_SYSTEM_GLOBALIZATION_PREDEFINED_CULTURES_ONLY=false" >> /etc/profile.d/env.sh',
62835+
`./config.sh --unattended --url https://github.com/${config.githubContext.owner}/${config.githubContext.repo} --token ${githubRegistrationToken} --labels ${label}`,
6282662836
'./run.sh',
6282762837
];
6282862838
}
6282962839
}
6283062840

62831-
async function startEc2Instance(label, githubRegistrationToken) {
62841+
async function startEc2Instances(label, count, githubRegistrationToken) {
6283262842
const ec2 = new AWS.EC2();
6283362843

62844+
// User data scripts are run as the root user.
62845+
// Docker and git are necessary for GitHub runner and should be pre-installed on the AMI.
6283462846
const userData = buildUserDataScript(githubRegistrationToken, label);
6283562847

6283662848
const params = {
6283762849
ImageId: config.input.ec2ImageId,
6283862850
InstanceType: config.input.ec2InstanceType,
62839-
MinCount: 1,
62840-
MaxCount: 1,
62851+
MinCount: count,
62852+
MaxCount: count,
6284162853
UserData: Buffer.from(userData.join('\n')).toString('base64'),
6284262854
SubnetId: config.input.subnetId,
6284362855
SecurityGroupIds: [config.input.securityGroupId],
6284462856
IamInstanceProfile: { Name: config.input.iamRoleName },
6284562857
TagSpecifications: config.tagSpecifications,
62858+
KeyName: config.input.keyPairName
6284662859
};
6284762860

6284862861
try {
6284962862
const result = await ec2.runInstances(params).promise();
62850-
const ec2InstanceId = result.Instances[0].InstanceId;
62851-
core.info(`AWS EC2 instance ${ec2InstanceId} is started`);
62852-
return ec2InstanceId;
62863+
const ec2InstanceIds = result.Instances.map(i => i.InstanceId);
62864+
core.info(`AWS EC2 instances ${JSON.stringify(ec2InstanceIds)} are started`);
62865+
return ec2InstanceIds;
6285362866
} catch (error) {
6285462867
core.error('AWS EC2 instance starting error');
6285562868
throw error;
6285662869
}
6285762870
}
6285862871

62859-
async function terminateEc2Instance() {
62872+
async function terminateEc2Instances() {
6286062873
const ec2 = new AWS.EC2();
6286162874

6286262875
const params = {
62863-
InstanceIds: [config.input.ec2InstanceId],
62876+
InstanceIds: config.input.ec2InstanceIds,
6286462877
};
6286562878

6286662879
try {
6286762880
await ec2.terminateInstances(params).promise();
62868-
core.info(`AWS EC2 instance ${config.input.ec2InstanceId} is terminated`);
62881+
core.info(`AWS EC2 instances ${JSON.stringify(config.input.ec2InstanceIds)} are terminated`);
6286962882
return;
6287062883
} catch (error) {
62871-
core.error(`AWS EC2 instance ${config.input.ec2InstanceId} termination error`);
62884+
core.error(`AWS EC2 instances ${JSON.stringify(config.input.ec2InstanceIds)} termination error`);
6287262885
throw error;
6287362886
}
6287462887
}
6287562888

62876-
async function waitForInstanceRunning(ec2InstanceId) {
62889+
async function waitForInstancesRunning(ec2InstanceIds) {
6287762890
const ec2 = new AWS.EC2();
6287862891

6287962892
const params = {
62880-
InstanceIds: [ec2InstanceId],
62893+
InstanceIds: ec2InstanceIds,
6288162894
};
6288262895

6288362896
try {
6288462897
await ec2.waitFor('instanceRunning', params).promise();
62885-
core.info(`AWS EC2 instance ${ec2InstanceId} is up and running`);
62898+
core.info(`AWS EC2 instances ${JSON.stringify(ec2InstanceIds)} are up and running`);
6288662899
return;
6288762900
} catch (error) {
62888-
core.error(`AWS EC2 instance ${ec2InstanceId} initialization error`);
62901+
core.error(`AWS EC2 instances ${JSON.stringify(ec2InstanceIds)} initialization error`);
6288962902
throw error;
6289062903
}
6289162904
}
6289262905

6289362906
module.exports = {
62894-
startEc2Instance,
62895-
terminateEc2Instance,
62896-
waitForInstanceRunning,
62907+
startEc2Instances,
62908+
terminateEc2Instances,
62909+
waitForInstancesRunning,
6289762910
};
6289862911

6289962912

@@ -62912,12 +62925,14 @@ class Config {
6291262925
githubToken: core.getInput('github-token'),
6291362926
ec2ImageId: core.getInput('ec2-image-id'),
6291462927
ec2InstanceType: core.getInput('ec2-instance-type'),
62928+
ec2InstanceCount: core.getInput('ec2-instance-count'),
6291562929
subnetId: core.getInput('subnet-id'),
6291662930
securityGroupId: core.getInput('security-group-id'),
6291762931
label: core.getInput('label'),
62918-
ec2InstanceId: core.getInput('ec2-instance-id'),
62932+
ec2InstanceIds: core.getInput('ec2-instance-id'),
6291962933
iamRoleName: core.getInput('iam-role-name'),
62920-
runnerHomeDir: core.getInput('runner-home-dir'),
62934+
keyPairName: core.getInput('key-pair-name'),
62935+
runnerHomeDir: core.getInput('runner-home-dir')
6292162936
};
6292262937

6292362938
const tags = JSON.parse(core.getInput('aws-resource-tags'));
@@ -62947,13 +62962,32 @@ class Config {
6294762962
}
6294862963

6294962964
if (this.input.mode === 'start') {
62950-
if (!this.input.ec2ImageId || !this.input.ec2InstanceType || !this.input.subnetId || !this.input.securityGroupId) {
62965+
if (!this.input.ec2ImageId || !this.input.ec2InstanceType || !this.input.subnetId || !this.input.securityGroupId || !this.input.keyPairName) {
6295162966
throw new Error(`Not all the required inputs are provided for the 'start' mode`);
6295262967
}
62968+
62969+
if (this.input.ec2InstanceCount === undefined) {
62970+
this.input.ec2InstanceCount = 1;
62971+
}
62972+
const parsedEc2InstanceCount = parseInt(this.input.ec2InstanceCount);
62973+
if (isNaN(parsedEc2InstanceCount)) {
62974+
throw new Error(`The 'ec2-instance-count' input has illegal value '${this.input.ec2InstanceCount}'`);
62975+
} else if (parsedEc2InstanceCount < 1) {
62976+
throw new Error(`The 'ec2-instance-count' input must be greater than zero`);
62977+
}
62978+
this.input.ec2InstanceCount = parsedEc2InstanceCount;
6295362979
} else if (this.input.mode === 'stop') {
62954-
if (!this.input.label || !this.input.ec2InstanceId) {
62980+
if (!this.input.label || !this.input.ec2InstanceIds) {
6295562981
throw new Error(`Not all the required inputs are provided for the 'stop' mode`);
6295662982
}
62983+
62984+
try {
62985+
const parsedEc2InstanceIds = JSON.parse(this.input.ec2InstanceIds);
62986+
this.input.ec2InstanceIds = parsedEc2InstanceIds;
62987+
} catch (error) {
62988+
core.info(`Got error ${error} when parsing '${this.input.ec2InstanceIds}' as JSON, assuming that it is a raw string containing a single EC2 instance ID`);
62989+
this.input.ec2InstanceIds = [this.input.ec2InstanceIds];
62990+
}
6295762991
} else {
6295862992
throw new Error('Wrong mode. Allowed values: start, stop.');
6295962993
}
@@ -62984,15 +63018,15 @@ const config = __webpack_require__(34570);
6298463018

6298563019
// use the unique label to find the runner
6298663020
// as we don't have the runner's id, it's not possible to get it in any other way
62987-
async function getRunner(label) {
63021+
async function getRunners(label) {
6298863022
const octokit = github.getOctokit(config.input.githubToken);
6298963023

6299063024
try {
6299163025
const runners = await octokit.paginate('GET /repos/{owner}/{repo}/actions/runners', config.githubContext);
62992-
const foundRunners = _.filter(runners, { labels: [{ name: label }] });
62993-
return foundRunners.length > 0 ? foundRunners[0] : null;
63026+
return _.filter(runners, { labels: [{ name: label }] });
6299463027
} catch (error) {
62995-
return null;
63028+
core.error(`Error fetching current runners: ${error}`)
63029+
return [];
6299663030
}
6299763031
}
6299863032

@@ -63010,48 +63044,48 @@ async function getRegistrationToken() {
6301063044
}
6301163045
}
6301263046

63013-
async function removeRunner() {
63014-
const runner = await getRunner(config.input.label);
63047+
async function removeRunners() {
63048+
const runners = await getRunners(config.input.label);
6301563049
const octokit = github.getOctokit(config.input.githubToken);
6301663050

6301763051
// skip the runner removal process if the runner is not found
63018-
if (!runner) {
63019-
core.info(`GitHub self-hosted runner with label ${config.input.label} is not found, so the removal is skipped`);
63052+
if (!runners || runners.length === 0) {
63053+
core.info(`GitHub self-hosted runners with label ${config.input.label} are not found, so the removal is skipped`);
6302063054
return;
6302163055
}
6302263056

6302363057
try {
63024-
await octokit.request('DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}', _.merge(config.githubContext, { runner_id: runner.id }));
63025-
core.info(`GitHub self-hosted runner ${runner.name} is removed`);
63058+
await Promise.all(runners.map(r => octokit.request('DELETE /repos/{owner}/{repo}/actions/runners/{runner_id}', _.merge(config.githubContext, { runner_id: r.id }))));
63059+
core.info(`GitHub self-hosted runners ${runners.map(r => r.name)} are removed`);
6302663060
return;
6302763061
} catch (error) {
63028-
core.error('GitHub self-hosted runner removal error');
63062+
core.error('GitHub self-hosted runners removal error');
6302963063
throw error;
6303063064
}
6303163065
}
6303263066

63033-
async function waitForRunnerRegistered(label) {
63067+
async function waitForRunnersRegistered(label, expectedRunnerCount) {
6303463068
const timeoutMinutes = 5;
6303563069
const retryIntervalSeconds = 10;
6303663070
const quietPeriodSeconds = 30;
6303763071
let waitSeconds = 0;
6303863072

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

6304363077
return new Promise((resolve, reject) => {
6304463078
const interval = setInterval(async () => {
63045-
const runner = await getRunner(label);
63079+
const runners = await getRunners(label);
6304663080

6304763081
if (waitSeconds > timeoutMinutes * 60) {
63048-
core.error('GitHub self-hosted runner registration error');
63082+
core.error('GitHub self-hosted runners registration error');
6304963083
clearInterval(interval);
63050-
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.`);
63084+
reject(`A timeout of ${timeoutMinutes} minutes is exceeded. Your AWS EC2 instances were not able to register themselves in GitHub as the new self-hosted runners.`);
6305163085
}
6305263086

63053-
if (runner && runner.status === 'online') {
63054-
core.info(`GitHub self-hosted runner ${runner.name} is registered and ready to use`);
63087+
if (runners && runners.length == expectedRunnerCount && runners.every(r => r.status === 'online')) {
63088+
core.info(`GitHub self-hosted runners ${JSON.stringify(runners.map(r => r.name))} are registered and ready to use`);
6305563089
clearInterval(interval);
6305663090
resolve();
6305763091
} else {
@@ -63064,8 +63098,8 @@ async function waitForRunnerRegistered(label) {
6306463098

6306563099
module.exports = {
6306663100
getRegistrationToken,
63067-
removeRunner,
63068-
waitForRunnerRegistered,
63101+
removeRunners,
63102+
waitForRunnersRegistered,
6306963103
};
6307063104

6307163105

@@ -63079,23 +63113,23 @@ const gh = __webpack_require__(56989);
6307963113
const config = __webpack_require__(34570);
6308063114
const core = __webpack_require__(42186);
6308163115

63082-
function setOutput(label, ec2InstanceId) {
63116+
function setOutput(label, ec2InstanceIds) {
6308363117
core.setOutput('label', label);
63084-
core.setOutput('ec2-instance-id', ec2InstanceId);
63118+
core.setOutput('ec2-instance-id', JSON.stringify(ec2InstanceIds));
6308563119
}
6308663120

6308763121
async function start() {
6308863122
const label = config.generateUniqueLabel();
6308963123
const githubRegistrationToken = await gh.getRegistrationToken();
63090-
const ec2InstanceId = await aws.startEc2Instance(label, githubRegistrationToken);
63091-
setOutput(label, ec2InstanceId);
63092-
await aws.waitForInstanceRunning(ec2InstanceId);
63093-
await gh.waitForRunnerRegistered(label);
63124+
const ec2InstanceIds = await aws.startEc2Instances(label, config.input.ec2InstanceCount, githubRegistrationToken);
63125+
setOutput(label, ec2InstanceIds);
63126+
await aws.waitForInstancesRunning(ec2InstanceIds);
63127+
await gh.waitForRunnersRegistered(label, config.input.ec2InstanceCount);
6309463128
}
6309563129

6309663130
async function stop() {
63097-
await aws.terminateEc2Instance();
63098-
await gh.removeRunner();
63131+
await aws.terminateEc2Instances();
63132+
await gh.removeRunners();
6309963133
}
6310063134

6310163135
(async function () {
@@ -69250,4 +69284,4 @@ module.exports = require("zlib");;
6925069284
/******/ // Load entry module and return exports
6925169285
/******/ return __webpack_require__(4351);
6925269286
/******/ })()
69253-
;
69287+
;

0 commit comments

Comments
 (0)