Skip to content
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ Join our discord community via [this invite link](https://discord.gg/bxgXW8jJGh)
| <a name="input_enable_userdata"></a> [enable\_userdata](#input\_enable\_userdata) | Should the userdata script be enabled for the runner. Set this to false if you are using your own prebuilt AMI. | `bool` | `true` | no |
| <a name="input_eventbridge"></a> [eventbridge](#input\_eventbridge) | Enable the use of EventBridge by the module. By enabling this feature events will be put on the EventBridge by the webhook instead of directly dispatching to queues for scaling.<br/><br/> `enable`: Enable the EventBridge feature.<br/> `accept_events`: List can be used to only allow specific events to be putted on the EventBridge. By default all events, empty list will be be interpreted as all events. | <pre>object({<br/> enable = optional(bool, true)<br/> accept_events = optional(list(string), null)<br/> })</pre> | `{}` | no |
| <a name="input_ghes_ssl_verify"></a> [ghes\_ssl\_verify](#input\_ghes\_ssl\_verify) | GitHub Enterprise SSL verification. Set to 'false' when custom certificate (chains) is used for GitHub Enterprise Server (insecure). | `bool` | `true` | no |
| <a name="input_ghes_url"></a> [ghes\_url](#input\_ghes\_url) | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB | `string` | `null` | no |
| <a name="input_ghes_url"></a> [ghes\_url](#input\_ghes\_url) | GitHub Enterprise Server URL. Example: https://github.internal.co - DO NOT SET IF USING PUBLIC GITHUB - github.com. However if you are using Github Eneterprise cloud with data-residency (ghe.com), set the endpoint here. Example - https://comaonyname.ghe.com | `string` | `null` | no |
| <a name="input_github_app"></a> [github\_app](#input\_github\_app) | GitHub app parameters, see your github app. Ensure the key is the base64-encoded `.pem` file (the output of `base64 app.private-key.pem`, not the content of `private-key.pem`). | <pre>object({<br/> key_base64 = string<br/> id = string<br/> webhook_secret = string<br/> })</pre> | n/a | yes |
| <a name="input_idle_config"></a> [idle\_config](#input\_idle\_config) | List of time periods, defined as a cron expression, to keep a minimum amount of runners active instead of scaling down to 0. By defining this list you can ensure that in time periods that match the cron expression within 5 seconds a runner is kept idle. | <pre>list(object({<br/> cron = string<br/> timeZone = string<br/> idleCount = number<br/> evictionStrategy = optional(string, "oldest_first")<br/> }))</pre> | `[]` | no |
| <a name="input_instance_allocation_strategy"></a> [instance\_allocation\_strategy](#input\_instance\_allocation\_strategy) | The allocation strategy for spot instances. AWS recommends using `price-capacity-optimized` however the AWS default is `lowest-price`. | `string` | `"lowest-price"` | no |
Expand Down
16 changes: 16 additions & 0 deletions lambdas/functions/control-plane/src/pool/pool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,22 @@ describe('Test simple pool.', () => {
});
});

describe('With Github Data Residency', () => {
beforeEach(() => {
process.env.GHES_URL = 'https://companyname.ghe.com';
});

it('Top up if the pool size is set to 5', async () => {
await expect(await adjust({ poolSize: 5 })).resolves;
// 2 idle, top up with 3 to match a pool of 5
expect(createRunners).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({ numberOfRunners: 3 }),
expect.anything(),
);
});
});

describe('With Runner Name Prefix', () => {
beforeEach(() => {
process.env.RUNNER_NAME_PREFIX = 'runner-prefix_';
Expand Down
8 changes: 2 additions & 6 deletions lambdas/functions/control-plane/src/pool/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import yn from 'yn';
import { bootTimeExceeded, listEC2Runners } from '../aws/runners';
import { RunnerList } from '../aws/runners.d';
import { createGithubAppAuth, createGithubInstallationAuth, createOctokitClient } from '../github/auth';
import { createRunners } from '../scale-runners/scale-up';
import { createRunners, getGitHubEnterpriseApiUrl } from '../scale-runners/scale-up';

const logger = createChildLogger('pool');

Expand All @@ -24,7 +24,6 @@ export async function adjust(event: PoolEvent): Promise<void> {
const runnerGroup = process.env.RUNNER_GROUP_NAME || '';
const runnerNamePrefix = process.env.RUNNER_NAME_PREFIX || '';
const environment = process.env.ENVIRONMENT;
const ghesBaseUrl = process.env.GHES_URL;
const ssmTokenPath = process.env.SSM_TOKEN_PATH;
const ssmConfigPath = process.env.SSM_CONFIG_PATH || '';
const subnets = process.env.SUBNET_IDS.split(',');
Expand All @@ -43,10 +42,7 @@ export async function adjust(event: PoolEvent): Promise<void> {
? (JSON.parse(process.env.ENABLE_ON_DEMAND_FAILOVER_FOR_ERRORS) as [string])
: [];

let ghesApiUrl = '';
if (ghesBaseUrl) {
ghesApiUrl = `${ghesBaseUrl}/api/v3`;
}
const { ghesApiUrl, ghesBaseUrl } = getGitHubEnterpriseApiUrl();

const installationId = await getInstallationId(ghesApiUrl, runnerOwner);
const ghAuth = await createGithubInstallationAuth(installationId, ghesApiUrl);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { addPersistentContextToChildLogger, createSingleMetric, logger } from '@aws-github-runner/aws-powertools-util';
import { publishMessage } from '../aws/sqs';
import { ActionRequestMessage, ActionRequestMessageRetry, getGitHubEnterpriseApiUrl, isJobQueued } from './scale-up';
import { ActionRequestMessage, ActionRequestMessageRetry, isJobQueued ,getGitHubEnterpriseApiUrl} from './scale-up';
import { getOctokit } from '../github/octokit';
import { MetricUnit } from '@aws-lambda-powertools/metrics';
import yn from 'yn';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,11 @@ describe('Scale down runners', () => {
mockCreateClient.mockResolvedValue(new mocktokit());
});

const endpoints = ['https://api.github.com', 'https://github.enterprise.something'];
const endpoints = ['https://api.github.com', 'https://github.enterprise.something', 'https://companyname.ghe.com'];

describe.each(endpoints)('for %s', (endpoint) => {
beforeEach(() => {
if (endpoint.includes('enterprise')) {
if (endpoint.includes('enterprise') || endpoint.includes('ghe.com')) {
process.env.GHES_URL = endpoint;
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { RunnerInfo, RunnerList } from './../aws/runners.d';
import { GhRunners, githubCache } from './cache';
import { ScalingDownConfig, getEvictionStrategy, getIdleRunnerCount } from './scale-down-config';
import { metricGitHubAppRateLimit } from '../github/rate-limit';
import {getGitHubEnterpriseApiUrl} from './scale-up';

const logger = createChildLogger('scale-down');

Expand All @@ -21,11 +22,7 @@ async function getOrCreateOctokit(runner: RunnerInfo): Promise<Octokit> {
}

logger.debug(`[createGitHubClientForRunner] Cache miss for ${key}`);
const ghesBaseUrl = process.env.GHES_URL;
let ghesApiUrl = '';
if (ghesBaseUrl) {
ghesApiUrl = `${ghesBaseUrl}/api/v3`;
}
const { ghesApiUrl} = getGitHubEnterpriseApiUrl();
const ghAuthPre = await createGithubAppAuth(undefined, ghesApiUrl);
const githubClientPre = await createOctokitClient(ghAuthPre.token, ghesApiUrl);

Expand Down
Loading
Loading