Class: Microsandbox::Sandbox
- Inherits:
-
Object
- Object
- Microsandbox::Sandbox
- Defined in:
- lib/microsandbox/sandbox.rb
Overview
A running sandbox (microVM) — the primary entry point of the SDK.
Class Method Summary collapse
-
.create(name, image: nil, cpus: nil, memory: nil, env: nil, workdir: nil, shell: nil, user: nil, hostname: nil, labels: nil, scripts: nil, entrypoint: nil, ports: nil, ports_udp: nil, volumes: nil, network: nil, patches: nil, from_snapshot: nil, log_level: nil, quiet_logs: false, security: nil, oci_upper_size: nil, max_duration: nil, idle_timeout: nil, rlimits: nil, pull_policy: nil, registry_auth: nil, registry_insecure: false, registry_ca_certs: nil, secrets: nil, detached: false, replace: false, replace_with_timeout: nil) {|sandbox| ... } ⇒ Sandbox, Object
Create and boot a sandbox.
-
.get(name) ⇒ SandboxHandle
Fetch a controllable handle for a sandbox by name (running or not).
-
.list ⇒ Array<SandboxHandle>
List all sandboxes as controllable handles.
-
.list_with(labels: {}) ⇒ Array<SandboxHandle>
List sandboxes carrying all of the given labels (AND-matched).
-
.remove(name) ⇒ nil
Remove a (stopped) sandbox by name.
-
.start(name, detached: false) ⇒ Sandbox
Restart a previously-defined sandbox by name.
Instance Method Summary collapse
-
#attach(command, args = [], cwd: nil, user: nil, env: nil, detach_keys: nil, rlimits: nil) ⇒ Integer
Attach an interactive terminal to a command in the sandbox.
-
#attach_shell ⇒ Integer
Attach an interactive terminal running the sandbox’s default shell.
-
#detach ⇒ nil
Detach this handle: disarm the stop-on-drop safety net so the sandbox keeps running after this handle is gone (and after this process exits).
-
#drain ⇒ nil
Trigger a graceful drain (SIGUSR1).
-
#exec(command, args = [], cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ⇒ ExecOutput
Run a command (no shell interpretation) and collect its output.
-
#exec_stream(command, args = [], cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ⇒ ExecHandle
Run a command and stream its output as it arrives.
-
#fs ⇒ FS
Guest filesystem operations.
-
#initialize(native) ⇒ Sandbox
constructor
A new instance of Sandbox.
- #inspect ⇒ Object
-
#kill ⇒ nil
Force-kill the sandbox (SIGKILL).
-
#log_stream(sources: nil, since_ms: nil, from_cursor: nil, until_ms: nil, follow: false) ⇒ LogStream
Stream captured logs as they appear.
-
#logs(tail: nil, since_ms: nil, until_ms: nil, sources: nil) ⇒ Array<LogEntry>
Read captured logs.
-
#metrics ⇒ Metrics
Latest resource-usage snapshot.
-
#metrics_stream(interval: 1.0) ⇒ MetricsStream
Stream resource-usage snapshots, one per interval tick, until the sandbox stops.
-
#name ⇒ String
The sandbox name.
-
#owns_lifecycle? ⇒ Boolean
Whether this handle owns the sandbox process lifecycle (i.e. stopping it or dropping the handle terminates the sandbox).
-
#shell(script, cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ⇒ ExecOutput
Run a shell script (pipes, redirects, etc. allowed) and collect output.
-
#shell_stream(script, cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ⇒ ExecHandle
Run a shell script and stream its output as it arrives.
-
#ssh ⇒ SshOps
SSH access to the sandbox — open a native in-process SSH client or prepare a reusable server endpoint.
-
#status ⇒ Symbol
The live status, fetched from the backend (a round-trip per call).
-
#stop ⇒ nil
Gracefully stop the sandbox (SIGTERM→SIGKILL escalation, 10s default) and wait for it to terminate.
-
#stop_and_wait ⇒ ExitStatus
Gracefully stop, then wait for the process to exit.
-
#wait ⇒ ExitStatus
Wait for the sandbox process to exit.
Constructor Details
#initialize(native) ⇒ Sandbox
Returns a new instance of Sandbox.
440 441 442 |
# File 'lib/microsandbox/sandbox.rb', line 440 def initialize(native) @native = native end |
Class Method Details
.create(name, image: nil, cpus: nil, memory: nil, env: nil, workdir: nil, shell: nil, user: nil, hostname: nil, labels: nil, scripts: nil, entrypoint: nil, ports: nil, ports_udp: nil, volumes: nil, network: nil, patches: nil, from_snapshot: nil, log_level: nil, quiet_logs: false, security: nil, oci_upper_size: nil, max_duration: nil, idle_timeout: nil, rlimits: nil, pull_policy: nil, registry_auth: nil, registry_insecure: false, registry_ca_certs: nil, secrets: nil, detached: false, replace: false, replace_with_timeout: nil) {|sandbox| ... } ⇒ Sandbox, Object
Create and boot a sandbox.
When a block is given the sandbox is yielded and stopped automatically when the block returns (the block’s value is returned); otherwise the live Microsandbox::Sandbox is returned and you are responsible for calling #stop.
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/microsandbox/sandbox.rb', line 223 def create(name, image: nil, cpus: nil, memory: nil, env: nil, workdir: nil, shell: nil, user: nil, hostname: nil, labels: nil, scripts: nil, entrypoint: nil, ports: nil, ports_udp: nil, volumes: nil, network: nil, patches: nil, from_snapshot: nil, log_level: nil, quiet_logs: false, security: nil, oci_upper_size: nil, max_duration: nil, idle_timeout: nil, rlimits: nil, pull_policy: nil, registry_auth: nil, registry_insecure: false, registry_ca_certs: nil, secrets: nil, detached: false, replace: false, replace_with_timeout: nil) # A sandbox boots from exactly one rootfs source. The core would reject a # contradictory pair, but only after a runtime round-trip; fail fast and # clearly here (the Python SDK validates this the same way). if image && from_snapshot raise ArgumentError, "provide either image: or from_snapshot:, not both" end Microsandbox.ensure_runtime! opts = {} opts["image"] = image.to_s if image opts["from_snapshot"] = from_snapshot.to_s if from_snapshot opts["cpus"] = Integer(cpus) if cpus opts["memory"] = Integer(memory) if memory opts["workdir"] = workdir.to_s if workdir opts["shell"] = shell.to_s if shell opts["user"] = user.to_s if user opts["hostname"] = hostname.to_s if hostname opts["env"] = stringify(env) if env opts["labels"] = stringify(labels) if labels opts["scripts"] = stringify(scripts) if scripts opts["entrypoint"] = Array(entrypoint).map(&:to_s) if entrypoint opts["ports"] = intify_ports(ports) if ports opts["ports_udp"] = intify_ports(ports_udp) if ports_udp opts["volumes"] = normalize_volumes(volumes) if volumes opts["patches"] = normalize_patches(patches) if patches apply_network_opts(opts, network) unless network.nil? opts["log_level"] = log_level.to_s if log_level opts["quiet_logs"] = true if quiet_logs opts["security"] = security.to_s if security opts["oci_upper_size"] = Integer(oci_upper_size) if oci_upper_size opts["max_duration"] = Integer(max_duration) if max_duration opts["idle_timeout"] = Integer(idle_timeout) if idle_timeout opts["rlimits"] = normalize_rlimits(rlimits) if rlimits opts["pull_policy"] = pull_policy.to_s if pull_policy apply_registry_opts(opts, registry_auth, registry_insecure, registry_ca_certs) opts["secrets"] = normalize_secrets(secrets) if secrets opts["detached"] = true if detached if replace_with_timeout opts["replace_with_timeout"] = coerce_duration(replace_with_timeout, "replace_with_timeout") elsif replace opts["replace"] = true end sandbox = new(Native::Sandbox.create(name.to_s, opts)) return sandbox unless block_given? begin yield sandbox ensure begin sandbox.stop rescue Microsandbox::Error # best-effort cleanup; ignore stop failures during teardown end end end |
.get(name) ⇒ SandboxHandle
Fetch a controllable handle for a sandbox by name (running or not).
298 299 300 |
# File 'lib/microsandbox/sandbox.rb', line 298 def get(name) SandboxHandle.new(Native::Sandbox.get(name.to_s)) end |
.list ⇒ Array<SandboxHandle>
List all sandboxes as controllable handles.
304 305 306 |
# File 'lib/microsandbox/sandbox.rb', line 304 def list Native::Sandbox.list.map { |h| SandboxHandle.new(h) } end |
.list_with(labels: {}) ⇒ Array<SandboxHandle>
List sandboxes carrying all of the given labels (AND-matched).
311 312 313 314 |
# File 'lib/microsandbox/sandbox.rb', line 311 def list_with(labels: {}) opts = {"labels" => stringify(labels)} Native::Sandbox.list_with(opts).map { |h| SandboxHandle.new(h) } end |
.remove(name) ⇒ nil
Remove a (stopped) sandbox by name.
318 319 320 321 |
# File 'lib/microsandbox/sandbox.rb', line 318 def remove(name) Native::Sandbox.remove(name.to_s) nil end |
.start(name, detached: false) ⇒ Sandbox
Restart a previously-defined sandbox by name.
291 292 293 294 |
# File 'lib/microsandbox/sandbox.rb', line 291 def start(name, detached: false) Microsandbox.ensure_runtime! new(Native::Sandbox.start(name.to_s, {"detached" => detached})) end |
Instance Method Details
#attach(command, args = [], cwd: nil, user: nil, env: nil, detach_keys: nil, rlimits: nil) ⇒ Integer
Attach an interactive terminal to a command in the sandbox.
Puts the host terminal into raw mode and forwards keystrokes (and SIGWINCH resizes) to the guest until the command exits or the detach sequence is typed. Requires a real TTY on stdin/stdout, so it is for CLI use, not library/automation code (use #exec/#exec_stream there). Blocks until the session ends. Mirrors the official SDKs’ ‘attach`.
510 511 512 513 514 515 516 517 518 519 520 521 522 523 |
# File 'lib/microsandbox/sandbox.rb', line 510 def attach(command, args = [], cwd: nil, user: nil, env: nil, detach_keys: nil, rlimits: nil) opts = {} opts["cwd"] = cwd.to_s if cwd opts["user"] = user.to_s if user opts["env"] = env.each_with_object({}) { |(k, v), a| a[k.to_s] = v.to_s } if env opts["detach_keys"] = detach_keys.to_s if detach_keys if rlimits opts["rlimits"] = rlimits.map do |resource, limit| soft, hard = limit.is_a?(Array) ? [limit[0], limit[1]] : [limit, limit] [resource.to_s, Integer(soft), Integer(hard)] end end @native.attach(command.to_s, Array(args).map(&:to_s), opts) end |
#attach_shell ⇒ Integer
Attach an interactive terminal running the sandbox’s default shell. See #attach for the host-TTY requirements.
528 529 530 |
# File 'lib/microsandbox/sandbox.rb', line 528 def attach_shell @native.attach_shell end |
#detach ⇒ nil
Detach this handle: disarm the stop-on-drop safety net so the sandbox keeps running after this handle is gone (and after this process exits).
649 650 651 652 |
# File 'lib/microsandbox/sandbox.rb', line 649 def detach @native.detach nil end |
#drain ⇒ nil
Trigger a graceful drain (SIGUSR1).
622 623 624 625 |
# File 'lib/microsandbox/sandbox.rb', line 622 def drain @native.drain nil end |
#exec(command, args = [], cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ⇒ ExecOutput
Run a command (no shell interpretation) and collect its output.
462 463 464 465 |
# File 'lib/microsandbox/sandbox.rb', line 462 def exec(command, args = [], cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ExecOutput.new(@native.exec(command.to_s, Array(args).map(&:to_s), exec_opts(cwd:, user:, env:, timeout:, tty:, stdin:, rlimits:))) end |
#exec_stream(command, args = [], cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ⇒ ExecHandle
Run a command and stream its output as it arrives.
Pass stdin: :pipe to feed the process interactively: ExecHandle#stdin then returns a writable sink; close it to send EOF (a process like cat that reads until EOF will otherwise block forever).
481 482 483 484 |
# File 'lib/microsandbox/sandbox.rb', line 481 def exec_stream(command, args = [], cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ExecHandle.new(@native.exec_stream(command.to_s, Array(args).map(&:to_s), exec_opts(cwd:, user:, env:, timeout:, tty:, stdin:, rlimits:, pipe_ok: true))) end |
#fs ⇒ FS
Guest filesystem operations.
534 535 536 |
# File 'lib/microsandbox/sandbox.rb', line 534 def fs @fs ||= FS.new(@native) end |
#inspect ⇒ Object
654 655 656 |
# File 'lib/microsandbox/sandbox.rb', line 654 def inspect "#<Microsandbox::Sandbox name=#{name.inspect}>" end |
#kill ⇒ nil
Force-kill the sandbox (SIGKILL).
615 616 617 618 |
# File 'lib/microsandbox/sandbox.rb', line 615 def kill @native.kill nil end |
#log_stream(sources: nil, since_ms: nil, from_cursor: nil, until_ms: nil, follow: false) ⇒ LogStream
Stream captured logs as they appear.
588 589 590 591 592 593 594 595 596 |
# File 'lib/microsandbox/sandbox.rb', line 588 def log_stream(sources: nil, since_ms: nil, from_cursor: nil, until_ms: nil, follow: false) opts = {} opts["sources"] = Array(sources).map(&:to_s) if sources opts["since_ms"] = Float(since_ms) if since_ms opts["from_cursor"] = from_cursor.to_s if from_cursor opts["until_ms"] = Float(until_ms) if until_ms opts["follow"] = true if follow LogStream.new(@native.log_stream(opts)) end |
#logs(tail: nil, since_ms: nil, until_ms: nil, sources: nil) ⇒ Array<LogEntry>
Read captured logs.
561 562 563 564 565 566 567 568 |
# File 'lib/microsandbox/sandbox.rb', line 561 def logs(tail: nil, since_ms: nil, until_ms: nil, sources: nil) opts = {} opts["tail"] = Integer(tail) if tail opts["since_ms"] = Float(since_ms) if since_ms opts["until_ms"] = Float(until_ms) if until_ms opts["sources"] = Array(sources).map(&:to_s) if sources @native.logs(opts).map { |entry| LogEntry.new(entry) } end |
#metrics ⇒ Metrics
Latest resource-usage snapshot.
549 550 551 |
# File 'lib/microsandbox/sandbox.rb', line 549 def metrics Metrics.new(@native.metrics) end |
#metrics_stream(interval: 1.0) ⇒ MetricsStream
Stream resource-usage snapshots, one per interval tick, until the sandbox stops. Requires metrics to be enabled for the sandbox.
574 575 576 |
# File 'lib/microsandbox/sandbox.rb', line 574 def metrics_stream(interval: 1.0) MetricsStream.new(@native.metrics_stream(coerce_duration(interval, "interval"))) end |
#name ⇒ String
Returns the sandbox name.
445 446 447 |
# File 'lib/microsandbox/sandbox.rb', line 445 def name @native.name end |
#owns_lifecycle? ⇒ Boolean
Returns whether this handle owns the sandbox process lifecycle (i.e. stopping it or dropping the handle terminates the sandbox).
642 643 644 |
# File 'lib/microsandbox/sandbox.rb', line 642 def owns_lifecycle? @native.owns_lifecycle end |
#shell(script, cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ⇒ ExecOutput
Run a shell script (pipes, redirects, etc. allowed) and collect output.
469 470 471 472 |
# File 'lib/microsandbox/sandbox.rb', line 469 def shell(script, cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ExecOutput.new(@native.shell(script.to_s, exec_opts(cwd:, user:, env:, timeout:, tty:, stdin:, rlimits:))) end |
#shell_stream(script, cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ⇒ ExecHandle
Run a shell script and stream its output as it arrives.
488 489 490 491 |
# File 'lib/microsandbox/sandbox.rb', line 488 def shell_stream(script, cwd: nil, user: nil, env: nil, timeout: nil, tty: false, stdin: nil, rlimits: nil) ExecHandle.new(@native.shell_stream(script.to_s, exec_opts(cwd:, user:, env:, timeout:, tty:, stdin:, rlimits:, pipe_ok: true))) end |
#ssh ⇒ SshOps
SSH access to the sandbox — open a native in-process SSH client or prepare a reusable server endpoint.
543 544 545 |
# File 'lib/microsandbox/sandbox.rb', line 543 def ssh SshOps.new(@native) end |
#status ⇒ Symbol
The live status, fetched from the backend (a round-trip per call).
636 637 638 |
# File 'lib/microsandbox/sandbox.rb', line 636 def status @native.status.to_sym end |
#stop ⇒ nil
Gracefully stop the sandbox (SIGTERM→SIGKILL escalation, 10s default) and wait for it to terminate. For a custom timeout or fire-and-return ‘request_*` control, fetch a Microsandbox::SandboxHandle via get.
602 603 604 605 |
# File 'lib/microsandbox/sandbox.rb', line 602 def stop @native.stop nil end |
#stop_and_wait ⇒ ExitStatus
Gracefully stop, then wait for the process to exit.
609 610 611 |
# File 'lib/microsandbox/sandbox.rb', line 609 def stop_and_wait ExitStatus.new(@native.stop_and_wait) end |
#wait ⇒ ExitStatus
Wait for the sandbox process to exit.
629 630 631 |
# File 'lib/microsandbox/sandbox.rb', line 629 def wait ExitStatus.new(@native.wait) end |