A simple, powerful CLI tool to spin up OpenIndiana virtual machines with QEMU
1import chalk from "chalk";
2
3export async function setupQemuBridge(bridgeName: string): Promise<void> {
4 const bridgeConfPath = "/etc/qemu/bridge.conf";
5 const bridgeConfContent = await Deno.readTextFile(bridgeConfPath).catch(
6 () => "",
7 );
8 if (bridgeConfContent.includes(`allow ${bridgeName}`)) {
9 console.log(
10 chalk.greenBright(
11 `QEMU bridge configuration for ${bridgeName} already exists.`,
12 ),
13 );
14 return;
15 }
16
17 console.log(
18 chalk.blueBright(
19 `Adding QEMU bridge configuration for ${bridgeName}...`,
20 ),
21 );
22
23 const cmd = new Deno.Command("sudo", {
24 args: [
25 "sh",
26 "-c",
27 `mkdir -p /etc/qemu && echo "allow ${bridgeName}" >> ${bridgeConfPath}`,
28 ],
29 stdin: "inherit",
30 stdout: "inherit",
31 stderr: "inherit",
32 });
33 const status = await cmd.spawn().status;
34
35 if (!status.success) {
36 console.error(
37 chalk.redBright(
38 `Failed to add QEMU bridge configuration for ${bridgeName}.`,
39 ),
40 );
41 Deno.exit(status.code);
42 }
43
44 console.log(
45 chalk.greenBright(
46 `QEMU bridge configuration for ${bridgeName} added successfully.`,
47 ),
48 );
49}
50
51export async function createBridgeNetworkIfNeeded(
52 bridgeName: string,
53): Promise<void> {
54 const bridgeExistsCmd = new Deno.Command("ip", {
55 args: ["link", "show", bridgeName],
56 stdout: "null",
57 stderr: "null",
58 });
59
60 const bridgeExistsStatus = await bridgeExistsCmd.spawn().status;
61 if (bridgeExistsStatus.success) {
62 console.log(
63 chalk.greenBright(`Network bridge ${bridgeName} already exists.`),
64 );
65 await setupQemuBridge(bridgeName);
66 return;
67 }
68
69 console.log(chalk.blueBright(`Creating network bridge ${bridgeName}...`));
70 const createBridgeCmd = new Deno.Command("sudo", {
71 args: ["ip", "link", "add", bridgeName, "type", "bridge"],
72 stdin: "inherit",
73 stdout: "inherit",
74 stderr: "inherit",
75 });
76
77 let status = await createBridgeCmd.spawn().status;
78 if (!status.success) {
79 console.error(
80 chalk.redBright(`Failed to create network bridge ${bridgeName}.`),
81 );
82 Deno.exit(status.code);
83 }
84
85 const bringUpBridgeCmd = new Deno.Command("sudo", {
86 args: ["ip", "link", "set", "dev", bridgeName, "up"],
87 stdin: "inherit",
88 stdout: "inherit",
89 stderr: "inherit",
90 });
91 status = await bringUpBridgeCmd.spawn().status;
92 if (!status.success) {
93 console.error(
94 chalk.redBright(`Failed to bring up network bridge ${bridgeName}.`),
95 );
96 Deno.exit(status.code);
97 }
98
99 console.log(
100 chalk.greenBright(`Network bridge ${bridgeName} created and up.`),
101 );
102
103 await setupQemuBridge(bridgeName);
104}
105
106export function generateRandomMacAddress(): string {
107 const hexDigits = "0123456789ABCDEF";
108 let macAddress = "52:54:00";
109
110 for (let i = 0; i < 3; i++) {
111 macAddress += ":";
112 for (let j = 0; j < 2; j++) {
113 macAddress += hexDigits.charAt(
114 Math.floor(Math.random() * hexDigits.length),
115 );
116 }
117 }
118
119 return macAddress;
120}