-
Notifications
You must be signed in to change notification settings - Fork 383
Expand file tree
/
Copy pathconfig.js
More file actions
184 lines (163 loc) · 7.12 KB
/
config.js
File metadata and controls
184 lines (163 loc) · 7.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
const core = require('@actions/core');
const github = require('@actions/github');
class Config {
constructor() {
this.input = {
ec2ImageId: core.getInput('ec2-image-id'),
ec2InstanceId: core.getInput('ec2-instance-id'),
ec2InstanceType: core.getInput('ec2-instance-type'),
ec2InstanceTypes: [],
githubToken: core.getInput('github-token'),
iamRoleName: core.getInput('iam-role-name'),
label: core.getInput('label'),
marketType: core.getInput('market-type'),
mode: core.getInput('mode'),
preRunnerScript: core.getInput('pre-runner-script'),
runnerHomeDir: core.getInput('runner-home-dir'),
securityGroupId: core.getInput('security-group-id'),
startupQuietPeriodSeconds: core.getInput('startup-quiet-period-seconds'),
startupRetryIntervalSeconds: core.getInput('startup-retry-interval-seconds'),
startupTimeoutMinutes: core.getInput('startup-timeout-minutes'),
subnetId: core.getInput('subnet-id'),
runAsService: core.getInput('run-runner-as-service') === 'true',
runAsUser: core.getInput('run-runner-as-user'),
ec2VolumeSize: core.getInput('ec2-volume-size'),
ec2DeviceName: core.getInput('ec2-device-name'),
ec2VolumeType: core.getInput('ec2-volume-type'),
blockDeviceMappings: JSON.parse(core.getInput('block-device-mappings') || '[]'),
availabilityZonesConfig: core.getInput('availability-zones-config'),
metadataOptions: JSON.parse(core.getInput('metadata-options') || '{}'),
packages: JSON.parse(core.getInput('packages') || '[]'),
useJit: core.getInput('use-jit') === 'true',
runnerGroupId: parseInt(core.getInput('runner-group-id') || '1', 10),
runnerDebug: core.getInput('runner-debug') === 'true',
};
// Get the AWS_REGION environment variable
this.defaultRegion = process.env.AWS_REGION;
const tags = JSON.parse(core.getInput('aws-resource-tags'));
this.tagSpecifications = null;
if (tags.length > 0) {
this.tagSpecifications = [
{ ResourceType: 'instance', Tags: tags },
{ ResourceType: 'volume', Tags: tags },
];
}
// the values of github.context.repo.owner and github.context.repo.repo are taken from
// the environment variable GITHUB_REPOSITORY specified in "owner/repo" format and
// provided by the GitHub Action on the runtime
this.githubContext = {
owner: github.context.repo.owner,
repo: github.context.repo.repo,
};
//
// validate input
//
if (!this.input.mode) {
throw new Error(`The 'mode' input is not specified`);
}
if (!this.input.githubToken) {
throw new Error(`The 'github-token' input is not specified`);
}
// Initialize availabilityZones as an empty array
this.availabilityZones = [];
if (this.input.mode === 'start') {
// Parse availability zones config if provided
if (this.input.availabilityZonesConfig) {
try {
this.availabilityZones = JSON.parse(this.input.availabilityZonesConfig);
// Validate each availability zone configuration
if (!Array.isArray(this.availabilityZones)) {
throw new Error('availability-zones-config must be a JSON array');
}
this.availabilityZones.forEach((az, index) => {
if (!az.imageId) {
throw new Error(`Missing imageId in availability-zones-config at index ${index}`);
}
if (!az.subnetId) {
throw new Error(`Missing subnetId in availability-zones-config at index ${index}`);
}
if (!az.securityGroupId) {
throw new Error(`Missing securityGroupId in availability-zones-config at index ${index}`);
}
// Region is optional, will use the default if not specified
if (!az.region) {
az.region = this.defaultRegion;
}
});
} catch (error) {
throw new Error(`Failed to parse availability-zones-config: ${error.message}`);
}
}
// Check for required instance type regardless of config method
if (!this.input.ec2InstanceType) {
throw new Error(`The 'ec2-instance-type' input is required for the 'start' mode.`);
}
// Parse ec2-instance-type: supports a single string or a JSON array of strings
const rawType = this.input.ec2InstanceType.trim();
if (rawType.startsWith('[')) {
try {
this.input.ec2InstanceTypes = JSON.parse(rawType);
if (!Array.isArray(this.input.ec2InstanceTypes) || this.input.ec2InstanceTypes.length === 0) {
throw new Error('must be a non-empty JSON array of strings');
}
for (const t of this.input.ec2InstanceTypes) {
if (typeof t !== 'string' || t.trim().length === 0) {
throw new Error('each element must be a non-empty string');
}
}
} catch (error) {
throw new Error(`Invalid 'ec2-instance-type' input: ${error.message}`);
}
} else {
this.input.ec2InstanceTypes = [rawType];
}
// Keep ec2InstanceType pointing to the first type for backward compatibility
this.input.ec2InstanceType = this.input.ec2InstanceTypes[0];
// If no availability zones config provided, check for individual parameters
if (this.availabilityZones.length === 0) {
if (!this.input.ec2ImageId || !this.input.subnetId || !this.input.securityGroupId) {
throw new Error(
`Either provide 'availability-zones-config' or all of the following: 'ec2-image-id', 'subnet-id', 'security-group-id'`
);
}
// Convert individual parameters to a single availability zone config
this.availabilityZones.push({
imageId: this.input.ec2ImageId,
subnetId: this.input.subnetId,
securityGroupId: this.input.securityGroupId,
// Add default region when using legacy configuration
region: this.defaultRegion
});
core.info('Using individual parameters as a single availability zone configuration');
}
if (this.input.useJit && this.input.runAsService) {
throw new Error(
"The 'use-jit' and 'run-runner-as-service' inputs are incompatible. " +
'JIT runners are single-use and cannot run as a service.'
);
}
if (this.marketType?.length > 0 && this.input.marketType !== 'spot') {
throw new Error('Invalid `market-type` input. Allowed values: spot.');
}
} else if (this.input.mode === 'stop') {
if (!this.input.ec2InstanceId) {
throw new Error(`The 'ec2-instance-id' input is required for the 'stop' mode.`);
}
if (!this.input.label) {
core.warning(`The 'label' input is not specified for the 'stop' mode. The runner will be removed by the 'ec2-instance-id' input.`);
}
} else {
throw new Error('Wrong mode. Allowed values: start, stop.');
}
}
generateUniqueLabel() {
return Math.random().toString(36).substr(2, 5);
}
}
try {
module.exports = new Config();
} catch (error) {
core.error(error);
core.setFailed(error.message);
}
module.exports.Config = Config;