Skip to content

Commit d5da761

Browse files
committed
WIP multi nodes
1 parent ec0d541 commit d5da761

20 files changed

+489
-114
lines changed

.envrc

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
use flake
2+
if [[ -f "./.env" ]]; then source "./.env"; fi

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/.vscode
22
/.zsh_history
33
.ssh
4-
/result
4+
/result
5+
/.env

deno.lock

+115-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/multi/.secrets/join.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"url": "https://192.168.2.152:6443",
3+
"token": "K103daab472e6b01fe590a22d779bcf6198da3a036849f7ca175c8f717b2ad66684::server:114d6916eec0ed6c94cc2c32bf4602cb"
4+
}

examples/multi/multi-one.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ServerInstanceConfig } from "../../src/types.ts";
2+
3+
export default {
4+
name: "jetski-multi-node-one",
5+
image: "22.04",
6+
cpus: 1,
7+
memoryGiBs: 2,
8+
diskGiBs: 5,
9+
k3sVersion: "v1.24.17+k3s1",
10+
serviceCidr: "10.254.251.0/24",
11+
clusterCidr: "10.254.252.0/22",
12+
clusterDnsIp: "10.254.255.10",
13+
clusterDomain: "jetski.local",
14+
bridged: Boolean(Deno.env.get("JETSKI_INSTANCE_BRIDGED")),
15+
externalNetworkCidr: Deno.env.get("JETSKI_INSTANCE_NODE_IP_CIDR"),
16+
externalNetworkInterface: "eth1",
17+
disableComponents: {
18+
traefik: true,
19+
metricsServer: true
20+
},
21+
nodeLabels: {
22+
"com.jetski/foo": "bar",
23+
"com.jetski/baz": "boo",
24+
},
25+
// datastoreEndpoint: "http://192.168.2.22:2379"
26+
kubelet: {
27+
maxPods: 500
28+
},
29+
isBootstrapInstance: true,
30+
sshDirectoryPath: "./.secrets/.ssh",
31+
joinMetadataPath: "./.secrets/join.json",
32+
} satisfies ServerInstanceConfig;

examples/multi/multi-two.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { ServerInstanceConfig } from "../../src/types.ts";
2+
import bootstrapInstanceConfig from "./multi-one.ts";
3+
4+
export default {
5+
...bootstrapInstanceConfig,
6+
name: "jetski-multi-node-two",
7+
image: "22.04",
8+
cpus: 1,
9+
memoryGiBs: 2,
10+
diskGiBs: 5,
11+
nodeLabels: {
12+
"com.jetski/foo": "bar",
13+
"com.jetski/baz": "boo",
14+
},
15+
isBootstrapInstance: false
16+
} satisfies ServerInstanceConfig;
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { InstanceConfig } from "../src/types.ts";
1+
import { ServerInstanceConfig } from "../../src/types.ts";
22

33
export default {
4-
name: "jetski-example",
4+
name: "jetski-single-node",
55
image: "22.04",
66
cpus: 1,
77
memoryGiBs: 2,
@@ -11,8 +11,8 @@ export default {
1111
serviceCidr: "10.254.255.0/24",
1212
clusterDnsIp: "10.254.255.10",
1313
clusterDomain: "jetski.local",
14-
bridged: true,
15-
filterSshIpByCidr: "192.168.2.0/24",
14+
bridged: Boolean(Deno.env.get("JETSKI_INSTANCE_BRIDGED")),
15+
externalNetworkCidr: Deno.env.get("JETSKI_INSTANCE_FILTER_SSH_IP_BY_CIDR"),
1616
disableComponents: {
1717
traefik: true,
1818
metricsServer: true
@@ -21,9 +21,9 @@ export default {
2121
"com.jetski/foo": "bar",
2222
"com.jetski/baz": "boo",
2323
},
24-
sshDirectoryPath: "./local/.ssh",
24+
sshDirectoryPath: "./.ssh",
2525
// datastoreEndpoint: "http://192.168.2.22:2379"
2626
kubelet: {
2727
maxPods: 500
2828
}
29-
} as InstanceConfig;
29+
} satisfies ServerInstanceConfig;

src/actions/create.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ export async function updateKubeconfig(
8080
ok("Kubeconfig has been updated. The current context should now be", cyan(name));
8181
}
8282

83-
export async function createInstance(instance: InstanceConfig) {
83+
export async function createInstance(instance: InstanceConfig, signal: AbortSignal) {
8484
const { sshDirectoryPath, cpus, memoryGiBs, diskGiBs, image, name, bridged } = instance;
8585

8686
await generateSshKeyPairIfNotExists(instance);
8787

8888
const sshPublicKey = await getSshPublicKey(sshDirectoryPath);
89-
const cloudInitConfig = createCloudInitConfig({ sshPublicKey, instance });
89+
const cloudInitConfig = await createCloudInitConfig({ sshPublicKey, instance });
9090
const tempDir = await Deno.makeTempDir();
9191
const cloudInitFilePath = joinPath(tempDir, "cloud-init.yaml");
9292
log("Generated cloud-init.yaml");
@@ -163,20 +163,22 @@ export async function createInstance(instance: InstanceConfig) {
163163
// Ignore
164164
}
165165

166-
const ip = await multipassPostStart(instance);
166+
const ip = await multipassPostStart(instance, signal);
167167

168-
await updateKubeconfig({ ip, instance });
168+
if (instance.isBootstrapInstance) {
169+
await updateKubeconfig({ ip, instance });
170+
}
169171
}
170172

171173
export default createCliAction(
172174
Type.Object({
173175
config: InstanceConfigPathSchema,
174176
}),
175-
async ({ config: configPath }) => {
177+
async ({ config: configPath }, _, signal) => {
176178
const absoluteConfigPath = resolvePath(configPath);
177179
const instance = await loadInstanceConfig(absoluteConfigPath);
178180

179-
await createInstance(instance);
181+
await createInstance(instance, signal);
180182

181183
return ExitCode.Zero;
182184
},

src/actions/destroy.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ export async function destroyInstance(instance: InstanceConfig) {
88
const { state, ipv4 } = await multipassInfo(instance);
99

1010
if (state === InstanceState.Running) {
11-
const ip = getSshIp(ipv4, instance.filterSshIpByCidr);
12-
await multipassUnroute({ ip, instance });
11+
const ip = getSshIp(ipv4, instance.externalNetworkCidr);
12+
13+
if (instance.isBootstrapInstance) {
14+
await multipassUnroute({ ip, instance });
15+
}
16+
1317
await multipassK3sKillAll({ ip, sshDirectoryPath });
1418
await multipassStop(instance);
1519
}

src/actions/refresh.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default createCliAction(
88
Type.Object({
99
config: InstanceConfigPathSchema,
1010
}),
11-
async ({ config: configPath }) => {
11+
async ({ config: configPath }, _, signal) => {
1212
const absoluteConfigPath = resolvePath(configPath);
1313
const instance = await loadInstanceConfig(absoluteConfigPath);
1414
const { name } = instance;
@@ -18,7 +18,7 @@ export default createCliAction(
1818
throw new Error(`Instance '${name}' is not in 'Running' state. Current state is '${state}'`);
1919
}
2020

21-
const ip = await multipassPostStart(instance);
21+
const ip = await multipassPostStart(instance, signal);
2222
await updateKubeconfig({ ip, instance });
2323

2424
ok(`Local routes and kubeconfig for instance '${name}' have been updated with IP: ${ip}`);

src/actions/reset.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export default createCliAction(
1111
default: false,
1212
})),
1313
}),
14-
async ({ config: configPath, skipConfirm }) => {
14+
async ({ config: configPath, skipConfirm }, _, signal) => {
1515
const absoluteConfigPath = resolvePath(configPath);
1616
const instance = await loadInstanceConfig(absoluteConfigPath);
1717
const { name } = instance;
@@ -28,7 +28,7 @@ export default createCliAction(
2828
}
2929

3030
await destroyInstance(instance);
31-
await createInstance(instance);
31+
await createInstance(instance, signal);
3232

3333
return ExitCode.Zero;
3434
},

src/actions/ssh.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ export default createCliAction(
1919
throw new Error(`Instance '${name}' is not in 'Running' state. Current state is '${state}'`);
2020
}
2121

22+
const ip = getSshIp(ipv4, instance.externalNetworkCidr);
23+
log(gray(`Instance IP is '${ip}'`));
24+
2225
const exitCode = await multipassSshInteractive({
2326
cmd: unparsedArgs,
2427
sshDirectoryPath,
25-
ip: getSshIp(ipv4, instance.filterSshIpByCidr),
28+
ip: getSshIp(ipv4, instance.externalNetworkCidr),
2629
});
2730

2831
return new ExitCode(exitCode);

src/actions/start.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default createCliAction(
88
Type.Object({
99
config: InstanceConfigPathSchema,
1010
}),
11-
async ({ config: configPath }) => {
11+
async ({ config: configPath }, _, signal) => {
1212
const absoluteConfigPath = resolvePath(configPath);
1313
const instance = await loadInstanceConfig(absoluteConfigPath);
1414
const { name } = instance;
@@ -21,8 +21,11 @@ export default createCliAction(
2121
}
2222

2323
await multipassStart(instance);
24-
const ip = await multipassPostStart(instance);
25-
await updateKubeconfig({ ip, instance });
24+
const ip = await multipassPostStart(instance, signal);
25+
26+
if (instance.isBootstrapInstance) {
27+
await updateKubeconfig({ ip, instance });
28+
}
2629

2730
ok(`Instance '${name}' has been started`);
2831

src/actions/stop.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ export default createCliAction(
1818
throw new Error(`Instance '${name}' is not in 'Running' state. Current state is '${state}'`);
1919
}
2020

21-
const ip = getSshIp(ipv4, instance.filterSshIpByCidr);
21+
const ip = getSshIp(ipv4, instance.externalNetworkCidr);
2222

23-
await multipassUnroute({ ip, instance });
23+
if (instance.isBootstrapInstance) {
24+
await multipassUnroute({ ip, instance });
25+
}
2426
await multipassK3sKillAll({ ip, sshDirectoryPath });
2527
await multipassStop(instance);
2628

src/actions/suspend.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ export default createCliAction(
1818
throw new Error(`Instance '${name}' is not in 'Running' state. Current state is '${state}'`);
1919
}
2020

21-
const ip = getSshIp(ipv4, instance.filterSshIpByCidr);
21+
const ip = getSshIp(ipv4, instance.externalNetworkCidr);
2222

23-
await multipassUnroute({ ip, instance });
23+
if (instance.isBootstrapInstance) {
24+
await multipassUnroute({ ip, instance });
25+
}
2426
await multipassSuspend(instance);
2527

2628
ok(`Instance '${name}' has been suspended`);

src/deps.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
export * from "https://deno.land/x/utils@2.15.2/cli_utils.ts";
2-
export * from "https://deno.land/x/utils@2.15.2/exec_utils.ts";
3-
export * from "https://deno.land/x/utils@2.15.2/deps/typebox.ts";
4-
export * from "https://deno.land/x/[email protected]/validation_utils.ts";
5-
export type { ValidationResult } from "https://deno.land/x/utils@2.15.2/validation_utils.ts";
1+
export * from "https://deno.land/x/utils@2.17.0/cli_utils.ts";
2+
export * from "https://deno.land/x/utils@2.17.0/exec_utils.ts";
3+
export * from "https://deno.land/x/utils@2.17.0/validation_utils.ts";
4+
export * from "./deps/typebox.ts";
5+
export type { ValidationResult } from "https://deno.land/x/utils@2.17.0/validation_utils.ts";
66
export * from "https://deno.land/[email protected]/fmt/colors.ts";
77

88
export {
@@ -18,7 +18,8 @@ export { parse as parseYaml, stringify as stringifyYaml } from "https://deno.lan
1818
export type { YAMLError } from "https://deno.land/[email protected]/yaml/_error.ts";
1919

2020
export { exists as fsExists } from "https://deno.land/[email protected]/fs/exists.ts";
21+
export { ensureFile } from "https://deno.land/[email protected]/fs/ensure_file.ts";
2122
export { assertExists } from "https://deno.land/[email protected]/assert/assert_exists.ts";
22-
export { memoizePromise } from "https://deno.land/x/utils@2.15.2/async_utils.ts";
23+
export { memoizePromise } from "https://deno.land/x/utils@2.17.0/async_utils.ts";
2324

2425
export { delay } from "https://deno.land/[email protected]/async/delay.ts";

src/deps/typebox.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "https://deno.land/x/[email protected]/deps/typebox.ts";
2+
export * from "https://deno.land/x/[email protected]/typebox_utils.ts";

0 commit comments

Comments
 (0)