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.
462 463 464 |
# File 'lib/microsandbox/sandbox.rb', line 462 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`.
532 533 534 535 536 537 538 539 540 541 542 543 544 545 |
# File 'lib/microsandbox/sandbox.rb', line 532 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.
550 551 552 |
# File 'lib/microsandbox/sandbox.rb', line 550 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).
671 672 673 674 |
# File 'lib/microsandbox/sandbox.rb', line 671 def detach @native.detach nil end |
#drain ⇒ nil
Trigger a graceful drain (SIGUSR1).
644 645 646 647 |
# File 'lib/microsandbox/sandbox.rb', line 644 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.
484 485 486 487 |
# File 'lib/microsandbox/sandbox.rb', line 484 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).
503 504 505 506 |
# File 'lib/microsandbox/sandbox.rb', line 503 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.
556 557 558 |
# File 'lib/microsandbox/sandbox.rb', line 556 def fs @fs ||= FS.new(@native) end |
#inspect ⇒ Object
676 677 678 |
# File 'lib/microsandbox/sandbox.rb', line 676 def inspect "#<Microsandbox::Sandbox name=#{name.inspect}>" end |
#kill ⇒ nil
Force-kill the sandbox (SIGKILL).
637 638 639 640 |
# File 'lib/microsandbox/sandbox.rb', line 637 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.
610 611 612 613 614 615 616 617 618 |
# File 'lib/microsandbox/sandbox.rb', line 610 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.
583 584 585 586 587 588 589 590 |
# File 'lib/microsandbox/sandbox.rb', line 583 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.
571 572 573 |
# File 'lib/microsandbox/sandbox.rb', line 571 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.
596 597 598 |
# File 'lib/microsandbox/sandbox.rb', line 596 def metrics_stream(interval: 1.0) MetricsStream.new(@native.metrics_stream(coerce_duration(interval, "interval"))) end |
#name ⇒ String
Returns the sandbox name.
467 468 469 |
# File 'lib/microsandbox/sandbox.rb', line 467 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).
664 665 666 |
# File 'lib/microsandbox/sandbox.rb', line 664 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.
491 492 493 494 |
# File 'lib/microsandbox/sandbox.rb', line 491 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.
510 511 512 513 |
# File 'lib/microsandbox/sandbox.rb', line 510 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.
565 566 567 |
# File 'lib/microsandbox/sandbox.rb', line 565 def ssh SshOps.new(@native) end |
#status ⇒ Symbol
The live status, fetched from the backend (a round-trip per call).
658 659 660 |
# File 'lib/microsandbox/sandbox.rb', line 658 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.
624 625 626 627 |
# File 'lib/microsandbox/sandbox.rb', line 624 def stop @native.stop nil end |
#stop_and_wait ⇒ ExitStatus
Gracefully stop, then wait for the process to exit.
631 632 633 |
# File 'lib/microsandbox/sandbox.rb', line 631 def stop_and_wait ExitStatus.new(@native.stop_and_wait) end |
#wait ⇒ ExitStatus
Wait for the sandbox process to exit.
651 652 653 |
# File 'lib/microsandbox/sandbox.rb', line 651 def wait ExitStatus.new(@native.wait) end |