Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import { Match, Schema } from 'effect'
const WorkloadExitTypeId: unique symbol = Symbol.for('@systemfsoftware/effect-daemon-microvm/WorkloadExit')
type WorkloadExitTypeId = typeof WorkloadExitTypeId

export class WorkloadExitedNormal extends Schema.TaggedClass<WorkloadExitedNormal>()('WorkloadExitedNormal', {}) {
export class WorkloadExitedNormal
extends Schema.TaggedClass<WorkloadExitedNormal, { readonly brand: unique symbol }>()('WorkloadExitedNormal', {})
{
readonly [WorkloadExitTypeId] = WorkloadExitTypeId
}

export class WorkloadExitedAbnormal extends Schema.TaggedClass<WorkloadExitedAbnormal>()('WorkloadExitedAbnormal', {
code: Schema.Int,
}) {
export class WorkloadExitedAbnormal
extends Schema.TaggedClass<WorkloadExitedAbnormal, { readonly brand: unique symbol }>()('WorkloadExitedAbnormal', {
code: Schema.Int,
})
{
readonly [WorkloadExitTypeId] = WorkloadExitTypeId
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { Match, Schema } from 'effect'
import * as Result from 'effect/Result'
import { WorkloadExit, WorkloadExitedAbnormal, WorkloadExitedNormal } from './WorkloadExit.schema.js'

export class ClassifyWorkloadExit extends Schema.TaggedClass<ClassifyWorkloadExit>()('ClassifyWorkloadExit', {
code: Schema.Int,
}) {
export class ClassifyWorkloadExit
extends Schema.TaggedClass<ClassifyWorkloadExit, { readonly brand: unique symbol }>()('ClassifyWorkloadExit', {
code: Schema.Int,
})
{
static readonly [Workflow.InstrumentationBrand] = { code: 'microvm.workload.exit.code' } as const
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,30 @@ import * as Result from 'effect/Result'
const VmTeardownTypeId: unique symbol = Symbol.for('@systemfsoftware/effect-daemon-microvm/VmTeardown')
type VmTeardownTypeId = typeof VmTeardownTypeId

export class KillVm extends Schema.TaggedClass<KillVm>()('KillVm', {}) {
export class KillVm extends Schema.TaggedClass<KillVm, { readonly brand: unique symbol }>()('KillVm', {}) {
readonly [VmTeardownTypeId] = VmTeardownTypeId
}

export class StopVmWithin extends Schema.TaggedClass<StopVmWithin>()('StopVmWithin', {
millis: Schema.Int,
}) {
export class StopVmWithin
extends Schema.TaggedClass<StopVmWithin, { readonly brand: unique symbol }>()('StopVmWithin', {
millis: Schema.Int,
})
{
readonly [VmTeardownTypeId] = VmTeardownTypeId
}

export class StopVm extends Schema.TaggedClass<StopVm>()('StopVm', {}) {
export class StopVm extends Schema.TaggedClass<StopVm, { readonly brand: unique symbol }>()('StopVm', {}) {
readonly [VmTeardownTypeId] = VmTeardownTypeId
}

export const VmTeardown = Schema.Union([KillVm, StopVmWithin, StopVm])
export type VmTeardown = typeof VmTeardown.Type

export class PlanVmTeardown extends Schema.TaggedClass<PlanVmTeardown>()('PlanVmTeardown', {
mode: Supervisor.Medium.ShutdownMode,
}) {
export class PlanVmTeardown
extends Schema.TaggedClass<PlanVmTeardown, { readonly brand: unique symbol }>()('PlanVmTeardown', {
mode: Supervisor.Medium.ShutdownMode,
})
{
static readonly [Workflow.InstrumentationBrand] = {} as const
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import { Context, Effect, Layer, Match, Option, Schema } from 'effect'
import type { ExecEvent, ExecHandle, ExecSink, ResolvedRuntime, Sandbox } from 'microsandbox'
import { ABNORMAL_EXIT_CODE, READY_TOKEN } from './child-script.js'

export class MachineLeftBehind extends Schema.TaggedError<MachineLeftBehind>()('MachineLeftBehind', {
names: Schema.Array(Schema.String),
}) {}

export class ExceptionalTermination extends Schema.TaggedError<ExceptionalTermination>()('ExceptionalTermination', {
observed: Schema.String,
}) {}
export class MachineLeftBehind
extends Schema.TaggedError<MachineLeftBehind, { readonly brand: unique symbol }>()('MachineLeftBehind', {
names: Schema.Array(Schema.String),
})
{}

export class ExceptionalTermination
extends Schema.TaggedError<ExceptionalTermination, { readonly brand: unique symbol }>()('ExceptionalTermination', {
observed: Schema.String,
})
{}

export type SandboxBehaviour = 'waits-for-steps' | 'ends-after-started'

Expand Down
6 changes: 3 additions & 3 deletions packages/effect-microsandbox/examples/boot-alpine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ import assert from 'node:assert'
import { Buffer } from 'node:buffer'
import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http'

export class HostListenerError extends Schema.TaggedError<HostListenerError>()(
export class HostListenerError extends Schema.TaggedError<HostListenerError, { readonly brand: unique symbol }>()(
'HostListenerError',
{
cause: Schema.Unknown,
},
) {}

export class SandboxListingError extends Schema.TaggedError<SandboxListingError>()(
export class SandboxListingError extends Schema.TaggedError<SandboxListingError, { readonly brand: unique symbol }>()(
'SandboxListingError',
{
cause: Schema.Unknown,
},
) {}

export class EscapeHatchDefect extends Schema.TaggedError<EscapeHatchDefect>()(
export class EscapeHatchDefect extends Schema.TaggedError<EscapeHatchDefect, { readonly brand: unique symbol }>()(
'EscapeHatchDefect',
{},
) {}
Expand Down
6 changes: 4 additions & 2 deletions packages/effect-microsandbox/src/JobExitStatus.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ const JobExitStatusTypeId: unique symbol = Symbol.for(
)
type JobExitStatusTypeId = typeof JobExitStatusTypeId

export class JobExited extends Schema.TaggedClass<JobExited>()('JobExited', {
export class JobExited extends Schema.TaggedClass<JobExited, { readonly brand: unique symbol }>()('JobExited', {
code: Schema.Natural,
}) {
readonly [JobExitStatusTypeId] = JobExitStatusTypeId
}

export class JobSignaled extends Schema.TaggedClass<JobSignaled>()('JobSignaled', {}) {
export class JobSignaled
extends Schema.TaggedClass<JobSignaled, { readonly brand: unique symbol }>()('JobSignaled', {})
{
readonly [JobExitStatusTypeId] = JobExitStatusTypeId
}

Expand Down
68 changes: 39 additions & 29 deletions packages/effect-microsandbox/src/MicroVMError.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,28 @@
import { Match, Option, Predicate, Schema } from 'effect'
import { GuestPort } from './MicroVMSpec.schema.js'

export class VirtualizationUnsupportedError extends Schema.TaggedError<VirtualizationUnsupportedError>()(
'VirtualizationUnsupportedError',
{
platform: Schema.String,
remediation: Schema.String,
cause: Schema.optional(Schema.Unknown),
},
) {
export class VirtualizationUnsupportedError
extends Schema.TaggedError<VirtualizationUnsupportedError, { readonly brand: unique symbol }>()(
'VirtualizationUnsupportedError',
{
platform: Schema.String,
remediation: Schema.String,
cause: Schema.optional(Schema.Unknown),
},
)
{
override get message(): string {
return `Virtualization is unsupported on platform "${this.platform}": ${this.remediation}`
}
}

/** The runtime could not start the sandbox; the message carries the runtime's own reason, so a failure names why. */
export class SandboxBootError extends Schema.TaggedError<SandboxBootError>()('SandboxBootError', {
sandboxName: Schema.String,
cause: Schema.optional(Schema.Unknown),
}) {
export class SandboxBootError
extends Schema.TaggedError<SandboxBootError, { readonly brand: unique symbol }>()('SandboxBootError', {
sandboxName: Schema.String,
cause: Schema.optional(Schema.Unknown),
})
{
override get message(): string {
const failed = `Sandbox "${this.sandboxName}" failed to boot`
return Option.match(Option.fromUndefinedOr(this.cause), {
Expand All @@ -34,16 +38,18 @@ export class SandboxBootError extends Schema.TaggedError<SandboxBootError>()('Sa
}
}

export class WaitTimeoutError extends Schema.TaggedError<WaitTimeoutError>()('WaitTimeoutError', {
wait: Schema.String,
timeoutMs: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
}) {
export class WaitTimeoutError
extends Schema.TaggedError<WaitTimeoutError, { readonly brand: unique symbol }>()('WaitTimeoutError', {
wait: Schema.String,
timeoutMs: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
})
{
override get message(): string {
return `Timed out after ${this.timeoutMs}ms waiting for "${this.wait}"`
}
}

export class ExecError extends Schema.TaggedError<ExecError>()('ExecError', {
export class ExecError extends Schema.TaggedError<ExecError, { readonly brand: unique symbol }>()('ExecError', {
argv: Schema.Array(Schema.String),
cause: Schema.optional(Schema.Unknown),
}) {
Expand All @@ -52,23 +58,27 @@ export class ExecError extends Schema.TaggedError<ExecError>()('ExecError', {
}
}

export class PortAllocationError extends Schema.TaggedError<PortAllocationError>()('PortAllocationError', {
guestPort: GuestPort,
cause: Schema.optional(Schema.Unknown),
}) {
export class PortAllocationError
extends Schema.TaggedError<PortAllocationError, { readonly brand: unique symbol }>()('PortAllocationError', {
guestPort: GuestPort,
cause: Schema.optional(Schema.Unknown),
})
{
override get message(): string {
return `The guest port ${this.guestPort} could not be mapped to a host port`
}
}

export class LoopbackViolationError extends Schema.TaggedError<LoopbackViolationError>()(
'LoopbackViolationError',
{
sandboxName: Schema.String,
host: Schema.String,
guestPort: GuestPort,
},
) {
export class LoopbackViolationError
extends Schema.TaggedError<LoopbackViolationError, { readonly brand: unique symbol }>()(
'LoopbackViolationError',
{
sandboxName: Schema.String,
host: Schema.String,
guestPort: GuestPort,
},
)
{
override get message(): string {
return `Sandbox "${this.sandboxName}" refused the network binding "${this.host}:${this.guestPort}" under its loopback policy`
}
Expand Down
36 changes: 21 additions & 15 deletions packages/effect-microsandbox/src/assess-virtualization.workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,36 @@ import { ProbeObservation } from './classify-probe-observation.workflow.js'
const VerdictTypeId: unique symbol = Symbol.for('@systemfsoftware/effect-microsandbox/VirtualizationVerdict')
type VerdictTypeId = typeof VerdictTypeId

export class VirtualizationEligible extends Schema.TaggedClass<VirtualizationEligible>()(
'VirtualizationEligible',
{},
) {
export class VirtualizationEligible
extends Schema.TaggedClass<VirtualizationEligible, { readonly brand: unique symbol }>()(
'VirtualizationEligible',
{},
)
{
readonly [VerdictTypeId] = VerdictTypeId
}

export class VirtualizationRefused extends Schema.TaggedClass<VirtualizationRefused>()(
'VirtualizationRefused',
{
remediation: Schema.String,
topology: Schema.String,
},
) {
export class VirtualizationRefused
extends Schema.TaggedClass<VirtualizationRefused, { readonly brand: unique symbol }>()(
'VirtualizationRefused',
{
remediation: Schema.String,
topology: Schema.String,
},
)
{
readonly [VerdictTypeId] = VerdictTypeId
}

export const VirtualizationVerdict = Schema.Union([VirtualizationEligible, VirtualizationRefused])
export type VirtualizationVerdict = typeof VirtualizationVerdict.Type

export class AssessVirtualization extends Schema.TaggedClass<AssessVirtualization>()('AssessVirtualization', {
platform: Schema.String,
observation: ProbeObservation,
}) {
export class AssessVirtualization
extends Schema.TaggedClass<AssessVirtualization, { readonly brand: unique symbol }>()('AssessVirtualization', {
platform: Schema.String,
observation: ProbeObservation,
})
{
static readonly [Workflow.InstrumentationBrand] = { platform: 'microsandbox.virtualization.platform' } as const
}
const REMEDIATIONS = {
Expand Down
12 changes: 7 additions & 5 deletions packages/effect-microsandbox/src/classify-job-exit.workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { Option, Schema } from 'effect'
import * as Result from 'effect/Result'
import { JobExited, JobExitStatus, JobSignaled } from './JobExitStatus.schema.js'

export class ClassifyJobExit extends Schema.TaggedClass<ClassifyJobExit>()('ClassifyJobExit', {
code: Schema.Int,
stdout: Schema.Uint8Array,
stderr: Schema.Uint8Array,
}) {
export class ClassifyJobExit
extends Schema.TaggedClass<ClassifyJobExit, { readonly brand: unique symbol }>()('ClassifyJobExit', {
code: Schema.Int,
stdout: Schema.Uint8Array,
stderr: Schema.Uint8Array,
})
{
static readonly [Workflow.InstrumentationBrand] = { code: 'microsandbox.job.exit.code' } as const
}

Expand Down
Loading
Loading