2022-09-16 22:51:19 +00:00
|
|
|
import { CloudRunnerSystem } from '../cloud-runner/services/cloud-runner-system';
|
|
|
|
|
import * as fs from 'fs';
|
2022-09-17 03:38:00 +00:00
|
|
|
import CloudRunnerLogger from '../cloud-runner/services/cloud-runner-logger';
|
2022-09-17 03:41:41 +00:00
|
|
|
import CloudRunnerOptions from '../cloud-runner/cloud-runner-options';
|
2022-09-16 21:24:23 +00:00
|
|
|
export class SharedWorkspaceLocking {
|
2022-10-05 00:37:32 +00:00
|
|
|
private static readonly workspaceRoot = `s3://game-ci-test-storage/locks/`;
|
2022-10-05 01:20:32 +00:00
|
|
|
public static async GetAllWorkspaces(): Promise<string[]> {
|
|
|
|
|
return (await SharedWorkspaceLocking.ReadLines(`aws s3 ls ${SharedWorkspaceLocking.workspaceRoot}`)).map((x) =>
|
|
|
|
|
x.replace(`/`, ``),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
public static async GetAllLocks(workspace: string): Promise<string[]> {
|
|
|
|
|
if (!(await SharedWorkspaceLocking.DoesWorkspaceExist(workspace))) {
|
|
|
|
|
throw new Error("Workspace doesn't exist, can't call get all locks");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
await SharedWorkspaceLocking.ReadLines(`aws s3 ls ${SharedWorkspaceLocking.workspaceRoot}${workspace}/`)
|
|
|
|
|
).map((x) => x.replace(`/`, ``));
|
|
|
|
|
}
|
|
|
|
|
public static async GetOrCreateLockedWorkspace(workspaceIfCreated: string, runId: string) {
|
2022-09-17 03:41:41 +00:00
|
|
|
if (!CloudRunnerOptions.retainWorkspaces) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-29 20:30:34 +00:00
|
|
|
const workspaces = await SharedWorkspaceLocking.GetFreeWorkspaces();
|
2022-09-16 21:24:23 +00:00
|
|
|
for (const element of workspaces) {
|
2022-09-29 20:30:34 +00:00
|
|
|
if (await SharedWorkspaceLocking.LockWorkspace(element, runId)) {
|
2022-09-16 21:24:23 +00:00
|
|
|
return element;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-05 01:20:32 +00:00
|
|
|
return await SharedWorkspaceLocking.CreateWorkspace(workspaceIfCreated);
|
2022-09-16 21:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-29 21:03:16 +00:00
|
|
|
public static async DoesWorkspaceExist(workspace: string) {
|
|
|
|
|
return (await SharedWorkspaceLocking.GetAllWorkspaces()).includes(workspace);
|
|
|
|
|
}
|
2022-10-05 01:20:32 +00:00
|
|
|
public static async HasWorkspaceLock(workspace: string, runId: string): Promise<boolean> {
|
|
|
|
|
if (!(await SharedWorkspaceLocking.DoesWorkspaceExist(workspace))) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-09-29 21:03:16 +00:00
|
|
|
|
2022-10-05 01:20:32 +00:00
|
|
|
return (await SharedWorkspaceLocking.GetAllLocks(workspace)).filter((x) => x.includes(runId)).length > 0;
|
2022-10-05 00:20:48 +00:00
|
|
|
}
|
|
|
|
|
|
2022-09-29 20:30:34 +00:00
|
|
|
public static async GetFreeWorkspaces(): Promise<string[]> {
|
|
|
|
|
const result: string[] = [];
|
|
|
|
|
const workspaces = await SharedWorkspaceLocking.GetAllWorkspaces();
|
|
|
|
|
for (const element of workspaces) {
|
|
|
|
|
if (!(await SharedWorkspaceLocking.IsWorkspaceLocked(element))) {
|
|
|
|
|
result.push(element);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2022-10-05 01:20:32 +00:00
|
|
|
|
|
|
|
|
public static async IsWorkspaceLocked(workspace: string): Promise<boolean> {
|
2022-09-29 21:03:16 +00:00
|
|
|
if (!(await SharedWorkspaceLocking.DoesWorkspaceExist(workspace))) {
|
2022-10-05 01:20:32 +00:00
|
|
|
return false;
|
2022-09-29 21:03:16 +00:00
|
|
|
}
|
2022-10-05 01:20:32 +00:00
|
|
|
const files = await SharedWorkspaceLocking.ReadLines(
|
|
|
|
|
`aws s3 ls ${SharedWorkspaceLocking.workspaceRoot}${workspace}/`,
|
|
|
|
|
);
|
2022-09-29 21:03:16 +00:00
|
|
|
|
2022-10-05 01:20:32 +00:00
|
|
|
// 1 Because we expect 1 workspace file to exist in every workspace folder
|
|
|
|
|
return files.length > 1;
|
2022-09-29 20:30:34 +00:00
|
|
|
}
|
|
|
|
|
|
2022-10-05 01:20:32 +00:00
|
|
|
public static async CreateWorkspace(workspace: string) {
|
|
|
|
|
const file = `${Date.now()}_workspace`;
|
|
|
|
|
fs.writeFileSync(file, '');
|
|
|
|
|
await CloudRunnerSystem.Run(
|
|
|
|
|
`aws s3 cp ./${file} ${SharedWorkspaceLocking.workspaceRoot}${workspace}/${file}`,
|
|
|
|
|
false,
|
|
|
|
|
true,
|
|
|
|
|
);
|
|
|
|
|
fs.rmSync(file);
|
2022-09-29 20:30:34 +00:00
|
|
|
|
2022-10-05 01:20:32 +00:00
|
|
|
return workspace;
|
2022-09-16 21:24:23 +00:00
|
|
|
}
|
2022-09-29 20:30:34 +00:00
|
|
|
|
|
|
|
|
public static async LockWorkspace(workspace: string, runId: string): Promise<boolean> {
|
|
|
|
|
const file = `${Date.now()}_${runId}_lock`;
|
2022-09-16 22:51:19 +00:00
|
|
|
fs.writeFileSync(file, '');
|
2022-09-29 20:30:34 +00:00
|
|
|
await CloudRunnerSystem.Run(
|
2022-10-05 00:37:32 +00:00
|
|
|
`aws s3 cp ./${file} ${SharedWorkspaceLocking.workspaceRoot}${workspace}/${file}`,
|
2022-09-29 20:30:34 +00:00
|
|
|
false,
|
|
|
|
|
true,
|
|
|
|
|
);
|
2022-09-16 22:51:19 +00:00
|
|
|
fs.rmSync(file);
|
|
|
|
|
|
2022-09-29 22:34:31 +00:00
|
|
|
return SharedWorkspaceLocking.HasWorkspaceLock(workspace, runId);
|
2022-09-16 22:51:19 +00:00
|
|
|
}
|
2022-09-29 20:30:34 +00:00
|
|
|
|
|
|
|
|
public static async ReleaseWorkspace(workspace: string, runId: string): Promise<boolean> {
|
2022-09-29 21:25:43 +00:00
|
|
|
if (!(await SharedWorkspaceLocking.DoesWorkspaceExist(workspace))) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-09-29 20:30:34 +00:00
|
|
|
const file = (await SharedWorkspaceLocking.GetAllLocks(workspace)).filter((x) => x.includes(`_${runId}_lock`));
|
|
|
|
|
CloudRunnerLogger.log(`${JSON.stringify(await SharedWorkspaceLocking.GetAllLocks(workspace))}`);
|
|
|
|
|
CloudRunnerLogger.log(`Deleting file ${file}`);
|
2022-10-05 00:37:32 +00:00
|
|
|
CloudRunnerLogger.log(`aws s3 rm ${SharedWorkspaceLocking.workspaceRoot}${workspace}/${file}`);
|
|
|
|
|
await CloudRunnerSystem.Run(`aws s3 rm ${SharedWorkspaceLocking.workspaceRoot}${workspace}/${file}`, false, true);
|
2022-09-29 20:30:34 +00:00
|
|
|
|
2022-09-29 22:34:31 +00:00
|
|
|
return !SharedWorkspaceLocking.HasWorkspaceLock(workspace, runId);
|
2022-09-29 20:30:34 +00:00
|
|
|
}
|
|
|
|
|
|
2022-10-05 01:20:32 +00:00
|
|
|
public static async CleanupWorkspace(workspace: string) {
|
2022-09-29 20:30:34 +00:00
|
|
|
await CloudRunnerSystem.Run(
|
2022-10-05 01:20:32 +00:00
|
|
|
`aws s3 rm ${SharedWorkspaceLocking.workspaceRoot}${workspace} --recursive`,
|
2022-09-29 20:30:34 +00:00
|
|
|
false,
|
|
|
|
|
true,
|
|
|
|
|
);
|
2022-10-05 01:20:32 +00:00
|
|
|
}
|
2022-09-17 04:44:07 +00:00
|
|
|
|
2022-10-05 01:20:32 +00:00
|
|
|
private static async ReadLines(command: string): Promise<string[]> {
|
|
|
|
|
const result = await CloudRunnerSystem.Run(command, false, true);
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
.split(`\n`)
|
|
|
|
|
.map((x) => x.replace(`\r`, ``))
|
|
|
|
|
.filter((x) => x !== ``)
|
|
|
|
|
.map((x) => {
|
|
|
|
|
const lineValues = x.split(` `);
|
|
|
|
|
|
|
|
|
|
return lineValues[lineValues.length - 1];
|
|
|
|
|
});
|
2022-09-17 04:09:36 +00:00
|
|
|
}
|
2022-09-16 21:24:23 +00:00
|
|
|
}
|
2022-09-16 18:48:40 +00:00
|
|
|
|
|
|
|
|
export default SharedWorkspaceLocking;
|