openlattice-ssh 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +30 -0
- package/dist/config.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/ssh-provider.d.ts +30 -0
- package/dist/ssh-provider.js +441 -0
- package/package.json +38 -0
- package/src/config.ts +42 -0
- package/src/index.ts +2 -0
- package/src/ssh-provider.ts +559 -0
- package/tests/conformance.test.ts +28 -0
- package/tests/integration.test.ts +152 -0
- package/tests/ssh-provider.test.ts +778 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterEach } from "vitest";
|
|
2
|
+
import { SSHProvider } from "../src/ssh-provider";
|
|
3
|
+
|
|
4
|
+
const HAS_SSH = process.env.TEST_SSH === "1";
|
|
5
|
+
|
|
6
|
+
describe.skipIf(!HAS_SSH)("SSHProvider integration", () => {
|
|
7
|
+
let provider: SSHProvider;
|
|
8
|
+
const toCleanup: string[] = [];
|
|
9
|
+
|
|
10
|
+
beforeAll(() => {
|
|
11
|
+
provider = new SSHProvider({
|
|
12
|
+
hosts: [
|
|
13
|
+
{
|
|
14
|
+
host: process.env.SSH_HOST ?? "localhost",
|
|
15
|
+
port: parseInt(process.env.SSH_PORT ?? "22", 10),
|
|
16
|
+
username: process.env.SSH_USER ?? "root",
|
|
17
|
+
privateKey: process.env.SSH_KEY,
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(async () => {
|
|
24
|
+
for (const id of toCleanup) {
|
|
25
|
+
try {
|
|
26
|
+
await provider.destroy(id);
|
|
27
|
+
} catch {
|
|
28
|
+
/* best-effort */
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
toCleanup.length = 0;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it(
|
|
35
|
+
"provisions, execs, and destroys",
|
|
36
|
+
async () => {
|
|
37
|
+
const node = await provider.provision({
|
|
38
|
+
runtime: { image: "any" },
|
|
39
|
+
});
|
|
40
|
+
toCleanup.push(node.externalId);
|
|
41
|
+
|
|
42
|
+
expect(node.externalId).toBeTruthy();
|
|
43
|
+
|
|
44
|
+
const result = await provider.exec(node.externalId, [
|
|
45
|
+
"echo",
|
|
46
|
+
"hello from ssh",
|
|
47
|
+
]);
|
|
48
|
+
expect(result.exitCode).toBe(0);
|
|
49
|
+
expect(result.stdout).toContain("hello from ssh");
|
|
50
|
+
|
|
51
|
+
await provider.destroy(node.externalId);
|
|
52
|
+
toCleanup.pop();
|
|
53
|
+
|
|
54
|
+
const status = await provider.inspect(node.externalId);
|
|
55
|
+
expect(status.status).toBe("terminated");
|
|
56
|
+
},
|
|
57
|
+
30_000
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
it(
|
|
61
|
+
"exec captures stderr and exit codes",
|
|
62
|
+
async () => {
|
|
63
|
+
const node = await provider.provision({
|
|
64
|
+
runtime: { image: "any" },
|
|
65
|
+
});
|
|
66
|
+
toCleanup.push(node.externalId);
|
|
67
|
+
|
|
68
|
+
const result = await provider.exec(node.externalId, [
|
|
69
|
+
"sh",
|
|
70
|
+
"-c",
|
|
71
|
+
"echo err >&2; exit 42",
|
|
72
|
+
]);
|
|
73
|
+
expect(result.exitCode).toBe(42);
|
|
74
|
+
expect(result.stderr).toContain("err");
|
|
75
|
+
},
|
|
76
|
+
30_000
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
it(
|
|
80
|
+
"exec supports cwd and env",
|
|
81
|
+
async () => {
|
|
82
|
+
const node = await provider.provision({
|
|
83
|
+
runtime: { image: "any" },
|
|
84
|
+
});
|
|
85
|
+
toCleanup.push(node.externalId);
|
|
86
|
+
|
|
87
|
+
const result = await provider.exec(node.externalId, [
|
|
88
|
+
"sh",
|
|
89
|
+
"-c",
|
|
90
|
+
"echo $MY_VAR",
|
|
91
|
+
], { env: { MY_VAR: "test123" } });
|
|
92
|
+
expect(result.stdout).toContain("test123");
|
|
93
|
+
},
|
|
94
|
+
30_000
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
it(
|
|
98
|
+
"inspect returns running status",
|
|
99
|
+
async () => {
|
|
100
|
+
const node = await provider.provision({
|
|
101
|
+
runtime: { image: "any" },
|
|
102
|
+
});
|
|
103
|
+
toCleanup.push(node.externalId);
|
|
104
|
+
|
|
105
|
+
const status = await provider.inspect(node.externalId);
|
|
106
|
+
expect(status.status).toBe("running");
|
|
107
|
+
},
|
|
108
|
+
30_000
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
it(
|
|
112
|
+
"healthCheck returns healthy",
|
|
113
|
+
async () => {
|
|
114
|
+
const health = await provider.healthCheck();
|
|
115
|
+
expect(health.healthy).toBe(true);
|
|
116
|
+
},
|
|
117
|
+
30_000
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
it(
|
|
121
|
+
"file extension reads and writes via SFTP",
|
|
122
|
+
async () => {
|
|
123
|
+
const node = await provider.provision({
|
|
124
|
+
runtime: { image: "any" },
|
|
125
|
+
});
|
|
126
|
+
toCleanup.push(node.externalId);
|
|
127
|
+
|
|
128
|
+
const files = provider.getExtension(node.externalId, "files")!;
|
|
129
|
+
expect(files).toBeDefined();
|
|
130
|
+
|
|
131
|
+
await files.write("/tmp/openlattice-test.txt", "hello ssh");
|
|
132
|
+
const content = await files.read("/tmp/openlattice-test.txt");
|
|
133
|
+
expect(content).toContain("hello ssh");
|
|
134
|
+
},
|
|
135
|
+
30_000
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
it(
|
|
139
|
+
"destroy is idempotent",
|
|
140
|
+
async () => {
|
|
141
|
+
const node = await provider.provision({
|
|
142
|
+
runtime: { image: "any" },
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
await provider.destroy(node.externalId);
|
|
146
|
+
await expect(
|
|
147
|
+
provider.destroy(node.externalId)
|
|
148
|
+
).resolves.toBeUndefined();
|
|
149
|
+
},
|
|
150
|
+
30_000
|
|
151
|
+
);
|
|
152
|
+
});
|