|
1 |
| -import { EC2 } from 'aws-sdk'; |
| 1 | +import { createAppAuth } from '@octokit/auth-app'; |
| 2 | +import { Octokit } from '@octokit/rest'; |
| 3 | +import { AppAuth } from '@octokit/auth-app/dist-types/types'; |
| 4 | +import { listRunners, terminateRunner, RunnerInfo } from './runners'; |
| 5 | +import { createGithubAppAuth, createInstallationClient } from './scale-up'; |
| 6 | + |
| 7 | +// function createGithubAppAuth(installationId: number | undefined): AppAuth { |
| 8 | +// const privateKey = Buffer.from(process.env.GITHUB_APP_KEY_BASE64 as string, 'base64').toString(); |
| 9 | +// const appId: number = parseInt(process.env.GITHUB_APP_ID as string); |
| 10 | +// const clientId = process.env.GITHUB_APP_CLIENT_ID as string; |
| 11 | +// const clientSecret = process.env.GITHUB_APP_CLIENT_SECRET as string; |
| 12 | + |
| 13 | +// return createAppAuth({ |
| 14 | +// id: appId, |
| 15 | +// privateKey: privateKey, |
| 16 | +// installationId: installationId, |
| 17 | +// clientId: clientId, |
| 18 | +// clientSecret: clientSecret, |
| 19 | +// }); |
| 20 | +// } |
| 21 | + |
| 22 | +// async function createInstallationClient(githubAppAuth: AppAuth): Promise<Octokit> { |
| 23 | +// const auth = await githubAppAuth({ type: 'installation' }); |
| 24 | +// return new Octokit({ auth: auth.token }); |
| 25 | +// } |
| 26 | + |
| 27 | +// specific to scale down |
| 28 | +async function createAppClient(githubAppAuth: AppAuth): Promise<Octokit> { |
| 29 | + const auth = await githubAppAuth({ type: 'app' }); |
| 30 | + return new Octokit({ auth: auth.token }); |
| 31 | +} |
| 32 | + |
| 33 | +interface Repo { |
| 34 | + isOrg: boolean; |
| 35 | + repoName: string; |
| 36 | + repoOwner: string; |
| 37 | +} |
| 38 | + |
| 39 | +function getRepo(runner: RunnerInfo): Repo { |
| 40 | + if (runner.repo) { |
| 41 | + return { |
| 42 | + repoOwner: runner.repo?.split('/')[0] as string, |
| 43 | + repoName: runner.repo?.split('/')[1] as string, |
| 44 | + isOrg: false, |
| 45 | + }; |
| 46 | + } else { |
| 47 | + return { |
| 48 | + repoOwner: runner.org as string, |
| 49 | + repoName: '', |
| 50 | + isOrg: true, |
| 51 | + }; |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +async function createGitHubClientForRunner(runner: RunnerInfo): Promise<Octokit> { |
| 56 | + const githubClient = await createAppClient(createGithubAppAuth(undefined)); |
| 57 | + const repo = getRepo(runner); |
| 58 | + |
| 59 | + const repoInstallationId = repo.isOrg |
| 60 | + ? ( |
| 61 | + await githubClient.apps.getOrgInstallation({ |
| 62 | + org: repo.repoOwner, |
| 63 | + }) |
| 64 | + ).data.id |
| 65 | + : ( |
| 66 | + await githubClient.apps.getRepoInstallation({ |
| 67 | + owner: repo.repoOwner, |
| 68 | + repo: repo.repoName, |
| 69 | + }) |
| 70 | + ).data.id; |
| 71 | + |
| 72 | + return createInstallationClient(createGithubAppAuth(repoInstallationId)); |
| 73 | +} |
2 | 74 |
|
3 | 75 | export async function scaleDown(): Promise<void> {
|
4 |
| - console.info('Not implemented yet'); |
| 76 | + const environment = process.env.ENVIRONMENT as string; |
| 77 | + const runners = await listRunners({ |
| 78 | + environment: environment, |
| 79 | + }); |
| 80 | + |
| 81 | + if (runners?.length === 0) { |
| 82 | + console.debug(`No active runners found for environment: '${environment}'`); |
| 83 | + return; |
| 84 | + } |
| 85 | + |
| 86 | + runners.forEach(async (r) => { |
| 87 | + const githubAppClient = await createGitHubClientForRunner(r); |
| 88 | + |
| 89 | + const repo = getRepo(r); |
| 90 | + const registered = await githubAppClient.actions.listSelfHostedRunnersForRepo({ |
| 91 | + owner: repo.repoOwner, |
| 92 | + repo: repo.repoName, |
| 93 | + }); |
| 94 | + |
| 95 | + console.log(registered.data.runners); |
| 96 | + registered.data.runners.forEach(async (a: any) => { |
| 97 | + const runnerName = a.name as string; |
| 98 | + if (runnerName === r.instanceId) { |
| 99 | + console.log(r.instanceId); |
| 100 | + try { |
| 101 | + const result = repo.isOrg |
| 102 | + ? await githubAppClient.actions.deleteSelfHostedRunnerFromOrg({ runner_id: a.id, org: repo.repoOwner }) |
| 103 | + : await githubAppClient.actions.deleteSelfHostedRunnerFromRepo({ |
| 104 | + runner_id: a.id, |
| 105 | + owner: repo.repoOwner, |
| 106 | + repo: repo.repoName, |
| 107 | + }); |
| 108 | + if (result?.status == 204) { |
| 109 | + terminateRunner(r); |
| 110 | + console.info( |
| 111 | + `AWS runner instance '${r.instanceId}' is terminated and GitHub runner '${runnerName}' is de-registered.`, |
| 112 | + ); |
| 113 | + } |
| 114 | + console.info( |
| 115 | + `AWS runner instance '${r.instanceId}' is terminated and GitHub runner '${runnerName}' is de-registered.`, |
| 116 | + ); |
| 117 | + } catch (e) { |
| 118 | + console.debug(`Runner '${runnerName}' cannot be de-registered, most likely the runner is active.`); |
| 119 | + } |
| 120 | + } |
| 121 | + }); |
| 122 | + }); |
5 | 123 | }
|
0 commit comments