sandbox-provider 0.1.1 → 0.1.2
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/lib/sandbox/provider/daytona/link.rb +59 -0
- data/lib/sandbox/provider/daytona.rb +31 -16
- data/lib/sandbox/provider/version.rb +1 -1
- data/lib/sandbox-provider.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c4be6ee4a326cae728dfa5986e371fb23a3b51a34646c3fc26d0c79e95647a7b
|
|
4
|
+
data.tar.gz: fd8ec5fda4686750696ea0e7ea14bdc317eeef2a90b6156ccee3c5ee91595e3b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f874cc33545840d4a68b082858285aa9824f61743db170c38fa82a7b208ed646028be1750069f4a77a38707c306d54ebd52c191fd6b0f9a79d8f7c01beb9bbc5
|
|
7
|
+
data.tar.gz: 8b6d3e75a0e01167d9a83950b0d481abbf2267e3491283cdb82f84137594d441b971c1dab46c7182addd9c8a1fa87fc2482ddc95749f5c0e90e03e10d460fdde
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# An SSH transport whose token another process can revoke by minting a new one. A command refused before
|
|
2
|
+
# it printed anything is tried once more with the store's current token.
|
|
3
|
+
class Sandbox::Provider::Daytona::Link
|
|
4
|
+
RETRY = [ *Sandbox::Adapter::Ssh::CONNECTION_ERRORS, Net::SSH::AuthenticationFailed ].freeze
|
|
5
|
+
|
|
6
|
+
def initialize(access, host_key: nil, on_host_key: nil)
|
|
7
|
+
@access = access
|
|
8
|
+
@host_key = host_key
|
|
9
|
+
@on_host_key = on_host_key
|
|
10
|
+
@ssh = build(access.call(nil))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def address = @ssh.address
|
|
14
|
+
def host = @ssh.host
|
|
15
|
+
def port = @ssh.port
|
|
16
|
+
def user = @ssh.user
|
|
17
|
+
def key = @ssh.key
|
|
18
|
+
def connection_errors = Sandbox::Adapter::Ssh::CONNECTION_ERRORS
|
|
19
|
+
def reattaches? = true
|
|
20
|
+
|
|
21
|
+
def exec(command, &block)
|
|
22
|
+
printed = false
|
|
23
|
+
begin
|
|
24
|
+
@ssh.exec(command) do |line|
|
|
25
|
+
printed = true
|
|
26
|
+
block&.call(line)
|
|
27
|
+
end
|
|
28
|
+
rescue *RETRY
|
|
29
|
+
raise if printed
|
|
30
|
+
|
|
31
|
+
refresh
|
|
32
|
+
@ssh.exec(command, &block)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def upload(path, io)
|
|
37
|
+
@ssh.upload(path, io)
|
|
38
|
+
rescue *RETRY
|
|
39
|
+
io.rewind if io.respond_to?(:rewind)
|
|
40
|
+
refresh
|
|
41
|
+
@ssh.upload(path, io)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def download(path)
|
|
45
|
+
@ssh.download(path)
|
|
46
|
+
rescue *RETRY
|
|
47
|
+
refresh
|
|
48
|
+
@ssh.download(path)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def refresh = @ssh = build(@access.call(@ssh.user))
|
|
54
|
+
|
|
55
|
+
def build(access)
|
|
56
|
+
Sandbox::Adapter::Ssh.new(host: access.host, port: access.port, user: access.token, key: nil,
|
|
57
|
+
host_key: @host_key, on_host_key: ->(key) { @host_key = key; @on_host_key&.call(key) })
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -15,9 +15,25 @@ class Sandbox::Provider::Daytona < Sandbox::Adapter::SandboxVm
|
|
|
15
15
|
# An SSH token and where it lands, good until `until`.
|
|
16
16
|
Access = Data.define(:host, :port, :token, :until)
|
|
17
17
|
# One token per sandbox, kept until it nears expiry: minting a new one revokes the previous, so every
|
|
18
|
-
# transport to the same sandbox
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
# transport to the same sandbox shares it, across processes when the store is shared. A fork gets its own.
|
|
19
|
+
# A store answers read(id), write(id, access), delete(id) and synchronize(id) { }.
|
|
20
|
+
class Tokens
|
|
21
|
+
def initialize
|
|
22
|
+
@tokens = {}
|
|
23
|
+
@lock = Monitor.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def read(id) = @tokens[id]
|
|
27
|
+
def write(id, access) = @tokens[id] = access
|
|
28
|
+
def delete(id) = @tokens.delete(id)
|
|
29
|
+
def synchronize(_id, &) = @lock.synchronize(&)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class << self
|
|
33
|
+
attr_writer :tokens
|
|
34
|
+
|
|
35
|
+
def tokens = @tokens ||= Tokens.new
|
|
36
|
+
end
|
|
21
37
|
|
|
22
38
|
def initialize(token, client: Client.new(token), **)
|
|
23
39
|
super(token, **)
|
|
@@ -150,7 +166,7 @@ to: Time.current.utc.iso8601 })
|
|
|
150
166
|
|
|
151
167
|
# A parent with live forks cannot go: the error says so.
|
|
152
168
|
def destroy(m)
|
|
153
|
-
|
|
169
|
+
self.class.tokens.synchronize(m.id) { self.class.tokens.delete(m.id) }
|
|
154
170
|
@client.delete("/sandbox/#{m.id}", force: true)
|
|
155
171
|
rescue Error => e
|
|
156
172
|
raise unless e.status == 404
|
|
@@ -165,19 +181,18 @@ to: Time.current.utc.iso8601 })
|
|
|
165
181
|
end
|
|
166
182
|
|
|
167
183
|
def transport(m, key: nil, host_key: nil, on_host_key: nil)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
184
|
+
Link.new(-> (stale) { access(m.id, stale:) }, host_key:, on_host_key:)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# The sandbox's token from the store, minted when there is none, it nears expiry, or it is `stale`: the
|
|
188
|
+
# one a refused connection used. Another process may have replaced it already; then that one is kept.
|
|
189
|
+
def access(id, stale: nil)
|
|
190
|
+
tokens = self.class.tokens
|
|
191
|
+
tokens.synchronize(id) do
|
|
192
|
+
kept = tokens.read(id)
|
|
193
|
+
kept = nil if kept.nil? || kept.until < Time.current || kept.token == stale
|
|
194
|
+
kept || mint(id).tap { |minted| tokens.write(id, minted) }
|
|
172
195
|
end
|
|
173
|
-
Sandbox::Adapter::Ssh.new(
|
|
174
|
-
host: access.host,
|
|
175
|
-
port: access.port,
|
|
176
|
-
user: access.token,
|
|
177
|
-
key: nil,
|
|
178
|
-
host_key:,
|
|
179
|
-
on_host_key:
|
|
180
|
-
)
|
|
181
196
|
end
|
|
182
197
|
|
|
183
198
|
# Their preview link for the port: a host at their edge and a token it wants in a header. The token rotates
|
data/lib/sandbox-provider.rb
CHANGED
|
@@ -12,6 +12,7 @@ require_relative "sandbox/provider/hetzner"
|
|
|
12
12
|
require_relative "sandbox/provider/hetzner/client"
|
|
13
13
|
require_relative "sandbox/provider/daytona"
|
|
14
14
|
require_relative "sandbox/provider/daytona/client"
|
|
15
|
+
require_relative "sandbox/provider/daytona/link"
|
|
15
16
|
require_relative "sandbox/provider/e2b"
|
|
16
17
|
require_relative "sandbox/provider/e2b/client"
|
|
17
18
|
require_relative "sandbox/provider/e2b/envd"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sandbox-provider
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- nvoi
|
|
@@ -52,6 +52,7 @@ files:
|
|
|
52
52
|
- lib/sandbox/provider/cloud_init.rb
|
|
53
53
|
- lib/sandbox/provider/daytona.rb
|
|
54
54
|
- lib/sandbox/provider/daytona/client.rb
|
|
55
|
+
- lib/sandbox/provider/daytona/link.rb
|
|
55
56
|
- lib/sandbox/provider/e2b.rb
|
|
56
57
|
- lib/sandbox/provider/e2b/client.rb
|
|
57
58
|
- lib/sandbox/provider/e2b/envd.rb
|