Class: Lemans::Environments::Daytona
- Inherits:
-
Lemans::Environment
- Object
- Lemans::Environment
- Lemans::Environments::Daytona
- Defined in:
- lib/lemans/environments/daytona.rb,
lib/lemans/environments/daytona/shell.rb,
lib/lemans/environments/daytona/retries.rb,
lib/lemans/environments/daytona/sdk_tweaks.rb,
lib/lemans/environments/daytona/snapshot_store.rb,
lib/lemans/environments/daytona/faraday_transfer.rb
Overview
Daytona sandboxes. Daytona builds images server-side into reusable content-named snapshots and enforces the network policy itself.
Defined Under Namespace
Modules: FaradayTransfer, Retries, SDKTweaks Classes: Shell, SnapshotStore
Constant Summary collapse
- TTL_MINUTES =
120- DEFAULT_BUILD_TIMEOUT =
600- TRANSFER_TIMEOUT =
Workspace tarballs ride uploads/downloads, so transfers get their own budget through the SDK's streaming API instead of the global HTTP cap.
900- CLIENT =
Trials run concurrently, and an unsynchronised memo would build several SDK clients and leak all but one.
Concurrent::Delay.new { ::Daytona::Daytona.new(credentials) }
Constants inherited from Lemans::Environment
Lemans::Environment::DEFAULT_TIMEOUT
Instance Attribute Summary collapse
-
#sandbox ⇒ Object
readonly
Returns the value of attribute sandbox.
Attributes inherited from Lemans::Environment
#build_timeout, #env, #image, #labels, #network, #resources
Class Method Summary collapse
- .client ⇒ Object
-
.credentials ⇒ Object
The CLI stores its key as DAYTONA_TOKEN, the SDK only reads DAYTONA_API_KEY; Config also resolves .env files, so go through it.
Instance Method Summary collapse
- #download(remote_path, local_path) ⇒ Object
- #exec(command, timeout: nil, env: {}) ⇒ Object
-
#initialize(image:, resources:, network:, env: {}, labels: {}, logger: nil, build_timeout: nil) ⇒ Daytona
constructor
A new instance of Daytona.
- #start ⇒ Object
-
#stop ⇒ Object
Deleting is the only cleanup that stops the meter.
- #switch_network_policy!(policy) ⇒ Object
- #upload(local_path, remote_path) ⇒ Object
Methods inherited from Lemans::Environment
Constructor Details
#initialize(image:, resources:, network:, env: {}, labels: {}, logger: nil, build_timeout: nil) ⇒ Daytona
Returns a new instance of Daytona.
44 45 46 47 48 |
# File 'lib/lemans/environments/daytona.rb', line 44 def initialize(image:, resources:, network:, env: {}, labels: {}, logger: nil, build_timeout: nil) super(image:, resources:, network:, env:, labels:, build_timeout: build_timeout || DEFAULT_BUILD_TIMEOUT) @logger = logger end |
Instance Attribute Details
#sandbox ⇒ Object (readonly)
Returns the value of attribute sandbox.
26 27 28 |
# File 'lib/lemans/environments/daytona.rb', line 26 def sandbox @sandbox end |
Class Method Details
.client ⇒ Object
32 |
# File 'lib/lemans/environments/daytona.rb', line 32 def self.client = CLIENT.value! |
.credentials ⇒ Object
The CLI stores its key as DAYTONA_TOKEN, the SDK only reads DAYTONA_API_KEY; Config also resolves .env files, so go through it.
36 37 38 39 40 41 42 |
# File 'lib/lemans/environments/daytona.rb', line 36 def self.credentials config = ::Daytona::Config.new config.api_key ||= config.read_env("DAYTONA_TOKEN") raise ConfigError, "no Daytona credentials: set DAYTONA_API_KEY or DAYTONA_TOKEN" unless config.api_key || config.jwt_token config end |
Instance Method Details
#download(remote_path, local_path) ⇒ Object
77 78 79 80 81 82 83 84 85 |
# File 'lib/lemans/environments/daytona.rb', line 77 def download(remote_path, local_path) local_path = Pathname(local_path) local_path.dirname.mkpath local_path.open("wb") do |file| sandbox.fs.download_file_stream(remote_path.to_s, timeout: TRANSFER_TIMEOUT) { file.write(it) } end rescue *Retries::SDK_ERRORS, SystemCallError => e raise InfrastructureError, "daytona: could not download #{remote_path}: #{e.}" end |
#exec(command, timeout: nil, env: {}) ⇒ Object
61 62 63 64 65 |
# File 'lib/lemans/environments/daytona.rb', line 61 def exec(command, timeout: nil, env: {}) @shell.exec(command, timeout: timeout || DEFAULT_TIMEOUT, env: env) rescue *Retries::SDK_ERRORS => e raise InfrastructureError, "daytona: exec failed: #{e.}" end |
#start ⇒ Object
50 51 52 53 54 55 56 57 58 59 |
# File 'lib/lemans/environments/daytona.rb', line 50 def start @sandbox = client.create(create_params, on_snapshot_create_logs: @logger) @shell = Shell.new(sandbox) self rescue *Retries::SDK_ERRORS => e # A sandbox created but never handed over would bill until its TTL: # the caller's ensure can only stop an environment it received. stop raise InfrastructureError, "daytona: could not start sandbox: #{e.}" end |
#stop ⇒ Object
Deleting is the only cleanup that stops the meter. Never raises: cleanup must not replace an otherwise valid result with an exception.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/lemans/environments/daytona.rb', line 96 def stop return if @sandbox.nil? id = @sandbox.id wait = true begin @sandbox.delete(wait:) @sandbox = nil rescue StandardError => e # VM shutdown: confirming destruction needs threads Ruby no longer # grants, but the bare DELETE needs none — the meter still stops. if e.is_a?(ThreadError) && wait wait = false retry end warn "lemans: sandbox #{id} may still be running — delete failed: #{e.class}: #{e.}" end end |
#switch_network_policy!(policy) ⇒ Object
87 88 89 90 91 92 |
# File 'lib/lemans/environments/daytona.rb', line 87 def switch_network_policy!(policy) sandbox.update_network_settings(**network_kwargs(policy, for_update: true)) @network = policy rescue *Retries::SDK_ERRORS => e raise InfrastructureError, "daytona: could not apply #{policy.mode} policy: #{e.}" end |
#upload(local_path, remote_path) ⇒ Object
67 68 69 70 71 72 73 74 75 |
# File 'lib/lemans/environments/daytona.rb', line 67 def upload(local_path, remote_path) # An open handle, not a path string: the SDK uploads a non-existent # path AS ITS OWN BYTES, so a missing file must die here as ENOENT. Pathname(local_path).open("rb") do |file| sandbox.fs.upload_file_stream(file, remote_path.to_s, timeout: TRANSFER_TIMEOUT) end rescue *Retries::SDK_ERRORS => e raise InfrastructureError, "daytona: could not upload #{local_path}: #{e.}" end |