mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-02 05:23:14 +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:
@@ -127,7 +127,7 @@ function makeEffects(context: EffectContext): Effects {
|
||||
>
|
||||
},
|
||||
subcontainer: {
|
||||
createFs(options: { imageId: string }) {
|
||||
createFs(options: { imageId: string; name: string }) {
|
||||
return rpcRound("subcontainer.create-fs", options) as ReturnType<
|
||||
T.Effects["subcontainer"]["createFs"]
|
||||
>
|
||||
|
||||
@@ -198,7 +198,11 @@ export class RpcListener {
|
||||
.then((x) => this.dealWithInput(x))
|
||||
.catch(mapError)
|
||||
.then(logData("response"))
|
||||
.then(writeDataToSocket),
|
||||
.then(writeDataToSocket)
|
||||
.catch((e) => {
|
||||
console.error(`Major error in socket handling: ${e}`)
|
||||
console.debug(`Data in: ${a.toString()}`)
|
||||
}),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ export class DockerProcedureContainer {
|
||||
packageId: string,
|
||||
data: DockerProcedure,
|
||||
volumes: { [id: VolumeId]: Volume },
|
||||
name: string,
|
||||
options: { subcontainer?: ExecSpawnable } = {},
|
||||
) {
|
||||
const subcontainer =
|
||||
@@ -29,6 +30,7 @@ export class DockerProcedureContainer {
|
||||
packageId,
|
||||
data,
|
||||
volumes,
|
||||
name,
|
||||
))
|
||||
return new DockerProcedureContainer(subcontainer)
|
||||
}
|
||||
@@ -37,8 +39,13 @@ export class DockerProcedureContainer {
|
||||
packageId: string,
|
||||
data: DockerProcedure,
|
||||
volumes: { [id: VolumeId]: Volume },
|
||||
name: string,
|
||||
) {
|
||||
const subcontainer = await SubContainer.of(effects, { id: data.image })
|
||||
const subcontainer = await SubContainer.of(
|
||||
effects,
|
||||
{ id: data.image },
|
||||
name,
|
||||
)
|
||||
|
||||
if (data.mounts) {
|
||||
const mounts = data.mounts
|
||||
|
||||
@@ -62,6 +62,7 @@ export class MainLoop {
|
||||
this.system.manifest.id,
|
||||
this.system.manifest.main,
|
||||
this.system.manifest.volumes,
|
||||
`Main - ${currentCommand.join(" ")}`,
|
||||
)
|
||||
return CommandController.of()(
|
||||
this.effects,
|
||||
@@ -162,26 +163,29 @@ export class MainLoop {
|
||||
const subcontainer = actionProcedure.inject
|
||||
? this.mainSubContainerHandle
|
||||
: undefined
|
||||
// prettier-ignore
|
||||
const container =
|
||||
await DockerProcedureContainer.of(
|
||||
effects,
|
||||
manifest.id,
|
||||
actionProcedure,
|
||||
manifest.volumes,
|
||||
{
|
||||
subcontainer,
|
||||
}
|
||||
)
|
||||
const commands = [
|
||||
actionProcedure.entrypoint,
|
||||
...actionProcedure.args,
|
||||
]
|
||||
const container = await DockerProcedureContainer.of(
|
||||
effects,
|
||||
manifest.id,
|
||||
actionProcedure,
|
||||
manifest.volumes,
|
||||
`Health Check - ${commands.join(" ")}`,
|
||||
{
|
||||
subcontainer,
|
||||
},
|
||||
)
|
||||
const env: Record<string, string> = actionProcedure.inject
|
||||
? {
|
||||
HOME: "/root",
|
||||
}
|
||||
: {}
|
||||
const executed = await container.exec(
|
||||
[actionProcedure.entrypoint, ...actionProcedure.args],
|
||||
{ input: JSON.stringify(timeChanged), env },
|
||||
)
|
||||
const executed = await container.exec(commands, {
|
||||
input: JSON.stringify(timeChanged),
|
||||
env,
|
||||
})
|
||||
|
||||
if (executed.exitCode === 0) {
|
||||
await effects.setHealth({
|
||||
|
||||
@@ -443,6 +443,7 @@ export class SystemForEmbassy implements System {
|
||||
): Promise<void> {
|
||||
const backup = this.manifest.backup.create
|
||||
if (backup.type === "docker") {
|
||||
const commands = [backup.entrypoint, ...backup.args]
|
||||
const container = await DockerProcedureContainer.of(
|
||||
effects,
|
||||
this.manifest.id,
|
||||
@@ -451,8 +452,9 @@ export class SystemForEmbassy implements System {
|
||||
...this.manifest.volumes,
|
||||
BACKUP: { type: "backup", readonly: false },
|
||||
},
|
||||
`Backup - ${commands.join(" ")}`,
|
||||
)
|
||||
await container.execFail([backup.entrypoint, ...backup.args], timeoutMs)
|
||||
await container.execFail(commands, timeoutMs)
|
||||
} else {
|
||||
const moduleCode = await this.moduleCode
|
||||
await moduleCode.createBackup?.(polyfillEffects(effects, this.manifest))
|
||||
@@ -464,6 +466,7 @@ export class SystemForEmbassy implements System {
|
||||
): Promise<void> {
|
||||
const restoreBackup = this.manifest.backup.restore
|
||||
if (restoreBackup.type === "docker") {
|
||||
const commands = [restoreBackup.entrypoint, ...restoreBackup.args]
|
||||
const container = await DockerProcedureContainer.of(
|
||||
effects,
|
||||
this.manifest.id,
|
||||
@@ -472,11 +475,9 @@ export class SystemForEmbassy implements System {
|
||||
...this.manifest.volumes,
|
||||
BACKUP: { type: "backup", readonly: true },
|
||||
},
|
||||
`Restore Backup - ${commands.join(" ")}`,
|
||||
)
|
||||
await container.execFail(
|
||||
[restoreBackup.entrypoint, ...restoreBackup.args],
|
||||
timeoutMs,
|
||||
)
|
||||
await container.execFail(commands, timeoutMs)
|
||||
} else {
|
||||
const moduleCode = await this.moduleCode
|
||||
await moduleCode.restoreBackup?.(polyfillEffects(effects, this.manifest))
|
||||
@@ -495,20 +496,17 @@ export class SystemForEmbassy implements System {
|
||||
const config = this.manifest.config?.get
|
||||
if (!config) return { spec: {} }
|
||||
if (config.type === "docker") {
|
||||
const commands = [config.entrypoint, ...config.args]
|
||||
const container = await DockerProcedureContainer.of(
|
||||
effects,
|
||||
this.manifest.id,
|
||||
config,
|
||||
this.manifest.volumes,
|
||||
`Get Config - ${commands.join(" ")}`,
|
||||
)
|
||||
// TODO: yaml
|
||||
return JSON.parse(
|
||||
(
|
||||
await container.execFail(
|
||||
[config.entrypoint, ...config.args],
|
||||
timeoutMs,
|
||||
)
|
||||
).stdout.toString(),
|
||||
(await container.execFail(commands, timeoutMs)).stdout.toString(),
|
||||
)
|
||||
} else {
|
||||
const moduleCode = await this.moduleCode
|
||||
@@ -543,24 +541,21 @@ export class SystemForEmbassy implements System {
|
||||
const setConfigValue = this.manifest.config?.set
|
||||
if (!setConfigValue) return
|
||||
if (setConfigValue.type === "docker") {
|
||||
const commands = [
|
||||
setConfigValue.entrypoint,
|
||||
...setConfigValue.args,
|
||||
JSON.stringify(newConfig),
|
||||
]
|
||||
const container = await DockerProcedureContainer.of(
|
||||
effects,
|
||||
this.manifest.id,
|
||||
setConfigValue,
|
||||
this.manifest.volumes,
|
||||
`Set Config - ${commands.join(" ")}`,
|
||||
)
|
||||
const answer = matchSetResult.unsafeCast(
|
||||
JSON.parse(
|
||||
(
|
||||
await container.execFail(
|
||||
[
|
||||
setConfigValue.entrypoint,
|
||||
...setConfigValue.args,
|
||||
JSON.stringify(newConfig),
|
||||
],
|
||||
timeoutMs,
|
||||
)
|
||||
).stdout.toString(),
|
||||
(await container.execFail(commands, timeoutMs)).stdout.toString(),
|
||||
),
|
||||
)
|
||||
const dependsOn = answer["depends-on"] ?? answer.dependsOn ?? {}
|
||||
@@ -652,23 +647,20 @@ export class SystemForEmbassy implements System {
|
||||
if (migration) {
|
||||
const [version, procedure] = migration
|
||||
if (procedure.type === "docker") {
|
||||
const commands = [
|
||||
procedure.entrypoint,
|
||||
...procedure.args,
|
||||
JSON.stringify(fromVersion),
|
||||
]
|
||||
const container = await DockerProcedureContainer.of(
|
||||
effects,
|
||||
this.manifest.id,
|
||||
procedure,
|
||||
this.manifest.volumes,
|
||||
`Migration - ${commands.join(" ")}`,
|
||||
)
|
||||
return JSON.parse(
|
||||
(
|
||||
await container.execFail(
|
||||
[
|
||||
procedure.entrypoint,
|
||||
...procedure.args,
|
||||
JSON.stringify(fromVersion),
|
||||
],
|
||||
timeoutMs,
|
||||
)
|
||||
).stdout.toString(),
|
||||
(await container.execFail(commands, timeoutMs)).stdout.toString(),
|
||||
)
|
||||
} else if (procedure.type === "script") {
|
||||
const moduleCode = await this.moduleCode
|
||||
@@ -695,20 +687,17 @@ export class SystemForEmbassy implements System {
|
||||
const setConfigValue = this.manifest.properties
|
||||
if (!setConfigValue) throw new Error("There is no properties")
|
||||
if (setConfigValue.type === "docker") {
|
||||
const commands = [setConfigValue.entrypoint, ...setConfigValue.args]
|
||||
const container = await DockerProcedureContainer.of(
|
||||
effects,
|
||||
this.manifest.id,
|
||||
setConfigValue,
|
||||
this.manifest.volumes,
|
||||
`Properties - ${commands.join(" ")}`,
|
||||
)
|
||||
const properties = matchProperties.unsafeCast(
|
||||
JSON.parse(
|
||||
(
|
||||
await container.execFail(
|
||||
[setConfigValue.entrypoint, ...setConfigValue.args],
|
||||
timeoutMs,
|
||||
)
|
||||
).stdout.toString(),
|
||||
(await container.execFail(commands, timeoutMs)).stdout.toString(),
|
||||
),
|
||||
)
|
||||
return asProperty(properties.data)
|
||||
@@ -761,6 +750,7 @@ export class SystemForEmbassy implements System {
|
||||
this.manifest.id,
|
||||
actionProcedure,
|
||||
this.manifest.volumes,
|
||||
`Action ${actionId}`,
|
||||
{
|
||||
subcontainer,
|
||||
},
|
||||
@@ -801,23 +791,20 @@ export class SystemForEmbassy implements System {
|
||||
const actionProcedure = this.manifest.dependencies?.[id]?.config?.check
|
||||
if (!actionProcedure) return { message: "Action not found", value: null }
|
||||
if (actionProcedure.type === "docker") {
|
||||
const commands = [
|
||||
actionProcedure.entrypoint,
|
||||
...actionProcedure.args,
|
||||
JSON.stringify(oldConfig),
|
||||
]
|
||||
const container = await DockerProcedureContainer.of(
|
||||
effects,
|
||||
this.manifest.id,
|
||||
actionProcedure,
|
||||
this.manifest.volumes,
|
||||
`Dependencies Check - ${commands.join(" ")}`,
|
||||
)
|
||||
return JSON.parse(
|
||||
(
|
||||
await container.execFail(
|
||||
[
|
||||
actionProcedure.entrypoint,
|
||||
...actionProcedure.args,
|
||||
JSON.stringify(oldConfig),
|
||||
],
|
||||
timeoutMs,
|
||||
)
|
||||
).stdout.toString(),
|
||||
(await container.execFail(commands, timeoutMs)).stdout.toString(),
|
||||
)
|
||||
} else if (actionProcedure.type === "script") {
|
||||
const moduleCode = await this.moduleCode
|
||||
|
||||
@@ -129,6 +129,7 @@ export const polyfillEffects = (
|
||||
manifest.id,
|
||||
manifest.main,
|
||||
manifest.volumes,
|
||||
[input.command, ...(input.args || [])].join(" "),
|
||||
)
|
||||
const daemon = promiseSubcontainer.then((subcontainer) =>
|
||||
daemons.runCommand()(
|
||||
|
||||
Reference in New Issue
Block a user