nightona 0.191.0
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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +22 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE +190 -0
- data/README.md +184 -0
- data/Rakefile +12 -0
- data/lib/nightona/code_interpreter.rb +359 -0
- data/lib/nightona/common/charts.rb +124 -0
- data/lib/nightona/common/code_interpreter.rb +56 -0
- data/lib/nightona/common/code_language.rb +14 -0
- data/lib/nightona/common/file_system.rb +26 -0
- data/lib/nightona/common/git.rb +19 -0
- data/lib/nightona/common/image.rb +500 -0
- data/lib/nightona/common/nightona.rb +230 -0
- data/lib/nightona/common/process.rb +149 -0
- data/lib/nightona/common/pty.rb +309 -0
- data/lib/nightona/common/resources.rb +39 -0
- data/lib/nightona/common/response.rb +83 -0
- data/lib/nightona/common/snapshot.rb +124 -0
- data/lib/nightona/computer_use.rb +919 -0
- data/lib/nightona/config.rb +116 -0
- data/lib/nightona/file_system.rb +451 -0
- data/lib/nightona/file_transfer.rb +383 -0
- data/lib/nightona/git.rb +334 -0
- data/lib/nightona/lsp_server.rb +139 -0
- data/lib/nightona/nightona.rb +336 -0
- data/lib/nightona/object_storage.rb +172 -0
- data/lib/nightona/otel.rb +183 -0
- data/lib/nightona/process.rb +550 -0
- data/lib/nightona/sandbox.rb +751 -0
- data/lib/nightona/sdk/version.rb +10 -0
- data/lib/nightona/sdk.rb +56 -0
- data/lib/nightona/snapshot_service.rb +238 -0
- data/lib/nightona/util.rb +80 -0
- data/lib/nightona/volume.rb +46 -0
- data/lib/nightona/volume_service.rb +61 -0
- data/lib/nightona.rb +10 -0
- data/project.json +100 -0
- data/scripts/generate-docs.rb +402 -0
- data/sig/nightona/sdk.rbs +6 -0
- metadata +242 -0
data/lib/nightona/sdk.rb
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Copyright Daytona Platforms Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
require 'logger'
|
|
7
|
+
|
|
8
|
+
require 'nightona_api_client'
|
|
9
|
+
require 'nightona_toolbox_api_client'
|
|
10
|
+
require 'toml'
|
|
11
|
+
require 'websocket-client-simple'
|
|
12
|
+
|
|
13
|
+
require_relative 'sdk/version'
|
|
14
|
+
require_relative 'config'
|
|
15
|
+
require_relative 'otel'
|
|
16
|
+
require_relative 'common/charts'
|
|
17
|
+
require_relative 'common/code_interpreter'
|
|
18
|
+
require_relative 'common/code_language'
|
|
19
|
+
require_relative 'common/nightona'
|
|
20
|
+
require_relative 'common/file_system'
|
|
21
|
+
require_relative 'common/image'
|
|
22
|
+
require_relative 'common/git'
|
|
23
|
+
require_relative 'common/process'
|
|
24
|
+
require_relative 'common/pty'
|
|
25
|
+
require_relative 'common/resources'
|
|
26
|
+
require_relative 'common/response'
|
|
27
|
+
require_relative 'common/snapshot'
|
|
28
|
+
require_relative 'code_interpreter'
|
|
29
|
+
require_relative 'computer_use'
|
|
30
|
+
require_relative 'nightona'
|
|
31
|
+
require_relative 'file_system'
|
|
32
|
+
require_relative 'git'
|
|
33
|
+
require_relative 'lsp_server'
|
|
34
|
+
require_relative 'object_storage'
|
|
35
|
+
require_relative 'sandbox'
|
|
36
|
+
require_relative 'snapshot_service'
|
|
37
|
+
require_relative 'util'
|
|
38
|
+
require_relative 'volume'
|
|
39
|
+
require_relative 'volume_service'
|
|
40
|
+
require_relative 'process'
|
|
41
|
+
|
|
42
|
+
module Nightona
|
|
43
|
+
module Sdk
|
|
44
|
+
class Error < StandardError; end
|
|
45
|
+
class TimeoutError < Error; end
|
|
46
|
+
class AuthenticationError < Error; end
|
|
47
|
+
class ForbiddenError < Error; end
|
|
48
|
+
class NotFoundError < Error; end
|
|
49
|
+
class ConflictError < Error; end
|
|
50
|
+
class ValidationError < Error; end
|
|
51
|
+
class RateLimitError < Error; end
|
|
52
|
+
class ServerError < Error; end
|
|
53
|
+
|
|
54
|
+
def self.logger = @logger ||= Logger.new($stdout, level: Logger::INFO)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Copyright Daytona Platforms Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
require 'uri'
|
|
7
|
+
|
|
8
|
+
module Nightona
|
|
9
|
+
class SnapshotService
|
|
10
|
+
include Instrumentation
|
|
11
|
+
|
|
12
|
+
SNAPSHOTS_FETCH_LIMIT = 200
|
|
13
|
+
|
|
14
|
+
# @param snapshots_api [NightonaApiClient::SnapshotsApi] The snapshots API client
|
|
15
|
+
# @param object_storage_api [NightonaApiClient::ObjectStorageApi] The object storage API client
|
|
16
|
+
# @param default_region_id [String, nil] Default region ID for snapshot creation
|
|
17
|
+
# @param otel_state [Nightona::OtelState, nil]
|
|
18
|
+
def initialize(snapshots_api:, object_storage_api:, default_region_id: nil, otel_state: nil)
|
|
19
|
+
@snapshots_api = snapshots_api
|
|
20
|
+
@object_storage_api = object_storage_api
|
|
21
|
+
@default_region_id = default_region_id
|
|
22
|
+
@otel_state = otel_state
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# List all Snapshots.
|
|
26
|
+
#
|
|
27
|
+
# @param page [Integer, Nil]
|
|
28
|
+
# @param limit [Integer, Nil]
|
|
29
|
+
# @return [Nightona::PaginatedResource] Paginated list of all Snapshots
|
|
30
|
+
# @raise [Nightona::Sdk::Error]
|
|
31
|
+
#
|
|
32
|
+
# @example
|
|
33
|
+
# nightona = Nightona::Nightona.new
|
|
34
|
+
# response = nightona.snapshot.list(page: 1, limit: 10)
|
|
35
|
+
# snapshots.items.each { |snapshot| puts "#{snapshot.name} (#{snapshot.image_name})" }
|
|
36
|
+
def list(page: nil, limit: nil)
|
|
37
|
+
raise Sdk::Error, 'page must be positive integer' if page && page < 1
|
|
38
|
+
|
|
39
|
+
raise Sdk::Error, 'limit must be positive integer' if limit && limit < 1
|
|
40
|
+
|
|
41
|
+
response = snapshots_api.get_all_snapshots(page:, limit:)
|
|
42
|
+
PaginatedResource.new(
|
|
43
|
+
total: response.total,
|
|
44
|
+
page: response.page,
|
|
45
|
+
total_pages: response.total_pages,
|
|
46
|
+
items: response.items.map { |snapshot_dto| Snapshot.from_dto(snapshot_dto) }
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Delete a Snapshot.
|
|
51
|
+
#
|
|
52
|
+
# @param snapshot [Nightona::Snapshot] Snapshot to delete
|
|
53
|
+
# @return [void]
|
|
54
|
+
#
|
|
55
|
+
# @example
|
|
56
|
+
# nightona = Nightona::Nightona.new
|
|
57
|
+
# snapshot = nightona.snapshot.get("demo")
|
|
58
|
+
# nightona.snapshot.delete(snapshot)
|
|
59
|
+
# puts "Snapshot deleted"
|
|
60
|
+
def delete(snapshot) = snapshots_api.remove_snapshot(snapshot.id)
|
|
61
|
+
|
|
62
|
+
# Get a Snapshot by name.
|
|
63
|
+
#
|
|
64
|
+
# @param name [String] Name of the Snapshot to get
|
|
65
|
+
# @return [Nightona::Snapshot] The Snapshot object
|
|
66
|
+
#
|
|
67
|
+
# @example
|
|
68
|
+
# nightona = Nightona::Nightona.new
|
|
69
|
+
# snapshot = nightona.snapshot.get("demo")
|
|
70
|
+
# puts "#{snapshot.name} (#{snapshot.image_name})"
|
|
71
|
+
def get(name) = Snapshot.from_dto(snapshots_api.get_snapshot(name))
|
|
72
|
+
|
|
73
|
+
# Creates and registers a new snapshot from the given Image definition.
|
|
74
|
+
#
|
|
75
|
+
# @param params [Nightona::CreateSnapshotParams] Parameters for snapshot creation
|
|
76
|
+
# @param on_logs [Proc, Nil] Callback proc handling snapshot creation logs
|
|
77
|
+
# @return [Nightona::Snapshot] The created snapshot
|
|
78
|
+
#
|
|
79
|
+
# @example
|
|
80
|
+
# image = Image.debianSlim('3.12').pipInstall('numpy')
|
|
81
|
+
# params = CreateSnapshotParams.new(name: 'my-snapshot', image: image)
|
|
82
|
+
# snapshot = nightona.snapshot.create(params) do |chunk|
|
|
83
|
+
# print chunk
|
|
84
|
+
# end
|
|
85
|
+
def create(params, on_logs: nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
86
|
+
create_snapshot_req = NightonaApiClient::CreateSnapshot.new(name: params.name)
|
|
87
|
+
|
|
88
|
+
if params.image.is_a?(String)
|
|
89
|
+
create_snapshot_req.image_name = params.image
|
|
90
|
+
create_snapshot_req.entrypoint = params.entrypoint
|
|
91
|
+
else
|
|
92
|
+
create_snapshot_req.build_info = NightonaApiClient::CreateBuildInfo.new(
|
|
93
|
+
context_hashes: self.class.process_image_context(object_storage_api, params.image),
|
|
94
|
+
dockerfile_content: if params.entrypoint
|
|
95
|
+
params.image.entrypoint(params.entrypoint).dockerfile
|
|
96
|
+
else
|
|
97
|
+
params.image.dockerfile
|
|
98
|
+
end
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
if params.resources
|
|
103
|
+
create_snapshot_req.cpu = params.resources.cpu
|
|
104
|
+
create_snapshot_req.gpu = params.resources.gpu
|
|
105
|
+
if params.resources.gpu_type
|
|
106
|
+
create_snapshot_req.gpu_type =
|
|
107
|
+
params.resources.gpu_type.is_a?(Array) ? params.resources.gpu_type : [params.resources.gpu_type]
|
|
108
|
+
end
|
|
109
|
+
create_snapshot_req.memory = params.resources.memory
|
|
110
|
+
create_snapshot_req.disk = params.resources.disk
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
create_snapshot_req.region_id = params.region_id || @default_region_id
|
|
114
|
+
create_snapshot_req.sandbox_class = params.sandbox_class
|
|
115
|
+
|
|
116
|
+
snapshot = snapshots_api.create_snapshot(create_snapshot_req)
|
|
117
|
+
|
|
118
|
+
# Always wait for snapshot to be ready, regardless of on_logs
|
|
119
|
+
snapshot = wait_for_snapshot(snapshot, on_logs:)
|
|
120
|
+
|
|
121
|
+
if [NightonaApiClient::SnapshotState::ERROR, NightonaApiClient::SnapshotState::BUILD_FAILED].include?(snapshot.state)
|
|
122
|
+
raise Sdk::Error, "Failed to create snapshot #{snapshot.name}, reason: #{snapshot.error_reason}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
Snapshot.from_dto(snapshot)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Activate a snapshot
|
|
129
|
+
#
|
|
130
|
+
# @param snapshot [Nightona::Snapshot] The snapshot instance
|
|
131
|
+
# @return [Nightona::Snapshot]
|
|
132
|
+
def activate(snapshot) = Snapshot.from_dto(snapshots_api.activate_snapshot(snapshot.id))
|
|
133
|
+
|
|
134
|
+
instrument :list, :delete, :get, :create, :activate, component: 'SnapshotService'
|
|
135
|
+
|
|
136
|
+
# Processes the image context by uploading it to object storage
|
|
137
|
+
#
|
|
138
|
+
# @param image [Nightona::Image] The Image instance
|
|
139
|
+
# @return [Array<String>] List of context hashes stored in object storage
|
|
140
|
+
def self.process_image_context(object_storage_api, image) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
141
|
+
return [] unless image.context_list && !image.context_list.empty?
|
|
142
|
+
|
|
143
|
+
push_access_creds = object_storage_api.get_push_access
|
|
144
|
+
|
|
145
|
+
object_storage = ObjectStorage.new(
|
|
146
|
+
endpoint_url: push_access_creds.storage_url,
|
|
147
|
+
aws_access_key_id: push_access_creds.access_key,
|
|
148
|
+
aws_secret_access_key: push_access_creds.secret,
|
|
149
|
+
aws_session_token: push_access_creds.session_token,
|
|
150
|
+
bucket_name: push_access_creds.bucket
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
image.context_list.map do |context|
|
|
154
|
+
object_storage.upload(
|
|
155
|
+
context.source_path,
|
|
156
|
+
push_access_creds.organization_id,
|
|
157
|
+
context.archive_path
|
|
158
|
+
)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
private
|
|
163
|
+
|
|
164
|
+
# @return [NightonaApiClient::SnapshotsApi] The snapshots API client
|
|
165
|
+
attr_reader :snapshots_api
|
|
166
|
+
|
|
167
|
+
# @return [NightonaApiClient::ObjectStorageApi, nil] The object storage API client
|
|
168
|
+
attr_reader :object_storage_api
|
|
169
|
+
|
|
170
|
+
# @return [String, nil] Default region ID for snapshot creation
|
|
171
|
+
attr_reader :default_region_id
|
|
172
|
+
|
|
173
|
+
# @return [Nightona::OtelState, nil]
|
|
174
|
+
attr_reader :otel_state
|
|
175
|
+
|
|
176
|
+
# Wait for snapshot to reach a terminal state (ACTIVE, ERROR, or BUILD_FAILED)
|
|
177
|
+
# Optionally streams logs if on_logs callback is provided
|
|
178
|
+
#
|
|
179
|
+
# @param snapshot [NightonaApiClient::SnapshotDto]
|
|
180
|
+
# @param on_logs [Proc, nil]
|
|
181
|
+
# @return [NightonaApiClient::SnapshotDto]
|
|
182
|
+
def wait_for_snapshot(snapshot, on_logs:) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
183
|
+
terminal_states = [
|
|
184
|
+
NightonaApiClient::SnapshotState::ACTIVE,
|
|
185
|
+
NightonaApiClient::SnapshotState::ERROR,
|
|
186
|
+
NightonaApiClient::SnapshotState::BUILD_FAILED
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
thread = nil
|
|
190
|
+
previous_state = snapshot.state
|
|
191
|
+
|
|
192
|
+
# Log initial state if callback provided
|
|
193
|
+
on_logs&.call("Creating snapshot #{snapshot.name} (#{snapshot.state})")
|
|
194
|
+
|
|
195
|
+
until terminal_states.include?(snapshot.state)
|
|
196
|
+
Sdk.logger.debug("Waiting for snapshot to be created: #{snapshot.state}")
|
|
197
|
+
|
|
198
|
+
# Start log streaming thread if callback provided and snapshot is building
|
|
199
|
+
if on_logs && thread.nil? && snapshot.state != NightonaApiClient::SnapshotState::PENDING
|
|
200
|
+
thread = start_log_streaming(snapshot, on_logs:)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Log state changes if callback provided
|
|
204
|
+
if on_logs && previous_state != snapshot.state
|
|
205
|
+
if snapshot.state != NightonaApiClient::SnapshotState::PENDING && thread.nil?
|
|
206
|
+
thread = start_log_streaming(snapshot, on_logs:)
|
|
207
|
+
end
|
|
208
|
+
on_logs.call("Creating snapshot #{snapshot.name} (#{snapshot.state})")
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
sleep(1)
|
|
212
|
+
previous_state = snapshot.state
|
|
213
|
+
snapshot = snapshots_api.get_snapshot(snapshot.id)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
thread&.join
|
|
217
|
+
|
|
218
|
+
if on_logs && snapshot.state == NightonaApiClient::SnapshotState::ACTIVE
|
|
219
|
+
on_logs.call("Created snapshot #{snapshot.name} (#{snapshot.state})")
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
snapshot
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# @param snapshot [NightonaApiClient::SnapshotDto]
|
|
226
|
+
# @param on_logs [Proc]
|
|
227
|
+
# @return [Thread]
|
|
228
|
+
def start_log_streaming(snapshot, on_logs:)
|
|
229
|
+
# Get build logs URL from API
|
|
230
|
+
build_logs_response = snapshots_api.get_snapshot_build_logs_url(snapshot.id)
|
|
231
|
+
uri = URI.parse("#{build_logs_response.url}?follow=true")
|
|
232
|
+
|
|
233
|
+
headers = {}
|
|
234
|
+
snapshots_api.api_client.update_params_for_auth!(headers, nil, ['bearer'])
|
|
235
|
+
Util.stream_async(uri:, headers:, on_chunk: on_logs)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Copyright Daytona Platforms Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
require 'net/http'
|
|
7
|
+
|
|
8
|
+
module Nightona
|
|
9
|
+
module Util
|
|
10
|
+
STDOUT_PREFIX = "\x01\x01\01"
|
|
11
|
+
private_constant :STDOUT_PREFIX
|
|
12
|
+
|
|
13
|
+
STDERR_PREFIX = "\x02\x02\02"
|
|
14
|
+
private_constant :STDERR_PREFIX
|
|
15
|
+
|
|
16
|
+
PREFIX_LEN = STDOUT_PREFIX.bytesize
|
|
17
|
+
private_constant :PREFIX_LEN
|
|
18
|
+
|
|
19
|
+
def self.demux(line)
|
|
20
|
+
out_parts = []
|
|
21
|
+
err_parts = []
|
|
22
|
+
state = nil
|
|
23
|
+
pos = 0
|
|
24
|
+
|
|
25
|
+
while pos < line.bytesize
|
|
26
|
+
si = line.index(STDOUT_PREFIX, pos)
|
|
27
|
+
ei = line.index(STDERR_PREFIX, pos)
|
|
28
|
+
|
|
29
|
+
if si && (ei.nil? || si < ei)
|
|
30
|
+
next_idx = si
|
|
31
|
+
next_state = :stdout
|
|
32
|
+
elsif ei
|
|
33
|
+
next_idx = ei
|
|
34
|
+
next_state = :stderr
|
|
35
|
+
else
|
|
36
|
+
case state
|
|
37
|
+
when :stdout then out_parts << line[pos..]
|
|
38
|
+
when :stderr then err_parts << line[pos..]
|
|
39
|
+
end
|
|
40
|
+
break
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if pos < next_idx
|
|
44
|
+
chunk = line[pos...next_idx]
|
|
45
|
+
case state
|
|
46
|
+
when :stdout then out_parts << chunk
|
|
47
|
+
when :stderr then err_parts << chunk
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
state = next_state
|
|
52
|
+
pos = next_idx + PREFIX_LEN
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
[out_parts.join, err_parts.join]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @param uri [URI]
|
|
59
|
+
# @param on_chunk [Proc]
|
|
60
|
+
# @param headers [Hash<String, String>]
|
|
61
|
+
# @return [Thread]
|
|
62
|
+
def self.stream_async(uri:, on_chunk:, headers: nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
63
|
+
Sdk.logger.debug("Starting async stream: #{uri}")
|
|
64
|
+
Thread.new do
|
|
65
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
|
66
|
+
request = Net::HTTP::Get.new(uri, headers)
|
|
67
|
+
|
|
68
|
+
http.request(request) do |response|
|
|
69
|
+
response.read_body do |chunk|
|
|
70
|
+
Sdk.logger.debug("Chunked response received: #{chunk.inspect}")
|
|
71
|
+
on_chunk.call(chunk)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
rescue Net::ReadTimeout => e
|
|
76
|
+
Sdk.logger.debug("Async stream (#{uri}) timeout: #{e.inspect}")
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Copyright Daytona Platforms Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
module Nightona
|
|
7
|
+
class Volume
|
|
8
|
+
# @return [String]
|
|
9
|
+
attr_reader :id
|
|
10
|
+
|
|
11
|
+
# @return [String]
|
|
12
|
+
attr_reader :name
|
|
13
|
+
|
|
14
|
+
# @return [String]
|
|
15
|
+
attr_reader :organization_id
|
|
16
|
+
|
|
17
|
+
# @return [String]
|
|
18
|
+
attr_reader :state
|
|
19
|
+
|
|
20
|
+
# @return [String]
|
|
21
|
+
attr_reader :created_at
|
|
22
|
+
|
|
23
|
+
# @return [String]
|
|
24
|
+
attr_reader :updated_at
|
|
25
|
+
|
|
26
|
+
# @return [String]
|
|
27
|
+
attr_reader :last_used_at
|
|
28
|
+
|
|
29
|
+
# @return [String, nil]
|
|
30
|
+
attr_reader :error_reason
|
|
31
|
+
|
|
32
|
+
# Initialize volume from DTO
|
|
33
|
+
#
|
|
34
|
+
# @param volume_dto [NightonaApiClient::SandboxVolume]
|
|
35
|
+
def initialize(volume_dto)
|
|
36
|
+
@id = volume_dto.id
|
|
37
|
+
@name = volume_dto.name
|
|
38
|
+
@organization_id = volume_dto.organization_id
|
|
39
|
+
@state = volume_dto.state
|
|
40
|
+
@created_at = volume_dto.created_at
|
|
41
|
+
@updated_at = volume_dto.updated_at
|
|
42
|
+
@last_used_at = volume_dto.last_used_at
|
|
43
|
+
@error_reason = volume_dto.error_reason
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Copyright Daytona Platforms Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
module Nightona
|
|
7
|
+
class VolumeService
|
|
8
|
+
include Instrumentation
|
|
9
|
+
|
|
10
|
+
# Service for managing Nightona Volumes. Can be used to list, get, create and delete Volumes.
|
|
11
|
+
#
|
|
12
|
+
# @param volumes_api [NightonaApiClient::VolumesApi]
|
|
13
|
+
# @param otel_state [Nightona::OtelState, nil]
|
|
14
|
+
def initialize(volumes_api, otel_state: nil)
|
|
15
|
+
@volumes_api = volumes_api
|
|
16
|
+
@otel_state = otel_state
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Create new Volume.
|
|
20
|
+
#
|
|
21
|
+
# @param name [String]
|
|
22
|
+
# @return [Nightona::Volume]
|
|
23
|
+
def create(name) = Volume.new(volumes_api.create_volume(NightonaApiClient::CreateVolume.new(name:)))
|
|
24
|
+
|
|
25
|
+
# Delete a Volume.
|
|
26
|
+
#
|
|
27
|
+
# @param volume [Nightona::Volume]
|
|
28
|
+
# @return [void]
|
|
29
|
+
def delete(volume) = volumes_api.delete_volume(volume.id)
|
|
30
|
+
|
|
31
|
+
# Get a Volume by name.
|
|
32
|
+
#
|
|
33
|
+
# @param name [String]
|
|
34
|
+
# @param create [Boolean]
|
|
35
|
+
# @return [Nightona::Volume]
|
|
36
|
+
def get(name, create: false)
|
|
37
|
+
Volume.new(volumes_api.get_volume_by_name(name))
|
|
38
|
+
rescue NightonaApiClient::ApiError => e
|
|
39
|
+
raise unless create && e.code == 404 && e.message.include?("Volume with name #{name} not found")
|
|
40
|
+
|
|
41
|
+
create(name)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# List all Volumes.
|
|
45
|
+
#
|
|
46
|
+
# @return [Array<Nightona::Volume>]
|
|
47
|
+
def list
|
|
48
|
+
volumes_api.list_volumes.map { |volume| Volume.new(volume) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
instrument :create, :delete, :get, :list, component: 'VolumeService'
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
# @return [NightonaApiClient::VolumesApi]
|
|
56
|
+
attr_reader :volumes_api
|
|
57
|
+
|
|
58
|
+
# @return [Nightona::OtelState, nil]
|
|
59
|
+
attr_reader :otel_state
|
|
60
|
+
end
|
|
61
|
+
end
|
data/lib/nightona.rb
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Copyright Daytona Platforms Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
# Main entry point for the Nightona Ruby SDK
|
|
7
|
+
# This file provides a convenient way to require the entire SDK with:
|
|
8
|
+
# require 'nightona'
|
|
9
|
+
|
|
10
|
+
require_relative 'nightona/sdk'
|
data/project.json
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sdk-ruby",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"projectType": "library",
|
|
5
|
+
"sourceRoot": "libs/sdk-ruby",
|
|
6
|
+
"tags": [],
|
|
7
|
+
"targets": {
|
|
8
|
+
"build": {
|
|
9
|
+
"executor": "nx:run-commands",
|
|
10
|
+
"options": {
|
|
11
|
+
"cwd": "{projectRoot}",
|
|
12
|
+
"commands": ["rm -f *.gem", "bundle install", "gem build nightona.gemspec"],
|
|
13
|
+
"parallel": false
|
|
14
|
+
},
|
|
15
|
+
"dependsOn": [
|
|
16
|
+
{
|
|
17
|
+
"target": "build",
|
|
18
|
+
"projects": ["api-client-ruby", "toolbox-api-client-ruby"]
|
|
19
|
+
},
|
|
20
|
+
"set-version"
|
|
21
|
+
],
|
|
22
|
+
"outputs": ["{projectRoot}/**/*.gem"]
|
|
23
|
+
},
|
|
24
|
+
"set-version": {
|
|
25
|
+
"executor": "nx:run-commands",
|
|
26
|
+
"options": {
|
|
27
|
+
"cwd": "{projectRoot}",
|
|
28
|
+
"command": "if [ -n \"$RUBYGEMS_PKG_VERSION\" ]; then sed -i \"s/VERSION = '[^']*'/VERSION = '${RUBYGEMS_PKG_VERSION#v}'/\" lib/nightona/sdk/version.rb && echo \"Changed version to $RUBYGEMS_PKG_VERSION\"; else echo \"Using version from version.rb\"; fi"
|
|
29
|
+
},
|
|
30
|
+
"cache": true,
|
|
31
|
+
"inputs": [
|
|
32
|
+
{ "env": "RUBYGEMS_PKG_VERSION" },
|
|
33
|
+
{ "env": "VERSION" }
|
|
34
|
+
],
|
|
35
|
+
"outputs": ["{projectRoot}/lib/nightona/sdk/version.rb"]
|
|
36
|
+
},
|
|
37
|
+
"lint": {
|
|
38
|
+
"executor": "nx:run-commands",
|
|
39
|
+
"options": {
|
|
40
|
+
"cwd": "{projectRoot}",
|
|
41
|
+
"command": "bundle exec rubocop"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"test": {
|
|
45
|
+
"executor": "nx:run-commands",
|
|
46
|
+
"cache": true,
|
|
47
|
+
"inputs": [
|
|
48
|
+
"default",
|
|
49
|
+
"{workspaceRoot}/libs/api-client-ruby/**/*",
|
|
50
|
+
"{workspaceRoot}/libs/toolbox-api-client-ruby/**/*"
|
|
51
|
+
],
|
|
52
|
+
"outputs": [],
|
|
53
|
+
"options": {
|
|
54
|
+
"cwd": "{projectRoot}",
|
|
55
|
+
"command": "bundle exec rspec --format documentation --tag '~e2e'"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"test:e2e": {
|
|
59
|
+
"executor": "nx:run-commands",
|
|
60
|
+
"options": {
|
|
61
|
+
"cwd": "{projectRoot}",
|
|
62
|
+
"command": "bundle exec rspec spec/e2e_spec.rb --format documentation"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"format": {
|
|
66
|
+
"executor": "nx:run-commands",
|
|
67
|
+
"options": {
|
|
68
|
+
"cwd": "{projectRoot}",
|
|
69
|
+
"commands": ["bundle exec rubocop -a --fail-level=E"],
|
|
70
|
+
"parallel": false
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"docs": {
|
|
74
|
+
"executor": "nx:run-commands",
|
|
75
|
+
"outputs": ["{workspaceRoot}/apps/docs/src/content/docs/en/ruby-sdk/**/*"],
|
|
76
|
+
"options": {
|
|
77
|
+
"cwd": "{projectRoot}",
|
|
78
|
+
"command": "bash -O extglob -c 'rm -rf ../../apps/docs/src/content/docs/en/ruby-sdk/!(index.mdx)' && bundle exec ruby scripts/generate-docs.rb"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"publish": {
|
|
82
|
+
"executor": "nx:run-commands",
|
|
83
|
+
"options": {
|
|
84
|
+
"cwd": "{projectRoot}",
|
|
85
|
+
"commands": [
|
|
86
|
+
"mkdir -p ~/.gem && echo \":rubygems: $RUBYGEMS_API_KEY\" > ~/.gem/credentials && chmod 0600 ~/.gem/credentials",
|
|
87
|
+
"gem push nightona-*.gem --key rubygems --host https://rubygems.org"
|
|
88
|
+
],
|
|
89
|
+
"parallel": false
|
|
90
|
+
},
|
|
91
|
+
"dependsOn": [
|
|
92
|
+
{
|
|
93
|
+
"target": "publish",
|
|
94
|
+
"projects": ["api-client-ruby", "toolbox-api-client-ruby"]
|
|
95
|
+
},
|
|
96
|
+
"build"
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|