More svc effect handlers (#2610)

* complete get_primary_url fn

* complete clear_network_interfaces fn

* formatting

* complete remove_address fn

* get_system_smtp wip

* complete get_system_smtp and set_system_smtp

* add SetSystemSmtpParams struct

* add set_system_smtp subcommand

* Remove 'Copy' implementation from `HostAddress`

Co-authored-by: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com>

* Refactor `get_host_primary` fn and clone  resulting `HostAddress`

Co-authored-by: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com>

* misc fixes and debug info

* seed hosts with a tor address

---------

Co-authored-by: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com>
Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
Dominion5254
2024-05-10 13:20:24 -06:00
committed by GitHub
parent 30aabe255b
commit 800b0763e4
31 changed files with 259 additions and 97 deletions

View File

@@ -28,7 +28,7 @@ import { DependencyConfig, Update } from "./dependencies/DependencyConfig"
import { BackupSet, Backups } from "./backup/Backups"
import { smtpConfig } from "./config/configConstants"
import { Daemons } from "./mainFn/Daemons"
import { healthCheck } from "./health/HealthCheck"
import { healthCheck, HealthCheckParams } from "./health/HealthCheck"
import { checkPortListening } from "./health/checkFns/checkPortListening"
import { checkWebUrl, runHealthScript } from "./health/checkFns"
import { List } from "./config/builder/list"
@@ -78,6 +78,7 @@ import { Checker, EmVer } from "./emverLite/mod"
import { ExposedStorePaths } from "./store/setupExposeStore"
import { PathBuilder, extractJsonPath, pathBuilder } from "./store/PathBuilder"
import { checkAllDependencies } from "./dependencies/dependencies"
import { health } from "."
// prettier-ignore
type AnyNeverCond<T extends any[], Then, Else> =
@@ -186,13 +187,13 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
nullIfEmpty,
runCommand: async <A extends string>(
effects: Effects,
imageId: Manifest["images"][number],
image: { id: Manifest["images"][number]; sharedRun?: boolean },
command: ValidIfNoStupidEscape<A> | [string, ...string[]],
options: CommandOptions & {
mounts?: { path: string; options: MountOptions }[]
},
): Promise<{ stdout: string | Buffer; stderr: string | Buffer }> => {
return runCommand<Manifest>(effects, imageId, command, options)
return runCommand<Manifest>(effects, image, command, options)
},
createAction: <
@@ -264,7 +265,9 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
)
},
HealthCheck: {
of: healthCheck,
of(o: HealthCheckParams<Manifest>) {
return healthCheck<Manifest>(o)
},
},
Dependency: {
of(data: Dependency["data"]) {
@@ -740,14 +743,14 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
export async function runCommand<Manifest extends SDKManifest>(
effects: Effects,
imageId: Manifest["images"][number],
image: { id: Manifest["images"][number]; sharedRun?: boolean },
command: string | [string, ...string[]],
options: CommandOptions & {
mounts?: { path: string; options: MountOptions }[]
},
): Promise<{ stdout: string | Buffer; stderr: string | Buffer }> {
const commands = splitCommand(command)
const overlay = await Overlay.of(effects, imageId)
const overlay = await Overlay.of(effects, image)
try {
for (let mount of options.mounts || []) {
await overlay.mount(mount.options, mount.path)

View File

@@ -1,5 +1,5 @@
import { InterfaceReceipt } from "../interfaces/interfaceReceipt"
import { Daemon, Effects } from "../types"
import { Daemon, Effects, SDKManifest } from "../types"
import { CheckResult } from "./checkFns/CheckResult"
import { HealthReceipt } from "./HealthReceipt"
import { Trigger } from "../trigger"
@@ -9,16 +9,23 @@ import { once } from "../util/once"
import { Overlay } from "../util/Overlay"
import { object, unknown } from "ts-matches"
export function healthCheck(o: {
export type HealthCheckParams<Manifest extends SDKManifest> = {
effects: Effects
name: string
imageId: string
image: {
id: Manifest["images"][number]
sharedRun?: boolean
}
trigger?: Trigger
fn(overlay: Overlay): Promise<CheckResult> | CheckResult
onFirstSuccess?: () => unknown | Promise<unknown>
}) {
}
export function healthCheck<Manifest extends SDKManifest>(
o: HealthCheckParams<Manifest>,
) {
new Promise(async () => {
const overlay = await Overlay.of(o.effects, o.imageId)
const overlay = await Overlay.of(o.effects, o.image)
try {
let currentValue: TriggerInput = {
hadSuccess: false,

View File

@@ -23,7 +23,7 @@ type Daemon<
> = {
id: "" extends Id ? never : Id
command: ValidIfNoStupidEscape<Command> | [string, ...string[]]
imageId: Manifest["images"][number]
image: { id: Manifest["images"][number]; sharedRun?: boolean }
mounts: Mounts<Manifest>
env?: Record<string, string>
ready: {
@@ -40,7 +40,7 @@ export const runDaemon =
<Manifest extends SDKManifest>() =>
async <A extends string>(
effects: Effects,
imageId: Manifest["images"][number],
image: { id: Manifest["images"][number]; sharedRun?: boolean },
command: ValidIfNoStupidEscape<A> | [string, ...string[]],
options: CommandOptions & {
mounts?: { path: string; options: MountOptions }[]
@@ -48,7 +48,7 @@ export const runDaemon =
},
): Promise<DaemonReturned> => {
const commands = splitCommand(command)
const overlay = options.overlay || (await Overlay.of(effects, imageId))
const overlay = options.overlay || (await Overlay.of(effects, image))
for (let mount of options.mounts || []) {
await overlay.mount(mount.options, mount.path)
}
@@ -183,9 +183,9 @@ export class Daemons<Manifest extends SDKManifest, Ids extends string> {
daemon.requires?.map((id) => daemonsStarted[id]) ?? [],
)
daemonsStarted[daemon.id] = requiredPromise.then(async () => {
const { command, imageId } = daemon
const { command, image } = daemon
const child = runDaemon<Manifest>()(effects, imageId, command, {
const child = runDaemon<Manifest>()(effects, image, command, {
env: daemon.env,
mounts: daemon.mounts.build(),
})

View File

@@ -1,8 +1,10 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { Callback } from "./Callback"
import type { HostId } from "./HostId"
export type GetPrimaryUrlParams = {
packageId: string | null
serviceInterfaceId: string
callback: Callback
hostId: HostId
}

View File

@@ -1,3 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ServiceInterfaceId } from "./ServiceInterfaceId"
export type RemoveAddressParams = { id: string }
export type RemoveAddressParams = { id: ServiceInterfaceId }

View File

@@ -28,4 +28,5 @@ export type ServerInfo = {
ntpSynced: boolean
zram: boolean
governor: Governor | null
smtp: string | null
}

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type SetSystemSmtpParams = { smtp: string }

View File

@@ -113,6 +113,7 @@ export { SetDependenciesParams } from "./SetDependenciesParams"
export { SetHealth } from "./SetHealth"
export { SetMainStatus } from "./SetMainStatus"
export { SetStoreParams } from "./SetStoreParams"
export { SetSystemSmtpParams } from "./SetSystemSmtpParams"
export { SignAssetParams } from "./SignAssetParams"
export { SignatureInfo } from "./SignatureInfo"
export { Signature } from "./Signature"

View File

@@ -12,10 +12,19 @@ export class Overlay {
readonly rootfs: string,
readonly guid: string,
) {}
static async of(effects: T.Effects, imageId: string) {
static async of(
effects: T.Effects,
image: { id: string; sharedRun?: boolean },
) {
const { id: imageId, sharedRun } = image
const [rootfs, guid] = await effects.createOverlayedImage({ imageId })
for (const dirPart of ["dev", "sys", "proc", "run"] as const) {
const shared = ["dev", "sys", "proc"]
if (!!sharedRun) {
shared.push("run")
}
for (const dirPart of shared) {
await fs.mkdir(`${rootfs}/${dirPart}`, { recursive: true })
await execFile("mount", [
"--rbind",