mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
add support for remote attaching to container (#2732)
* add support for remote attaching to container * feature: Add in the subcontainer searching * feat: Add in the name/ imageId filtering * Feat: Fix the env and the workdir * chore: Make the sigkill first? * add some extra guard on term * fix: Health during error doesnt return what we need * chore: Cleanup for pr * fix build * fix build * Update startos-iso.yaml * Update startos-iso.yaml * Update startos-iso.yaml * Update startos-iso.yaml * Update startos-iso.yaml * Update startos-iso.yaml * Update startos-iso.yaml * check status during build --------- Co-authored-by: J H <dragondef@gmail.com>
This commit is contained in:
@@ -782,6 +782,7 @@ export async function runCommand<Manifest extends T.Manifest>(
|
||||
effects,
|
||||
image,
|
||||
options.mounts || [],
|
||||
commands.join(" "),
|
||||
(subcontainer) => subcontainer.exec(commands),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ export class CommandController {
|
||||
| SubContainer,
|
||||
command: T.CommandType,
|
||||
options: {
|
||||
subcontainerName?: string
|
||||
// Defaults to the DEFAULT_SIGTERM_TIMEOUT = 30_000ms
|
||||
sigtermTimeout?: number
|
||||
mounts?: { path: string; options: MountOptions }[]
|
||||
@@ -51,7 +52,11 @@ export class CommandController {
|
||||
subcontainer instanceof SubContainer
|
||||
? subcontainer
|
||||
: await (async () => {
|
||||
const subc = await SubContainer.of(effects, subcontainer)
|
||||
const subc = await SubContainer.of(
|
||||
effects,
|
||||
subcontainer,
|
||||
options?.subcontainerName || commands.join(" "),
|
||||
)
|
||||
for (let mount of options.mounts || []) {
|
||||
await subc.mount(mount.options, mount.path)
|
||||
}
|
||||
@@ -119,6 +124,11 @@ export class CommandController {
|
||||
async term({ signal = SIGTERM, timeout = this.sigtermTimeout } = {}) {
|
||||
try {
|
||||
if (!this.state.exited) {
|
||||
if (signal !== "SIGKILL") {
|
||||
setTimeout(() => {
|
||||
if (!this.state.exited) this.process.kill("SIGKILL")
|
||||
}, timeout)
|
||||
}
|
||||
if (!this.process.kill(signal)) {
|
||||
console.error(
|
||||
`failed to send signal ${signal} to pid ${this.process.pid}`,
|
||||
@@ -126,11 +136,6 @@ export class CommandController {
|
||||
}
|
||||
}
|
||||
|
||||
if (signal !== "SIGKILL") {
|
||||
setTimeout(() => {
|
||||
this.process.kill("SIGKILL")
|
||||
}, timeout)
|
||||
}
|
||||
await this.runningAnswer
|
||||
} finally {
|
||||
await this.subcontainer.destroy?.()
|
||||
|
||||
@@ -28,6 +28,7 @@ export class Daemon {
|
||||
| SubContainer,
|
||||
command: T.CommandType,
|
||||
options: {
|
||||
subcontainerName?: string
|
||||
mounts?: { path: string; options: MountOptions }[]
|
||||
env?:
|
||||
| {
|
||||
|
||||
@@ -127,6 +127,7 @@ export class Daemons<Manifest extends T.Manifest, Ids extends string> {
|
||||
const daemon = Daemon.of()(this.effects, options.image, options.command, {
|
||||
...options,
|
||||
mounts: options.mounts.build(),
|
||||
subcontainerName: id,
|
||||
})
|
||||
const healthDaemon = new HealthDaemon(
|
||||
daemon,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ImageId } from "./ImageId"
|
||||
|
||||
export type CreateSubcontainerFsParams = { imageId: ImageId }
|
||||
export type CreateSubcontainerFsParams = {
|
||||
imageId: ImageId
|
||||
name: string | null
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Sessions } from "./Sessions"
|
||||
|
||||
export type SessionList = { current: string; sessions: Sessions }
|
||||
export type SessionList = { current: string | null; sessions: Sessions }
|
||||
|
||||
@@ -366,7 +366,10 @@ export type Effects = {
|
||||
// subcontainer
|
||||
subcontainer: {
|
||||
/** A low level api used by SubContainer */
|
||||
createFs(options: { imageId: string }): Promise<[string, string]>
|
||||
createFs(options: {
|
||||
imageId: string
|
||||
name: string | null
|
||||
}): Promise<[string, string]>
|
||||
/** A low level api used by SubContainer */
|
||||
destroyFs(options: { guid: string }): Promise<void>
|
||||
}
|
||||
|
||||
@@ -86,10 +86,12 @@ export class SubContainer implements ExecSpawnable {
|
||||
static async of(
|
||||
effects: T.Effects,
|
||||
image: { id: T.ImageId; sharedRun?: boolean },
|
||||
name: string,
|
||||
) {
|
||||
const { id, sharedRun } = image
|
||||
const [rootfs, guid] = await effects.subcontainer.createFs({
|
||||
imageId: id as string,
|
||||
name,
|
||||
})
|
||||
|
||||
const shared = ["dev", "sys"]
|
||||
@@ -115,9 +117,10 @@ export class SubContainer implements ExecSpawnable {
|
||||
effects: T.Effects,
|
||||
image: { id: T.ImageId; sharedRun?: boolean },
|
||||
mounts: { options: MountOptions; path: string }[],
|
||||
name: string,
|
||||
fn: (subContainer: SubContainer) => Promise<T>,
|
||||
): Promise<T> {
|
||||
const subContainer = await SubContainer.of(effects, image)
|
||||
const subContainer = await SubContainer.of(effects, image, name)
|
||||
try {
|
||||
for (let mount of mounts) {
|
||||
await subContainer.mount(mount.options, mount.path)
|
||||
@@ -179,10 +182,12 @@ export class SubContainer implements ExecSpawnable {
|
||||
}
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
try {
|
||||
let timeout = setTimeout(() => this.leader.kill("SIGKILL"), 30000)
|
||||
this.leader.on("exit", () => {
|
||||
clearTimeout(timeout)
|
||||
resolve()
|
||||
})
|
||||
if (!this.leader.kill("SIGKILL")) {
|
||||
if (!this.leader.kill("SIGTERM")) {
|
||||
reject(new Error("kill(2) failed"))
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user