Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/file-server/zfs/test/util.ts
1450 views
1
// application/typescript text
2
import { context, setContext } from "@cocalc/file-server/zfs/config";
3
import { mkdtemp, rm } from "fs/promises";
4
import { tmpdir } from "os";
5
import { join } from "path";
6
import { executeCode } from "@cocalc/backend/execute-code";
7
import { initDataDir } from "@cocalc/file-server/zfs/util";
8
import { resetDb } from "@cocalc/file-server/zfs/db";
9
import { getPools } from "@cocalc/file-server/zfs/pools";
10
import { map as asyncMap } from "awaiting";
11
12
// export "describe" from here that is a no-op unless TEST_ZFS is set
13
14
const Describe = process.env.TEST_ZFS ? describe : describe.skip;
15
const describe0 = describe;
16
export { Describe as describe, describe0 };
17
18
export async function init() {
19
if (!context.PREFIX.includes("test")) {
20
throw Error("context.PREFIX must contain 'test'");
21
}
22
await initDataDir();
23
resetDb();
24
}
25
26
export async function createTestPools({
27
size = "10G",
28
count = 1,
29
prefix,
30
}: {
31
size?: string;
32
count?: number;
33
prefix?: string;
34
}): Promise<{ tempDir: string; pools: string[]; prefix?: string }> {
35
setContext({ prefix });
36
if (!context.PREFIX.includes("test")) {
37
throw Error(`context.PREFIX=${context.PREFIX} must contain 'test'`);
38
}
39
// Create temp directory
40
const tempDir = await mkdtemp(join(tmpdir(), "test-"));
41
const pools: string[] = [];
42
// in case pools left from a failing test:
43
for (const pool of Object.keys(await getPools())) {
44
try {
45
await executeCode({
46
command: "sudo",
47
args: ["zpool", "destroy", pool],
48
});
49
} catch {}
50
}
51
for (let n = 0; n < count; n++) {
52
const image = join(tempDir, `${n}`, "0.img");
53
await executeCode({
54
command: "mkdir",
55
args: [join(tempDir, `${n}`)],
56
});
57
await executeCode({
58
command: "truncate",
59
args: ["-s", size, image],
60
});
61
const pool = `${context.PREFIX}-${n}`;
62
pools.push(pool);
63
await executeCode({
64
command: "sudo",
65
args: ["zpool", "create", pool, image],
66
});
67
}
68
// ensure pool cache is cleared:
69
await getPools({ noCache: true });
70
return { tempDir, pools, prefix };
71
}
72
73
// Even after setting sharefnfs=off, it can be a while (a minute?) until NFS
74
// fully frees up the share so we can destroy the pool. This makes it instant,
75
// which is very useful for unit testing.
76
export async function restartNfsServer() {
77
await executeCode({
78
command: "sudo",
79
args: ["service", "nfs-kernel-server", "restart"],
80
});
81
}
82
83
export async function deleteTestPools(x?: {
84
tempDir: string;
85
pools: string[];
86
prefix?: string;
87
}) {
88
if (!x) {
89
return;
90
}
91
const { tempDir, pools, prefix } = x;
92
setContext({ prefix });
93
if (!context.PREFIX.includes("test")) {
94
throw Error("context.PREFIX must contain 'test'");
95
}
96
97
const f = async (pool) => {
98
try {
99
await executeCode({
100
command: "sudo",
101
args: ["zpool", "destroy", pool],
102
});
103
} catch (err) {
104
// if (!`$err}`.includes("no such pool")) {
105
// console.log(err);
106
// }
107
}
108
};
109
await asyncMap(pools, pools.length, f);
110
await rm(tempDir, { recursive: true });
111
}
112
113