microsandbox-rb 0.5.8 → 0.5.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +125 -0
- data/Cargo.lock +90 -45
- data/DESIGN.md +32 -19
- data/README.md +108 -36
- data/ext/microsandbox/Cargo.toml +4 -4
- data/ext/microsandbox/extconf.rb +6 -2
- data/ext/microsandbox/src/agent.rs +166 -0
- data/ext/microsandbox/src/backend.rs +170 -0
- data/ext/microsandbox/src/conv.rs +19 -1
- data/ext/microsandbox/src/error.rs +6 -0
- data/ext/microsandbox/src/image.rs +7 -7
- data/ext/microsandbox/src/lib.rs +31 -4
- data/ext/microsandbox/src/sandbox.rs +666 -61
- data/ext/microsandbox/src/ssh.rs +317 -0
- data/ext/microsandbox/src/volume.rs +6 -1
- data/lib/microsandbox/agent.rb +181 -0
- data/lib/microsandbox/errors.rb +6 -0
- data/lib/microsandbox/exec_handle.rb +14 -11
- data/lib/microsandbox/fs.rb +7 -7
- data/lib/microsandbox/image.rb +1 -1
- data/lib/microsandbox/network.rb +300 -0
- data/lib/microsandbox/patch.rb +98 -0
- data/lib/microsandbox/sandbox.rb +285 -77
- data/lib/microsandbox/snapshot.rb +2 -2
- data/lib/microsandbox/ssh.rb +247 -0
- data/lib/microsandbox/version.rb +2 -2
- data/lib/microsandbox/volume.rb +3 -3
- data/lib/microsandbox.rb +65 -0
- data/sig/microsandbox.rbs +164 -14
- metadata +8 -1
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Microsandbox
|
|
4
|
+
# The result of an {SshClient#exec} call. Like {ExecOutput}, `stdout`/`stderr`
|
|
5
|
+
# are the captured bytes decoded as UTF-8 (lenient); use `stdout_bytes`/
|
|
6
|
+
# `stderr_bytes` for the raw ASCII-8BIT bytes.
|
|
7
|
+
class SshOutput
|
|
8
|
+
# @return [Integer] the remote command's exit status
|
|
9
|
+
attr_reader :status
|
|
10
|
+
# @return [String] raw stdout bytes (ASCII-8BIT)
|
|
11
|
+
attr_reader :stdout_bytes
|
|
12
|
+
# @return [String] raw stderr bytes (ASCII-8BIT)
|
|
13
|
+
attr_reader :stderr_bytes
|
|
14
|
+
|
|
15
|
+
def initialize(data)
|
|
16
|
+
@status = data["status"]
|
|
17
|
+
@success = data["success"]
|
|
18
|
+
@stdout_bytes = data["stdout"]
|
|
19
|
+
@stderr_bytes = data["stderr"]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [Boolean] whether the command exited with status 0
|
|
23
|
+
def success? = @success
|
|
24
|
+
|
|
25
|
+
# @return [Boolean] whether the command exited non-zero
|
|
26
|
+
def failure? = !@success
|
|
27
|
+
|
|
28
|
+
# @return [String] stdout decoded as UTF-8
|
|
29
|
+
def stdout
|
|
30
|
+
@stdout ||= @stdout_bytes.dup.force_encoding(Encoding::UTF_8)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [String] stderr decoded as UTF-8
|
|
34
|
+
def stderr
|
|
35
|
+
@stderr ||= @stderr_bytes.dup.force_encoding(Encoding::UTF_8)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def to_s = stdout
|
|
39
|
+
|
|
40
|
+
def inspect
|
|
41
|
+
"#<Microsandbox::SshOutput status=#{@status} success=#{@success} " \
|
|
42
|
+
"stdout=#{stdout.bytesize}B stderr=#{stderr.bytesize}B>"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# A high-level SFTP session over an {SshClient}, from {SshClient#sftp}. All
|
|
47
|
+
# paths are guest paths. Mirrors the `SftpClient` of the official SDKs.
|
|
48
|
+
class SftpClient
|
|
49
|
+
def initialize(native)
|
|
50
|
+
@native = native
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Read a file's full contents.
|
|
54
|
+
# @return [String] raw bytes (ASCII-8BIT)
|
|
55
|
+
def read(path)
|
|
56
|
+
@native.read(path.to_s)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Read a file and decode it as UTF-8 (lenient).
|
|
60
|
+
# @return [String]
|
|
61
|
+
def read_text(path)
|
|
62
|
+
read(path).force_encoding(Encoding::UTF_8)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Write a file, creating or truncating it.
|
|
66
|
+
# @return [nil]
|
|
67
|
+
def write(path, data)
|
|
68
|
+
@native.write(path.to_s, data.to_s)
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Create a directory.
|
|
73
|
+
# @return [nil]
|
|
74
|
+
def mkdir(path)
|
|
75
|
+
@native.mkdir(path.to_s)
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Remove a file.
|
|
80
|
+
# @return [nil]
|
|
81
|
+
def remove_file(path)
|
|
82
|
+
@native.remove_file(path.to_s)
|
|
83
|
+
nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Remove an empty directory.
|
|
87
|
+
# @return [nil]
|
|
88
|
+
def remove_dir(path)
|
|
89
|
+
@native.remove_dir(path.to_s)
|
|
90
|
+
nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Rename (move) a file or directory.
|
|
94
|
+
# @return [nil]
|
|
95
|
+
def rename(old_path, new_path)
|
|
96
|
+
@native.rename(old_path.to_s, new_path.to_s)
|
|
97
|
+
nil
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Create a symlink at +link_path+ pointing to +target+.
|
|
101
|
+
# @return [nil]
|
|
102
|
+
def symlink(target, link_path)
|
|
103
|
+
@native.symlink(target.to_s, link_path.to_s)
|
|
104
|
+
nil
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Resolve a path to its canonical absolute form.
|
|
108
|
+
# @return [String]
|
|
109
|
+
def real_path(path)
|
|
110
|
+
@native.real_path(path.to_s)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Read a symlink's target.
|
|
114
|
+
# @return [String]
|
|
115
|
+
def read_link(path)
|
|
116
|
+
@native.read_link(path.to_s)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Close the SFTP session. Idempotent.
|
|
120
|
+
# @return [nil]
|
|
121
|
+
def close
|
|
122
|
+
@native.close
|
|
123
|
+
nil
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# A native, in-process SSH client session to a sandbox, from
|
|
128
|
+
# {SshOps#open_client}. Mirrors the `SshClient` of the official SDKs.
|
|
129
|
+
#
|
|
130
|
+
# @example
|
|
131
|
+
# sb.ssh.open_client do |client|
|
|
132
|
+
# out = client.exec("uname -a")
|
|
133
|
+
# puts out.stdout
|
|
134
|
+
# end
|
|
135
|
+
class SshClient
|
|
136
|
+
def initialize(native)
|
|
137
|
+
@native = native
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Run a command over SSH and collect its output.
|
|
141
|
+
# @param command [String] the command line (interpreted by the remote shell)
|
|
142
|
+
# @param tty [Boolean] allocate a pseudo-terminal
|
|
143
|
+
# @return [SshOutput]
|
|
144
|
+
def exec(command, tty: false)
|
|
145
|
+
SshOutput.new(@native.exec(command.to_s, tty ? true : false))
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Attach the local terminal to an interactive SSH shell. Host-TTY coupled
|
|
149
|
+
# (puts the terminal in raw mode and forwards SIGWINCH); blocks until the
|
|
150
|
+
# remote shell exits or the detach sequence is typed.
|
|
151
|
+
# @param term [String, nil] TERM value to request (defaults to $TERM)
|
|
152
|
+
# @param detach_keys [String, nil] detach key sequence (e.g. "ctrl-p,ctrl-q")
|
|
153
|
+
# @return [Integer] the remote shell's exit status
|
|
154
|
+
def attach(term: nil, detach_keys: nil)
|
|
155
|
+
@native.attach(term&.to_s, detach_keys&.to_s)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Open an SFTP session over this connection. With a block, the session is
|
|
159
|
+
# yielded and closed when the block returns.
|
|
160
|
+
# @yieldparam sftp [SftpClient]
|
|
161
|
+
# @return [SftpClient, Object]
|
|
162
|
+
def sftp
|
|
163
|
+
session = SftpClient.new(@native.sftp)
|
|
164
|
+
return session unless block_given?
|
|
165
|
+
|
|
166
|
+
begin
|
|
167
|
+
yield session
|
|
168
|
+
ensure
|
|
169
|
+
session.close
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Close the SSH client session. Idempotent.
|
|
174
|
+
# @return [nil]
|
|
175
|
+
def close
|
|
176
|
+
@native.close
|
|
177
|
+
nil
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# A reusable SSH server endpoint for a sandbox, from {SshOps#prepare_server}.
|
|
182
|
+
# Each {#serve_connection} serves a single SSH transport over this process's
|
|
183
|
+
# stdin/stdout — typically wired up by a parent SSH daemon via `ForceCommand`
|
|
184
|
+
# or an inetd-style spawn. Mirrors the `SshServer` of the official SDKs.
|
|
185
|
+
class SshServer
|
|
186
|
+
def initialize(native)
|
|
187
|
+
@native = native
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Serve one SSH connection over this process's stdin/stdout. Blocks until
|
|
191
|
+
# the session ends.
|
|
192
|
+
# @return [nil]
|
|
193
|
+
def serve_connection
|
|
194
|
+
@native.serve_connection
|
|
195
|
+
nil
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Release the prepared server endpoint. Idempotent.
|
|
199
|
+
# @return [nil]
|
|
200
|
+
def close
|
|
201
|
+
@native.close
|
|
202
|
+
nil
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# The SSH namespace for a sandbox, returned by {Sandbox#ssh}. Use it to open a
|
|
207
|
+
# native in-process SSH client or prepare a reusable server endpoint.
|
|
208
|
+
class SshOps
|
|
209
|
+
def initialize(native)
|
|
210
|
+
@native = native
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Open a native in-process SSH client to the sandbox. With a block, the
|
|
214
|
+
# client is yielded and closed when the block returns.
|
|
215
|
+
# @param user [String] guest user to authenticate as (default "root")
|
|
216
|
+
# @param term [String, nil] TERM value for the session
|
|
217
|
+
# @param sftp [Boolean] enable the SFTP subsystem (default true)
|
|
218
|
+
# @yieldparam client [SshClient]
|
|
219
|
+
# @return [SshClient, Object]
|
|
220
|
+
def open_client(user: "root", term: nil, sftp: true)
|
|
221
|
+
opts = {"user" => user.to_s, "sftp" => sftp ? true : false}
|
|
222
|
+
opts["term"] = term.to_s if term
|
|
223
|
+
client = SshClient.new(@native.ssh_open_client(opts))
|
|
224
|
+
return client unless block_given?
|
|
225
|
+
|
|
226
|
+
begin
|
|
227
|
+
yield client
|
|
228
|
+
ensure
|
|
229
|
+
client.close
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Prepare a reusable SSH server endpoint for the sandbox.
|
|
234
|
+
# @param host_key_path [String, nil] PEM host key path (generated if omitted)
|
|
235
|
+
# @param authorized_keys_path [String, nil] authorized_keys file path
|
|
236
|
+
# @param user [String, nil] guest user connections run as
|
|
237
|
+
# @param sftp [Boolean] enable the SFTP subsystem (default true)
|
|
238
|
+
# @return [SshServer]
|
|
239
|
+
def prepare_server(host_key_path: nil, authorized_keys_path: nil, user: nil, sftp: true)
|
|
240
|
+
opts = {"sftp" => sftp ? true : false}
|
|
241
|
+
opts["host_key_path"] = host_key_path.to_s if host_key_path
|
|
242
|
+
opts["authorized_keys_path"] = authorized_keys_path.to_s if authorized_keys_path
|
|
243
|
+
opts["user"] = user.to_s if user
|
|
244
|
+
SshServer.new(@native.ssh_prepare_server(opts))
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
data/lib/microsandbox/version.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Microsandbox
|
|
4
|
-
# Gem version. Tracks the upstream microsandbox runtime (currently `v0.5.
|
|
4
|
+
# Gem version. Tracks the upstream microsandbox runtime (currently `v0.5.8`,
|
|
5
5
|
# the pinned core-crate tag); the patch segment advances for gem-only revisions
|
|
6
6
|
# that add bindings atop the same core. Must equal the native ext's Cargo crate
|
|
7
7
|
# version (`Native.version`), enforced by spec/unit/version_spec.rb.
|
|
8
|
-
VERSION = "0.5.
|
|
8
|
+
VERSION = "0.5.10"
|
|
9
9
|
end
|
data/lib/microsandbox/volume.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Microsandbox
|
|
|
7
7
|
# (`kind`, `used_bytes`, …) are populated when returned from {Volume.get}/{Volume.list}.
|
|
8
8
|
class VolumeInfo
|
|
9
9
|
attr_reader :name, :path, :quota_mib, :used_bytes, :capacity_bytes,
|
|
10
|
-
|
|
10
|
+
:disk_format, :disk_fstype, :labels
|
|
11
11
|
|
|
12
12
|
def initialize(data)
|
|
13
13
|
@name = data["name"]
|
|
@@ -33,7 +33,7 @@ module Microsandbox
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def inspect
|
|
36
|
-
"#<Microsandbox::VolumeInfo name=#{@name.inspect}#{
|
|
36
|
+
"#<Microsandbox::VolumeInfo name=#{@name.inspect}#{" kind=#{@kind}" if @kind}>"
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -49,7 +49,7 @@ module Microsandbox
|
|
|
49
49
|
# @param labels [Hash, nil]
|
|
50
50
|
# @return [VolumeInfo]
|
|
51
51
|
def create(name, kind: "dir", size_mib: nil, quota_mib: nil, labels: nil)
|
|
52
|
-
opts = {
|
|
52
|
+
opts = {"kind" => kind.to_s}
|
|
53
53
|
opts["size_mib"] = Integer(size_mib) if size_mib
|
|
54
54
|
opts["quota_mib"] = Integer(quota_mib) if quota_mib
|
|
55
55
|
opts["labels"] = labels.each_with_object({}) { |(k, v), a| a[k.to_s] = v.to_s } if labels
|
data/lib/microsandbox.rb
CHANGED
|
@@ -22,6 +22,10 @@ require_relative "microsandbox/streams"
|
|
|
22
22
|
require_relative "microsandbox/image"
|
|
23
23
|
require_relative "microsandbox/volume"
|
|
24
24
|
require_relative "microsandbox/snapshot"
|
|
25
|
+
require_relative "microsandbox/patch"
|
|
26
|
+
require_relative "microsandbox/network"
|
|
27
|
+
require_relative "microsandbox/agent"
|
|
28
|
+
require_relative "microsandbox/ssh"
|
|
25
29
|
require_relative "microsandbox/sandbox"
|
|
26
30
|
|
|
27
31
|
# Microsandbox — lightweight microVM sandboxes for Ruby.
|
|
@@ -74,6 +78,11 @@ module Microsandbox
|
|
|
74
78
|
# @return [nil]
|
|
75
79
|
def ensure_runtime!
|
|
76
80
|
return if @runtime_ready
|
|
81
|
+
# A cloud backend has no local msb/libkrunfw runtime to provision: skip the
|
|
82
|
+
# presence check and the first-use download entirely. Resolving the kind
|
|
83
|
+
# uses the same lazy env/profile/config ladder every operation already
|
|
84
|
+
# consults, so this adds no work for local hosts (the common case).
|
|
85
|
+
return if default_backend_kind == :cloud
|
|
77
86
|
if installed?
|
|
78
87
|
@runtime_ready = true
|
|
79
88
|
return
|
|
@@ -100,6 +109,62 @@ module Microsandbox
|
|
|
100
109
|
Native.set_runtime_msb_path(path.to_s)
|
|
101
110
|
end
|
|
102
111
|
|
|
112
|
+
# Override the `libkrunfw` shared-library path (SDK tier of the resolver,
|
|
113
|
+
# below the `MSB_LIBKRUNFW_PATH` environment variable). Process-level and
|
|
114
|
+
# set-once: a second call is silently ignored, and the env var still wins.
|
|
115
|
+
# Mirrors {runtime_path=} for libkrunfw.
|
|
116
|
+
# @param path [String]
|
|
117
|
+
# @return [void]
|
|
118
|
+
def libkrunfw_path=(path)
|
|
119
|
+
Native.set_runtime_libkrunfw_path(path.to_s)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Install a process-wide default backend (v0.5.8 backend routing). Without a
|
|
123
|
+
# call to this, operations use a local libkrun backend; the env/profile
|
|
124
|
+
# ladder (`MSB_BACKEND`, `MSB_API_URL`+`MSB_API_KEY`, `MSB_PROFILE`,
|
|
125
|
+
# `~/.microsandbox/config.json`) is resolved lazily on first use. Call once
|
|
126
|
+
# at startup, before any sandbox operations.
|
|
127
|
+
#
|
|
128
|
+
# @param kind ["local","cloud", Symbol] backend kind
|
|
129
|
+
# @param url [String, nil] cloud control-plane URL (cloud, unless `profile:`)
|
|
130
|
+
# @param api_key [String, nil] cloud API key (cloud, unless `profile:`)
|
|
131
|
+
# @param profile [String, nil] named profile from `~/.microsandbox/config.json`
|
|
132
|
+
# @return [void]
|
|
133
|
+
def set_default_backend(kind, url: nil, api_key: nil, profile: nil)
|
|
134
|
+
Native.set_default_backend(kind.to_s, url&.to_s, api_key&.to_s, profile&.to_s)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Run the given block with a temporary default backend, restoring the
|
|
138
|
+
# previous one afterward (even on error). NOTE: the swap is process-wide
|
|
139
|
+
# while the block runs, not fiber/thread-local — concurrent threads observe
|
|
140
|
+
# the temporary backend. It is also NOT safe to call from multiple threads
|
|
141
|
+
# at once: two interleaved `with_backend` calls can restore each other's
|
|
142
|
+
# saved backend out of order and leave a temporary backend installed
|
|
143
|
+
# permanently. Use it only when no other thread is changing the backend, and
|
|
144
|
+
# avoid calling {set_default_backend} inside the block (the restore on exit
|
|
145
|
+
# would overwrite that change). Mirrors the official SDKs' scoped-backend helper.
|
|
146
|
+
#
|
|
147
|
+
# @param kind ["local","cloud", Symbol]
|
|
148
|
+
# @param url [String, nil]
|
|
149
|
+
# @param api_key [String, nil]
|
|
150
|
+
# @param profile [String, nil]
|
|
151
|
+
# @yield with the temporary backend installed
|
|
152
|
+
# @return [Object] the block's return value
|
|
153
|
+
def with_backend(kind, url: nil, api_key: nil, profile: nil)
|
|
154
|
+
token = Native.push_default_backend(kind.to_s, url&.to_s, api_key&.to_s, profile&.to_s)
|
|
155
|
+
begin
|
|
156
|
+
yield
|
|
157
|
+
ensure
|
|
158
|
+
Native.pop_default_backend(token)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# @return [Symbol] the active default backend kind, :local or :cloud.
|
|
163
|
+
# The first call resolves the env/profile/config ladder.
|
|
164
|
+
def default_backend_kind
|
|
165
|
+
Native.default_backend_kind.to_sym
|
|
166
|
+
end
|
|
167
|
+
|
|
103
168
|
# Latest resource-usage snapshot for every running sandbox, keyed by name.
|
|
104
169
|
# Mirrors the official `all_sandbox_metrics`/`allSandboxMetrics` helpers.
|
|
105
170
|
# @return [Hash{String => Metrics}]
|
data/sig/microsandbox.rbs
CHANGED
|
@@ -9,8 +9,13 @@ module Microsandbox
|
|
|
9
9
|
def self.ensure_runtime!: () -> nil
|
|
10
10
|
def self.runtime_path: () -> String
|
|
11
11
|
def self.runtime_path=: (String path) -> void
|
|
12
|
+
def self.libkrunfw_path=: (String path) -> void
|
|
12
13
|
def self.all_sandbox_metrics: () -> Hash[String, Metrics]
|
|
13
14
|
|
|
15
|
+
def self.set_default_backend: (String | Symbol kind, ?url: String?, ?api_key: String?, ?profile: String?) -> void
|
|
16
|
+
def self.with_backend: [T] (String | Symbol kind, ?url: String?, ?api_key: String?, ?profile: String?) { () -> T } -> T
|
|
17
|
+
def self.default_backend_kind: () -> Symbol
|
|
18
|
+
|
|
14
19
|
class Error < StandardError
|
|
15
20
|
def self.code: () -> String
|
|
16
21
|
def code: () -> String
|
|
@@ -37,6 +42,8 @@ module Microsandbox
|
|
|
37
42
|
class MetricsDisabledError < Error end
|
|
38
43
|
class MetricsUnavailableError < Error end
|
|
39
44
|
class UnsupportedOperationError < Error end
|
|
45
|
+
class CloudHttpError < Error end
|
|
46
|
+
class UnsupportedError < Error end
|
|
40
47
|
|
|
41
48
|
class ExecOutput
|
|
42
49
|
def initialize: (Hash[String, untyped] data) -> void
|
|
@@ -114,15 +121,26 @@ module Microsandbox
|
|
|
114
121
|
def timestamp: () -> Time
|
|
115
122
|
end
|
|
116
123
|
|
|
117
|
-
class
|
|
124
|
+
class SandboxHandle
|
|
118
125
|
def name: () -> String
|
|
119
126
|
def status: () -> Symbol
|
|
120
127
|
def running?: () -> bool
|
|
121
128
|
def stopped?: () -> bool
|
|
122
129
|
def created_at: () -> Time?
|
|
123
130
|
def updated_at: () -> Time?
|
|
131
|
+
def stop: () -> nil
|
|
132
|
+
def stop_with_timeout: (Numeric timeout) -> nil
|
|
133
|
+
def kill: () -> nil
|
|
134
|
+
def kill_with_timeout: (Numeric timeout) -> nil
|
|
135
|
+
def request_stop: () -> nil
|
|
136
|
+
def request_kill: () -> nil
|
|
137
|
+
def request_drain: () -> nil
|
|
138
|
+
def wait_until_stopped: () -> SandboxStopResult
|
|
124
139
|
end
|
|
125
140
|
|
|
141
|
+
# Deprecated alias for SandboxHandle (was a read-only metadata type pre-v0.5.8).
|
|
142
|
+
SandboxInfo: singleton(SandboxHandle)
|
|
143
|
+
|
|
126
144
|
class SandboxStopResult
|
|
127
145
|
def name: () -> String
|
|
128
146
|
def status: () -> Symbol
|
|
@@ -140,7 +158,8 @@ module Microsandbox
|
|
|
140
158
|
?user: String?, ?hostname: String?, ?labels: Hash[untyped, untyped]?,
|
|
141
159
|
?scripts: Hash[untyped, untyped]?, ?entrypoint: Array[String]?,
|
|
142
160
|
?ports: Hash[untyped, untyped]?, ?ports_udp: Hash[untyped, untyped]?,
|
|
143
|
-
?volumes: Hash[untyped, untyped]?, ?network: untyped?,
|
|
161
|
+
?volumes: Hash[untyped, untyped]?, ?network: untyped?,
|
|
162
|
+
?patches: Array[Hash[untyped, untyped]]?, ?from_snapshot: String?,
|
|
144
163
|
?log_level: (String | Symbol)?, ?quiet_logs: bool, ?security: (String | Symbol)?,
|
|
145
164
|
?oci_upper_size: Integer?, ?max_duration: Integer?, ?idle_timeout: Integer?,
|
|
146
165
|
?rlimits: Hash[untyped, untyped]?, ?pull_policy: (String | Symbol)?,
|
|
@@ -150,9 +169,9 @@ module Microsandbox
|
|
|
150
169
|
?replace: bool, ?replace_with_timeout: Numeric?)
|
|
151
170
|
?{ (Sandbox) -> untyped } -> untyped
|
|
152
171
|
def self.start: (String name, ?detached: bool) -> Sandbox
|
|
153
|
-
def self.get: (String name) ->
|
|
154
|
-
def self.list: () -> Array[
|
|
155
|
-
def self.list_with: (?labels: Hash[untyped, untyped]) -> Array[
|
|
172
|
+
def self.get: (String name) -> SandboxHandle
|
|
173
|
+
def self.list: () -> Array[SandboxHandle]
|
|
174
|
+
def self.list_with: (?labels: Hash[untyped, untyped]) -> Array[SandboxHandle]
|
|
156
175
|
def self.remove: (String name) -> nil
|
|
157
176
|
|
|
158
177
|
def name: () -> String
|
|
@@ -162,23 +181,28 @@ module Microsandbox
|
|
|
162
181
|
def shell: (String script, ?cwd: String?, ?user: String?, ?env: Hash[untyped, untyped]?,
|
|
163
182
|
?timeout: Numeric?, ?tty: bool, ?stdin: String?, ?rlimits: Hash[untyped, untyped]?) -> ExecOutput
|
|
164
183
|
def exec_stream: (String command, ?Array[String] args, ?cwd: String?, ?user: String?,
|
|
165
|
-
?env: Hash[untyped, untyped]?, ?timeout: Numeric?, ?tty: bool, ?stdin: String?,
|
|
184
|
+
?env: Hash[untyped, untyped]?, ?timeout: Numeric?, ?tty: bool, ?stdin: (String | :pipe)?,
|
|
166
185
|
?rlimits: Hash[untyped, untyped]?) -> ExecHandle
|
|
167
186
|
def shell_stream: (String script, ?cwd: String?, ?user: String?, ?env: Hash[untyped, untyped]?,
|
|
168
|
-
?timeout: Numeric?, ?tty: bool, ?stdin: String?, ?rlimits: Hash[untyped, untyped]?) -> ExecHandle
|
|
187
|
+
?timeout: Numeric?, ?tty: bool, ?stdin: (String | :pipe)?, ?rlimits: Hash[untyped, untyped]?) -> ExecHandle
|
|
188
|
+
def attach: (String command, ?Array[String] args, ?cwd: String?, ?user: String?,
|
|
189
|
+
?env: Hash[untyped, untyped]?, ?detach_keys: String?,
|
|
190
|
+
?rlimits: Hash[untyped, untyped]?) -> Integer
|
|
191
|
+
def attach_shell: () -> Integer
|
|
169
192
|
def fs: () -> FS
|
|
193
|
+
def ssh: () -> SshOps
|
|
170
194
|
def metrics: () -> Metrics
|
|
171
195
|
def logs: (?tail: Integer?, ?since_ms: Numeric?, ?until_ms: Numeric?,
|
|
172
196
|
?sources: Array[String | Symbol]?) -> Array[LogEntry]
|
|
173
197
|
def metrics_stream: (?interval: Numeric) -> MetricsStream
|
|
174
198
|
def log_stream: (?sources: Array[String | Symbol]?, ?since_ms: Numeric?,
|
|
175
199
|
?from_cursor: String?, ?until_ms: Numeric?, ?follow: bool) -> LogStream
|
|
176
|
-
def stop: (
|
|
177
|
-
def
|
|
178
|
-
def
|
|
179
|
-
def
|
|
180
|
-
def
|
|
181
|
-
def
|
|
200
|
+
def stop: () -> nil
|
|
201
|
+
def stop_and_wait: () -> ExitStatus
|
|
202
|
+
def kill: () -> nil
|
|
203
|
+
def drain: () -> nil
|
|
204
|
+
def wait: () -> ExitStatus
|
|
205
|
+
def status: () -> Symbol
|
|
182
206
|
def owns_lifecycle?: () -> bool
|
|
183
207
|
def detach: () -> nil
|
|
184
208
|
end
|
|
@@ -210,7 +234,7 @@ module Microsandbox
|
|
|
210
234
|
end
|
|
211
235
|
|
|
212
236
|
class ExitStatus
|
|
213
|
-
def exit_code: () -> Integer
|
|
237
|
+
def exit_code: () -> Integer?
|
|
214
238
|
def success?: () -> bool
|
|
215
239
|
def failure?: () -> bool
|
|
216
240
|
end
|
|
@@ -321,4 +345,130 @@ module Microsandbox
|
|
|
321
345
|
?with_image: bool, ?plain_tar: bool) -> nil
|
|
322
346
|
def self.import: (String archive_path, ?dest: String?) -> SnapshotInfo
|
|
323
347
|
end
|
|
348
|
+
|
|
349
|
+
module Patch
|
|
350
|
+
def self.text: (String path, String content, ?mode: Integer?, ?replace: bool) -> Hash[String, untyped]
|
|
351
|
+
def self.file: (String path, String content, ?mode: Integer?, ?replace: bool) -> Hash[String, untyped]
|
|
352
|
+
def self.append: (String path, String content) -> Hash[String, untyped]
|
|
353
|
+
def self.copy_file: (String src, String dst, ?mode: Integer?, ?replace: bool) -> Hash[String, untyped]
|
|
354
|
+
def self.copy_dir: (String src, String dst, ?replace: bool) -> Hash[String, untyped]
|
|
355
|
+
def self.symlink: (String target, String link, ?replace: bool) -> Hash[String, untyped]
|
|
356
|
+
def self.mkdir: (String path, ?mode: Integer?) -> Hash[String, untyped]
|
|
357
|
+
def self.remove: (String path) -> Hash[String, untyped]
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
module Destination
|
|
361
|
+
def self.any: () -> Hash[String, String]
|
|
362
|
+
def self.ip: (String value) -> Hash[String, String]
|
|
363
|
+
def self.cidr: (String value) -> Hash[String, String]
|
|
364
|
+
def self.domain: (String value) -> Hash[String, String]
|
|
365
|
+
def self.domain_suffix: (String value) -> Hash[String, String]
|
|
366
|
+
def self.group: ((String | Symbol) value) -> Hash[String, String]
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
module Rule
|
|
370
|
+
def self.allow: (?destination: untyped?, ?direction: (String | Symbol),
|
|
371
|
+
?protocol: (String | Symbol)?, ?protocols: Array[String | Symbol]?,
|
|
372
|
+
?port: (String | Integer)?, ?ports: Array[String | Integer]?) -> Hash[String, untyped]
|
|
373
|
+
def self.deny: (?destination: untyped?, ?direction: (String | Symbol),
|
|
374
|
+
?protocol: (String | Symbol)?, ?protocols: Array[String | Symbol]?,
|
|
375
|
+
?port: (String | Integer)?, ?ports: Array[String | Integer]?) -> Hash[String, untyped]
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
class NetworkPolicy
|
|
379
|
+
PRESET_ALIASES: Hash[String, String]
|
|
380
|
+
def self.public_only: () -> NetworkPolicy
|
|
381
|
+
def self.none: () -> NetworkPolicy
|
|
382
|
+
def self.allow_all: () -> NetworkPolicy
|
|
383
|
+
def self.non_local: () -> NetworkPolicy
|
|
384
|
+
def self.preset: ((String | Symbol) name) -> NetworkPolicy
|
|
385
|
+
def self.custom: (?default_egress: (String | Symbol)?, ?default_ingress: (String | Symbol)?,
|
|
386
|
+
?rules: Array[Hash[untyped, untyped]], ?deny_domains: Array[String],
|
|
387
|
+
?deny_domain_suffixes: Array[String]) -> NetworkPolicy
|
|
388
|
+
def self.coerce: (untyped network) -> Hash[String, untyped]
|
|
389
|
+
def initialize: (Hash[String, untyped] wire) -> void
|
|
390
|
+
def to_h: () -> Hash[String, untyped]
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
class AgentFrame
|
|
394
|
+
def initialize: (Hash[String, untyped] data) -> void
|
|
395
|
+
def id: () -> Integer
|
|
396
|
+
def flags: () -> Integer
|
|
397
|
+
def body: () -> String
|
|
398
|
+
def terminal?: () -> bool
|
|
399
|
+
def session_start?: () -> bool
|
|
400
|
+
def shutdown?: () -> bool
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
class AgentStream
|
|
404
|
+
include Enumerable[AgentFrame]
|
|
405
|
+
def id: () -> Integer
|
|
406
|
+
def recv: () -> AgentFrame?
|
|
407
|
+
def each: () { (AgentFrame) -> void } -> self
|
|
408
|
+
| () -> Enumerator[AgentFrame, self]
|
|
409
|
+
def close: () -> nil
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
class AgentClient
|
|
413
|
+
FLAG_TERMINAL: Integer
|
|
414
|
+
FLAG_SESSION_START: Integer
|
|
415
|
+
FLAG_SHUTDOWN: Integer
|
|
416
|
+
def self.connect_sandbox: (String name, ?timeout: Numeric?) ?{ (AgentClient) -> untyped } -> untyped
|
|
417
|
+
def self.connect_path: (String path, ?timeout: Numeric?) ?{ (AgentClient) -> untyped } -> untyped
|
|
418
|
+
def self.socket_path: (String name) -> String
|
|
419
|
+
def initialize: (untyped native) -> void
|
|
420
|
+
def request: (Integer flags, String body) -> AgentFrame
|
|
421
|
+
def stream: (Integer flags, String body) -> AgentStream
|
|
422
|
+
def send_frame: (Integer id, Integer flags, String body) -> nil
|
|
423
|
+
def ready_bytes: () -> String
|
|
424
|
+
def close: () -> nil
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
class SshOutput
|
|
428
|
+
def initialize: (Hash[String, untyped] data) -> void
|
|
429
|
+
def status: () -> Integer
|
|
430
|
+
def success?: () -> bool
|
|
431
|
+
def failure?: () -> bool
|
|
432
|
+
def stdout: () -> String
|
|
433
|
+
def stderr: () -> String
|
|
434
|
+
def stdout_bytes: () -> String
|
|
435
|
+
def stderr_bytes: () -> String
|
|
436
|
+
def to_s: () -> String
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
class SftpClient
|
|
440
|
+
def initialize: (untyped native) -> void
|
|
441
|
+
def read: (String path) -> String
|
|
442
|
+
def read_text: (String path) -> String
|
|
443
|
+
def write: (String path, String data) -> nil
|
|
444
|
+
def mkdir: (String path) -> nil
|
|
445
|
+
def remove_file: (String path) -> nil
|
|
446
|
+
def remove_dir: (String path) -> nil
|
|
447
|
+
def rename: (String old_path, String new_path) -> nil
|
|
448
|
+
def symlink: (String target, String link_path) -> nil
|
|
449
|
+
def real_path: (String path) -> String
|
|
450
|
+
def read_link: (String path) -> String
|
|
451
|
+
def close: () -> nil
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
class SshClient
|
|
455
|
+
def initialize: (untyped native) -> void
|
|
456
|
+
def exec: (String command, ?tty: bool) -> SshOutput
|
|
457
|
+
def attach: (?term: String?, ?detach_keys: String?) -> Integer
|
|
458
|
+
def sftp: () ?{ (SftpClient) -> untyped } -> untyped
|
|
459
|
+
def close: () -> nil
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
class SshServer
|
|
463
|
+
def initialize: (untyped native) -> void
|
|
464
|
+
def serve_connection: () -> nil
|
|
465
|
+
def close: () -> nil
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
class SshOps
|
|
469
|
+
def initialize: (untyped native) -> void
|
|
470
|
+
def open_client: (?user: String, ?term: String?, ?sftp: bool) ?{ (SshClient) -> untyped } -> untyped
|
|
471
|
+
def prepare_server: (?host_key_path: String?, ?authorized_keys_path: String?,
|
|
472
|
+
?user: String?, ?sftp: bool) -> SshServer
|
|
473
|
+
end
|
|
324
474
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: microsandbox-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.10
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- ya-luotao
|
|
@@ -45,6 +45,8 @@ files:
|
|
|
45
45
|
- README.md
|
|
46
46
|
- ext/microsandbox/Cargo.toml
|
|
47
47
|
- ext/microsandbox/extconf.rb
|
|
48
|
+
- ext/microsandbox/src/agent.rs
|
|
49
|
+
- ext/microsandbox/src/backend.rs
|
|
48
50
|
- ext/microsandbox/src/conv.rs
|
|
49
51
|
- ext/microsandbox/src/error.rs
|
|
50
52
|
- ext/microsandbox/src/exec.rs
|
|
@@ -53,9 +55,11 @@ files:
|
|
|
53
55
|
- ext/microsandbox/src/runtime.rs
|
|
54
56
|
- ext/microsandbox/src/sandbox.rs
|
|
55
57
|
- ext/microsandbox/src/snapshot.rs
|
|
58
|
+
- ext/microsandbox/src/ssh.rs
|
|
56
59
|
- ext/microsandbox/src/stream.rs
|
|
57
60
|
- ext/microsandbox/src/volume.rs
|
|
58
61
|
- lib/microsandbox.rb
|
|
62
|
+
- lib/microsandbox/agent.rb
|
|
59
63
|
- lib/microsandbox/errors.rb
|
|
60
64
|
- lib/microsandbox/exec_handle.rb
|
|
61
65
|
- lib/microsandbox/exec_output.rb
|
|
@@ -63,8 +67,11 @@ files:
|
|
|
63
67
|
- lib/microsandbox/image.rb
|
|
64
68
|
- lib/microsandbox/log_entry.rb
|
|
65
69
|
- lib/microsandbox/metrics.rb
|
|
70
|
+
- lib/microsandbox/network.rb
|
|
71
|
+
- lib/microsandbox/patch.rb
|
|
66
72
|
- lib/microsandbox/sandbox.rb
|
|
67
73
|
- lib/microsandbox/snapshot.rb
|
|
74
|
+
- lib/microsandbox/ssh.rb
|
|
68
75
|
- lib/microsandbox/streams.rb
|
|
69
76
|
- lib/microsandbox/version.rb
|
|
70
77
|
- lib/microsandbox/volume.rb
|