@khal-os/cli 1.0.2 → 1.0.4
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/index.js +83 -44
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -15546,14 +15546,22 @@ __export(exports_kubernetes, {
|
|
|
15546
15546
|
KubernetesRuntime: () => KubernetesRuntime
|
|
15547
15547
|
});
|
|
15548
15548
|
import { execFile } from "node:child_process";
|
|
15549
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
15549
15550
|
import { promisify } from "node:util";
|
|
15550
|
-
|
|
15551
|
+
function isInCluster() {
|
|
15552
|
+
if (_inClusterCached !== undefined)
|
|
15553
|
+
return _inClusterCached;
|
|
15554
|
+
_inClusterCached = existsSync6(IN_CLUSTER_TOKEN_PATH) && !!process.env.KUBERNETES_SERVICE_HOST;
|
|
15555
|
+
return _inClusterCached;
|
|
15556
|
+
}
|
|
15557
|
+
var exec, IN_CLUSTER_TOKEN_PATH = "/var/run/secrets/kubernetes.io/serviceaccount/token", _inClusterCached, DEFAULT_KUBECONFIG = "/etc/rancher/k3s/k3s.yaml", DEFAULT_NATS_URL = "nats://nats:4222", DEFAULT_RESOURCES, SANDBOX_RUNTIME_CLASS = "sysbox-runc", SANDBOX_PVC_SIZE = "20Gi", SANDBOX_STORAGE_CLASS = "local-path", SANDBOX_SSH_PORT = 22, SANDBOX_NAMESPACE = "khal-sandbox", SANDBOX_HELM_CHART, SANDBOX_RESOURCES, KubernetesRuntime;
|
|
15551
15558
|
var init_kubernetes = __esm(() => {
|
|
15552
15559
|
exec = promisify(execFile);
|
|
15553
15560
|
DEFAULT_RESOURCES = {
|
|
15554
15561
|
requests: { cpu: "100m", memory: "256Mi" },
|
|
15555
15562
|
limits: { cpu: "1", memory: "1Gi" }
|
|
15556
15563
|
};
|
|
15564
|
+
SANDBOX_HELM_CHART = process.env.KHAL_SANDBOX_CHART_PATH ?? "helm/khal-sandbox";
|
|
15557
15565
|
SANDBOX_RESOURCES = {
|
|
15558
15566
|
requests: { cpu: "500m", memory: "1Gi" },
|
|
15559
15567
|
limits: { cpu: "2", memory: "4Gi" }
|
|
@@ -15586,7 +15594,11 @@ var init_kubernetes = __esm(() => {
|
|
|
15586
15594
|
const kc = config;
|
|
15587
15595
|
const slug = kc.appSlug ?? "app";
|
|
15588
15596
|
const id = kc.instanceId ?? slug;
|
|
15589
|
-
|
|
15597
|
+
if (isInCluster()) {
|
|
15598
|
+
this.kubeconfig = "";
|
|
15599
|
+
} else {
|
|
15600
|
+
this.kubeconfig = kc.kubeconfig ?? process.env.KUBECONFIG ?? DEFAULT_KUBECONFIG;
|
|
15601
|
+
}
|
|
15590
15602
|
this.natsUrl = kc.natsUrl ?? DEFAULT_NATS_URL;
|
|
15591
15603
|
this.nodePort = kc.nodePort;
|
|
15592
15604
|
this.sandboxMode = kc.sandboxMode ?? false;
|
|
@@ -15598,13 +15610,14 @@ var init_kubernetes = __esm(() => {
|
|
|
15598
15610
|
this.domainSuffix = kc.domainSuffix;
|
|
15599
15611
|
if (this.sandboxMode) {
|
|
15600
15612
|
const user = kc.userId ?? id;
|
|
15613
|
+
const safeUser = user.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
15601
15614
|
this.runtimeClassName = kc.runtimeClassName ?? SANDBOX_RUNTIME_CLASS;
|
|
15602
|
-
this.namespace =
|
|
15603
|
-
this.podName = `sandbox-${
|
|
15604
|
-
this.serviceName = `sandbox-${
|
|
15605
|
-
this.helmRelease = `sandbox-${
|
|
15615
|
+
this.namespace = SANDBOX_NAMESPACE;
|
|
15616
|
+
this.podName = `sandbox-${safeUser}-0`.slice(0, 63);
|
|
15617
|
+
this.serviceName = `sandbox-${safeUser}`.slice(0, 63);
|
|
15618
|
+
this.helmRelease = `sandbox-${safeUser}`.slice(0, 53);
|
|
15606
15619
|
this.image = kc.image ?? "khal-os/sandbox:latest";
|
|
15607
|
-
this.instanceId = kc.instanceId ?? `sandbox-${
|
|
15620
|
+
this.instanceId = kc.instanceId ?? `sandbox-${safeUser}`;
|
|
15608
15621
|
this.resources = kc.resources ?? SANDBOX_RESOURCES;
|
|
15609
15622
|
} else {
|
|
15610
15623
|
this.runtimeClassName = kc.runtimeClassName;
|
|
@@ -15690,19 +15703,18 @@ var init_kubernetes = __esm(() => {
|
|
|
15690
15703
|
this.assignedPort = await this.resolveNodePort();
|
|
15691
15704
|
}
|
|
15692
15705
|
async startSandbox() {
|
|
15693
|
-
await this.applyManifest(this.namespaceManifest());
|
|
15694
15706
|
const setArgs = this.buildHelmValues();
|
|
15695
15707
|
const helmArgs = [
|
|
15708
|
+
...this.kubeconfigArgs(),
|
|
15696
15709
|
"upgrade",
|
|
15697
15710
|
"--install",
|
|
15698
15711
|
this.helmRelease,
|
|
15699
15712
|
this.helmChart,
|
|
15700
15713
|
"--namespace",
|
|
15701
15714
|
this.namespace,
|
|
15702
|
-
"--create-namespace",
|
|
15703
15715
|
"--wait",
|
|
15704
15716
|
"--timeout",
|
|
15705
|
-
"
|
|
15717
|
+
"180s",
|
|
15706
15718
|
...setArgs
|
|
15707
15719
|
];
|
|
15708
15720
|
this.emit({
|
|
@@ -15712,12 +15724,12 @@ var init_kubernetes = __esm(() => {
|
|
|
15712
15724
|
message: `helm ${helmArgs.join(" ")}`
|
|
15713
15725
|
});
|
|
15714
15726
|
try {
|
|
15715
|
-
await exec("helm", helmArgs, { timeout:
|
|
15727
|
+
await exec("helm", helmArgs, { timeout: 240000 });
|
|
15716
15728
|
} catch (err) {
|
|
15717
15729
|
const msg = err instanceof Error ? err.message : String(err);
|
|
15718
|
-
throw new Error(`
|
|
15730
|
+
throw new Error(`helm upgrade --install ${this.helmRelease} failed: ${msg}`);
|
|
15719
15731
|
}
|
|
15720
|
-
await this.waitForPod(
|
|
15732
|
+
await this.waitForPod(240000);
|
|
15721
15733
|
}
|
|
15722
15734
|
buildHelmValues() {
|
|
15723
15735
|
const sets = [];
|
|
@@ -15728,25 +15740,48 @@ var init_kubernetes = __esm(() => {
|
|
|
15728
15740
|
set("image.tag", this.image.split(":")[1] ?? "latest");
|
|
15729
15741
|
if (this.userId)
|
|
15730
15742
|
set("user.id", this.userId);
|
|
15731
|
-
|
|
15743
|
+
const natsHost = this.parseNatsHost();
|
|
15744
|
+
const natsPort = this.parseNatsPort();
|
|
15745
|
+
set("nats.centralHost", natsHost);
|
|
15746
|
+
set("nats.centralPort", natsPort);
|
|
15732
15747
|
set("resources.requests.cpu", this.resources.requests?.cpu ?? SANDBOX_RESOURCES.requests.cpu);
|
|
15733
15748
|
set("resources.requests.memory", this.resources.requests?.memory ?? SANDBOX_RESOURCES.requests.memory);
|
|
15734
15749
|
set("resources.limits.cpu", this.resources.limits?.cpu ?? SANDBOX_RESOURCES.limits.cpu);
|
|
15735
15750
|
set("resources.limits.memory", this.resources.limits?.memory ?? SANDBOX_RESOURCES.limits.memory);
|
|
15736
|
-
set("
|
|
15737
|
-
|
|
15751
|
+
set("storage.size", this.pvcSize);
|
|
15752
|
+
if (this.storageClass)
|
|
15753
|
+
set("storage.className", this.storageClass);
|
|
15738
15754
|
set("ssh.port", this.sshPort);
|
|
15739
15755
|
if (this.sysboxAvailable && this.runtimeClassName) {
|
|
15740
|
-
set("
|
|
15756
|
+
set("runtime.className", this.runtimeClassName);
|
|
15741
15757
|
} else {
|
|
15742
|
-
set("
|
|
15758
|
+
set("runtime.className", "");
|
|
15743
15759
|
}
|
|
15744
15760
|
if (this.domainSuffix && this.userId) {
|
|
15745
|
-
set("
|
|
15746
|
-
set("
|
|
15761
|
+
set("domain.enabled", true);
|
|
15762
|
+
set("domain.base", this.domainSuffix);
|
|
15763
|
+
} else {
|
|
15764
|
+
set("domain.enabled", false);
|
|
15747
15765
|
}
|
|
15748
15766
|
return sets;
|
|
15749
15767
|
}
|
|
15768
|
+
parseNatsHost() {
|
|
15769
|
+
try {
|
|
15770
|
+
const u = new URL(this.natsUrl);
|
|
15771
|
+
return u.hostname || "nats";
|
|
15772
|
+
} catch {
|
|
15773
|
+
return this.natsUrl.replace(/^nats:\/\//, "").split(":")[0] || "nats";
|
|
15774
|
+
}
|
|
15775
|
+
}
|
|
15776
|
+
parseNatsPort() {
|
|
15777
|
+
try {
|
|
15778
|
+
const u = new URL(this.natsUrl);
|
|
15779
|
+
return u.port ? Number(u.port) : 4222;
|
|
15780
|
+
} catch {
|
|
15781
|
+
const match = this.natsUrl.match(/:(\d+)$/);
|
|
15782
|
+
return match ? Number(match[1]) : 4222;
|
|
15783
|
+
}
|
|
15784
|
+
}
|
|
15750
15785
|
async stop() {
|
|
15751
15786
|
if (!this.running)
|
|
15752
15787
|
return;
|
|
@@ -15765,7 +15800,7 @@ var init_kubernetes = __esm(() => {
|
|
|
15765
15800
|
}
|
|
15766
15801
|
async stopSandbox() {
|
|
15767
15802
|
try {
|
|
15768
|
-
await exec("helm", ["uninstall", this.helmRelease, "--namespace", this.namespace, "--wait"], { timeout: 60000 });
|
|
15803
|
+
await exec("helm", [...this.kubeconfigArgs(), "uninstall", this.helmRelease, "--namespace", this.namespace, "--wait"], { timeout: 60000 });
|
|
15769
15804
|
this.emit({
|
|
15770
15805
|
type: "log",
|
|
15771
15806
|
source: "kubernetes",
|
|
@@ -15923,15 +15958,19 @@ var init_kubernetes = __esm(() => {
|
|
|
15923
15958
|
spec
|
|
15924
15959
|
});
|
|
15925
15960
|
}
|
|
15961
|
+
kubeconfigArgs() {
|
|
15962
|
+
return this.kubeconfig ? ["--kubeconfig", this.kubeconfig] : [];
|
|
15963
|
+
}
|
|
15926
15964
|
async kubectl(args) {
|
|
15927
|
-
const { stdout } = await exec("kubectl", [
|
|
15965
|
+
const { stdout } = await exec("kubectl", [...this.kubeconfigArgs(), ...args], {
|
|
15928
15966
|
timeout: 30000
|
|
15929
15967
|
});
|
|
15930
15968
|
return stdout;
|
|
15931
15969
|
}
|
|
15932
15970
|
applyManifest(json) {
|
|
15971
|
+
const kubeArgs = this.kubeconfigArgs();
|
|
15933
15972
|
return new Promise((resolve3, reject) => {
|
|
15934
|
-
const child = execFile("kubectl", [
|
|
15973
|
+
const child = execFile("kubectl", [...kubeArgs, "apply", "-f", "-"], { timeout: 30000 }, (err) => err ? reject(err) : resolve3());
|
|
15935
15974
|
child.stdin?.write(json);
|
|
15936
15975
|
child.stdin?.end();
|
|
15937
15976
|
});
|
|
@@ -19947,22 +19986,22 @@ function decode(data) {
|
|
|
19947
19986
|
|
|
19948
19987
|
// src/commands/app.ts
|
|
19949
19988
|
var S = {
|
|
19950
|
-
list: "os.
|
|
19951
|
-
get: "os.
|
|
19952
|
-
register: "os.
|
|
19953
|
-
unregister: "os.
|
|
19954
|
-
disable: "os.
|
|
19955
|
-
enable: "os.
|
|
19956
|
-
storeList: "os.
|
|
19957
|
-
storeSubmit: "os.
|
|
19958
|
-
storeApprove: "os.
|
|
19959
|
-
storeReject: "os.
|
|
19960
|
-
runStart: "os.
|
|
19961
|
-
runEnd: "os.
|
|
19962
|
-
runList: "os.
|
|
19963
|
-
vote: "os.
|
|
19964
|
-
unvote: "os.
|
|
19965
|
-
metrics: "os.
|
|
19989
|
+
list: "os.apps.list",
|
|
19990
|
+
get: "os.apps.get",
|
|
19991
|
+
register: "os.apps.register",
|
|
19992
|
+
unregister: "os.apps.unregister",
|
|
19993
|
+
disable: "os.apps.disable",
|
|
19994
|
+
enable: "os.apps.enable",
|
|
19995
|
+
storeList: "os.apps.store.list",
|
|
19996
|
+
storeSubmit: "os.apps.store.submit",
|
|
19997
|
+
storeApprove: "os.apps.store.approve",
|
|
19998
|
+
storeReject: "os.apps.store.reject",
|
|
19999
|
+
runStart: "os.apps.run.start",
|
|
20000
|
+
runEnd: "os.apps.run.end",
|
|
20001
|
+
runList: "os.apps.run.list",
|
|
20002
|
+
vote: "os.apps.vote",
|
|
20003
|
+
unvote: "os.apps.unvote",
|
|
20004
|
+
metrics: "os.apps.metrics",
|
|
19966
20005
|
temporalInstall: "os.marketplace.install",
|
|
19967
20006
|
temporalUninstall: "os.marketplace.uninstall",
|
|
19968
20007
|
temporalUpdate: "os.marketplace.update",
|
|
@@ -20029,7 +20068,7 @@ function resolveInstanceFromOpts(opts, cmd) {
|
|
|
20029
20068
|
async function resolveRemote(name) {
|
|
20030
20069
|
const nc = await connectNats();
|
|
20031
20070
|
try {
|
|
20032
|
-
const resp = await nc.request("os.
|
|
20071
|
+
const resp = await nc.request("os.apps.config.remotes", encode({}), { timeout: TIMEOUT });
|
|
20033
20072
|
const data = JSON.parse(decode(resp.data));
|
|
20034
20073
|
const remote = data.remotes?.find((r) => r.name === name);
|
|
20035
20074
|
if (!remote)
|
|
@@ -20898,7 +20937,7 @@ function formatTimestamp(ts) {
|
|
|
20898
20937
|
return ts;
|
|
20899
20938
|
}
|
|
20900
20939
|
}
|
|
20901
|
-
var eventsCommand = new Command("events").description("Tail handler events with timing and status").argument("[subject-pattern]", "NATS subject pattern to filter events (e.g.
|
|
20940
|
+
var eventsCommand = new Command("events").description("Tail handler events with timing and status").argument("[subject-pattern]", "NATS subject pattern to filter events (e.g. apps.*)").option("--all", "Subscribe to all handler events").option("--since <duration>", "Replay events from JetStream (e.g. 5m, 1h, 30s)").option("--json", "Output raw JSON lines").option("-i, --instance <url>", "KhalOS instance URL").action(async (subjectPattern, opts, cmd) => {
|
|
20902
20941
|
if (!subjectPattern && !opts.all) {
|
|
20903
20942
|
console.error("Error: specify a subject pattern or use --all");
|
|
20904
20943
|
process.exit(1);
|
|
@@ -23670,7 +23709,7 @@ var assertAppsCommand = new Command("apps").description("Compare NATS app count
|
|
|
23670
23709
|
let expectedApps = [];
|
|
23671
23710
|
try {
|
|
23672
23711
|
const nc = await connectNats();
|
|
23673
|
-
const resp = await nc.request("os.
|
|
23712
|
+
const resp = await nc.request("os.apps.list", new TextEncoder().encode(JSON.stringify({})), {
|
|
23674
23713
|
timeout: 5000
|
|
23675
23714
|
});
|
|
23676
23715
|
const data = JSON.parse(decode(resp.data));
|
|
@@ -24191,12 +24230,12 @@ async function watchHealth(nc, subject) {
|
|
|
24191
24230
|
|
|
24192
24231
|
// src/commands/stop.ts
|
|
24193
24232
|
init_source();
|
|
24194
|
-
import { existsSync as
|
|
24233
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7, unlinkSync } from "node:fs";
|
|
24195
24234
|
import { homedir as homedir4 } from "node:os";
|
|
24196
24235
|
import { join as join6 } from "node:path";
|
|
24197
24236
|
var PID_FILE = join6(homedir4(), ".khal-os", "khal-os.pid");
|
|
24198
24237
|
var stopCommand = new Command("stop").description("Stop running KhalOS instance").action(() => {
|
|
24199
|
-
if (!
|
|
24238
|
+
if (!existsSync7(PID_FILE)) {
|
|
24200
24239
|
console.log(`
|
|
24201
24240
|
${source_default.dim("Khal OS is not running.")}
|
|
24202
24241
|
`);
|