Skip to content

Commit 2ca6080

Browse files
committed
feat: add sandbox new command
1 parent 10c3211 commit 2ca6080

2 files changed

Lines changed: 75 additions & 31 deletions

File tree

main.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import token_storage from "./token_storage.ts";
1919
import {
2020
sandboxKillCommand,
2121
sandboxListCommand,
22+
sandboxNewCommand,
2223
sandboxSshCommand,
2324
} from "./sandbox.ts";
2425

@@ -176,6 +177,7 @@ const sandboxCommand = new Command<GlobalOptions>()
176177
.action(() => {
177178
sandboxCommand.showHelp();
178179
})
180+
.command("new", sandboxNewCommand)
179181
.command("list", sandboxListCommand)
180182
.command("kill", sandboxKillCommand)
181183
.command("ssh", sandboxSshCommand);

sandbox.ts

Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,41 @@ type SandboxContext = GlobalOptions & {
1111
org?: string;
1212
};
1313

14+
export const sandboxNewCommand = new Command<SandboxContext>()
15+
.description("Create a new sandbox in an organization")
16+
.action(async (options) => {
17+
const org = await ensureOrg(options);
18+
const client = createTrpcClient(options.debug, options.endpoint);
19+
20+
// deno-lint-ignore no-explicit-any
21+
const token = await (client.orgs as any).accessTokens.create.mutate({
22+
org,
23+
description: "$$DENO_DEPLOY_CLI_SSH_TOKEN$$",
24+
expiresAt: new Date(Date.now() + 1000 * 60 * 60).toISOString(), // 1 hour
25+
});
26+
27+
const sandbox = await Sandbox.create({
28+
debug: options.debug,
29+
token: token.token,
30+
});
31+
32+
const success = await sshIntoSandbox(sandbox);
33+
const stopMessage = "Stopping the sandbox...";
34+
if (success) {
35+
// Closes the sandbox only when ssh session was established and finished successfully
36+
await sandbox.close();
37+
console.log(stopMessage);
38+
} else {
39+
// Otherwise, keep the sandbox running and wait for Ctrl+C
40+
console.log("\nCtrl+C to stop the sandbox.");
41+
Deno.addSignalListener("SIGINT", async () => {
42+
console.log("\n" + stopMessage);
43+
await sandbox.close();
44+
Deno.exit();
45+
});
46+
}
47+
});
48+
1449
export const sandboxListCommand = new Command<SandboxContext>()
1550
.description("List all sandboxes in an organization")
1651
.action(async (options) => {
@@ -130,37 +165,7 @@ export const sandboxSshCommand = new Command<SandboxContext>()
130165
debug: options.debug,
131166
token: token.token,
132167
});
133-
134-
const ssh = await sandbox.exposeSsh();
135-
136-
const connectInfo = ssh.username + "@" + ssh.hostname;
137-
138-
const which = await new Deno.Command("which", {
139-
args: ["ssh"],
140-
stdout: "null",
141-
stderr: "null",
142-
}).output();
143-
144-
if (which.success) {
145-
// If ssh is available, directly spawn ssh process
146-
console.log(`ssh ${connectInfo}`);
147-
const command = new Deno.Command("ssh", {
148-
args: [connectInfo],
149-
stdin: "inherit",
150-
stdout: "inherit",
151-
stderr: "inherit",
152-
});
153-
154-
const _sshProcess = command.spawn();
155-
} else {
156-
// Fallback: just print the connection info
157-
console.log(
158-
`Started ssh session. You can now connect to ${magenta(connectInfo)}
159-
160-
Example:
161-
ssh ${connectInfo}`,
162-
);
163-
}
168+
await sshIntoSandbox(sandbox);
164169
});
165170

166171
async function ensureOrg(options: SandboxContext) {
@@ -176,6 +181,43 @@ async function ensureOrg(options: SandboxContext) {
176181
)).org;
177182
}
178183

184+
/**
185+
* Make an ssh connection to the running sandbox. Returns true if ssh session
186+
* was successfully created and finished, false when ssh is not available and
187+
* connection info was printed instead.
188+
*/
189+
async function sshIntoSandbox(sandbox: Sandbox): Promise<boolean> {
190+
const ssh = await sandbox.exposeSsh();
191+
const connectInfo = ssh.username + "@" + ssh.hostname;
192+
193+
const which = await new Deno.Command("which", {
194+
args: ["ssh_"],
195+
stdout: "null",
196+
stderr: "null",
197+
}).output();
198+
if (which.success) {
199+
console.log(`ssh ${connectInfo}`);
200+
const command = new Deno.Command("ssh", {
201+
args: [connectInfo],
202+
stdin: "inherit",
203+
stdout: "inherit",
204+
stderr: "inherit",
205+
});
206+
const sshProcess = await command.spawn();
207+
await sshProcess.output();
208+
await sandbox.close();
209+
return true;
210+
} else {
211+
console.log(
212+
`Started ssh session. You can now connect to ${magenta(connectInfo)}
213+
214+
Example:
215+
ssh ${connectInfo}`,
216+
);
217+
return false;
218+
}
219+
}
220+
179221
/**
180222
* Format duration in ms to human readable string
181223
*

0 commit comments

Comments
 (0)