Class: OodCore::Job::Adapters::Coder::Batch
- Inherits:
-
Object
- Object
- OodCore::Job::Adapters::Coder::Batch
- Defined in:
- lib/ood_core/job/adapters/coder/batch.rb
Overview
Utility class for the Coder adapter to interact with the Coders API.
Defined Under Namespace
Classes: Error
Instance Method Summary collapse
- #api_call(method, endpoint, headers, body = nil) ⇒ Object
- #coder_state_to_ood_status(coder_state) ⇒ Object
- #create_coder_workspace(org_id, project_id, template_version_id, coder_parameters, app_credentials, name) ⇒ Object
- #delete(id) ⇒ Object
- #delete_coder_workspace(id) ⇒ Object
- #end_time(json_data, status) ⇒ Object
- #generate_coder_workspace_name(submitted_name) ⇒ Object
- #get_build_logs(build_id) ⇒ Object
- #get_headers(coder_token) ⇒ Object
- #get_rich_parameters(coder_parameters, project_id, app_credentials) ⇒ Object
- #get_workspace_info(id) ⇒ Object
- #info(id) ⇒ Object
-
#initialize(config, credentials) ⇒ Batch
constructor
A new instance of Batch.
- #parse_error_logs(logs_array) ⇒ Object
- #read_coder_output(latest_build) ⇒ Object
- #start_time(json_data) ⇒ Object
- #submit(script) ⇒ Object
- #username ⇒ Object
- #wait_for_workspace_deletion(id) ⇒ Object
- #wallclock_time(json_data, status) ⇒ Object
- #workspace_status(workspace_info) ⇒ Object
Constructor Details
#initialize(config, credentials) ⇒ Batch
Returns a new instance of Batch.
8 9 10 11 12 13 14 15 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 8 def initialize(config, credentials) @host = config[:host] @token = config[:token] @service_user = config[:service_user] @deletion_max_attempts = config[:deletion_max_attempts] || 5 @deletion_timeout_interval_seconds = config[:deletion_timeout_interval] || 10 @credentials = credentials end |
Instance Method Details
#api_call(method, endpoint, headers, body = nil) ⇒ Object
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 195 def api_call(method, endpoint, headers, body = nil) uri = URI(endpoint) case method.downcase when 'get' request = Net::HTTP::Get.new(uri, headers) when 'post' request = Net::HTTP::Post.new(uri, headers) when 'delete' request = Net::HTTP::Delete.new(uri, headers) else raise ArgumentError, "Invalid HTTP method: #{method}" end request.body = body.to_json if body response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http| http.request(request) end case response when Net::HTTPSuccess JSON.parse(response.body) else raise Error, "HTTP Error: #{response.code} #{response.} for request #{endpoint} and body #{body}" end end |
#coder_state_to_ood_status(coder_state) ⇒ Object
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 151 def coder_state_to_ood_status(coder_state) case coder_state when "starting" "queued" when "failed" "suspended" when "running" "running" when "deleted" "completed" when "stopped" "completed" else "undetermined" end end |
#create_coder_workspace(org_id, project_id, template_version_id, coder_parameters, app_credentials, name) ⇒ Object
60 61 62 63 64 65 66 67 68 69 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 60 def create_coder_workspace(org_id, project_id, template_version_id, coder_parameters, app_credentials, name) endpoint = "#{@host}/api/v2/organizations/#{org_id}/members/#{@service_user}/workspaces" headers = get_headers(@token) body = { template_version_id: template_version_id, name: name, rich_parameter_values: get_rich_parameters(coder_parameters, project_id, app_credentials), } api_call('post', endpoint, headers, body) end |
#delete(id) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 84 def delete(id) delete_coder_workspace(id) credentials = @credentials.load_credentials(id) puts "credentials loaded #{credentials["id"]}" wait_for_workspace_deletion(id) do |attempt| puts "#{Time.now.inspect} Deleting workspace (attempt #{attempt}/#{5})" end workspace_info = get_workspace_info(id) @credentials.destroy_credentials(credentials, workspace_status(workspace_info), id) end |
#delete_coder_workspace(id) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 72 def delete_coder_workspace(id) build_id = get_workspace_info(id)["id"] endpoint = "#{@host}/api/v2/workspaces/#{build_id}/builds" headers = get_headers(@token) body = { 'orphan' => false, 'transition' => 'delete' } api_call('post', endpoint, headers, body) end |
#end_time(json_data, status) ⇒ Object
185 186 187 188 189 190 191 192 193 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 185 def end_time(json_data, status) if status == 'deleted' end_time_string = json_data["latest_build"].dig("updated_at") et = DateTime.parse(end_time_string).to_time.to_i else et = DateTime.now.to_time.to_i end et end |
#generate_coder_workspace_name(submitted_name) ⇒ Object
40 41 42 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 40 def generate_coder_workspace_name(submitted_name) "#{username}-#{submitted_name}-#{rand(2_821_109_907_456).to_s(36)}" end |
#get_build_logs(build_id) ⇒ Object
168 169 170 171 172 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 168 def get_build_logs(build_id) endpoint = "#{@host}/api/v2/workspacebuilds/#{build_id}/logs" headers = get_headers(@token) api_call('get', endpoint, headers) end |
#get_headers(coder_token) ⇒ Object
32 33 34 35 36 37 38 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 32 def get_headers(coder_token) { 'Content-Type' => 'application/json', 'Accept' => 'application/json', 'Coder-Session-Token' => coder_token } end |
#get_rich_parameters(coder_parameters, project_id, app_credentials) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 17 def get_rich_parameters(coder_parameters, project_id, app_credentials) rich_parameter_values = [ { name: "application_credential_name", value: app_credentials[:name] }, { name: "application_credential_id", value: app_credentials[:id] }, { name: "application_credential_secret", value: app_credentials[:secret] }, {name: "project_id", value: project_id } ] if coder_parameters coder_parameters.each do |key, value| rich_parameter_values << { name: key, value: value.to_s} end end rich_parameter_values end |
#get_workspace_info(id) ⇒ Object
117 118 119 120 121 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 117 def get_workspace_info(id) endpoint = "#{@host}/api/v2/users/#{@service_user}/workspace/#{id}?include_deleted=true" headers = get_headers(@token) api_call('get', endpoint, headers) end |
#info(id) ⇒ Object
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 130 def info(id) workspace_info = get_workspace_info(id) latest_build = workspace_info.dig("latest_build") coder_status = workspace_status(workspace_info) || latest_build.dig("job", "status") ood_status = coder_state_to_ood_status(coder_status) coder_output_hash = read_coder_output(latest_build) build_logs = get_build_logs(latest_build.dig("id")) error_logs = parse_error_logs(build_logs) OodCore::Job::Adapters::Coder::CoderJobInfo.new(**{ id: workspace_info["id"], job_name: workspace_info["workspace_name"], status: OodCore::Job::Status.new(state: ood_status), job_owner: workspace_info["workspace_owner_name"], submission_time: workspace_info["created_at"], dispatch_time: workspace_info.dig("updated_at"), wallclock_time: wallclock_time(workspace_info, ood_status), ood_connection_info: { host: coder_output_hash[:floating_ip], port: 80, error_logs: error_logs}, native: coder_output_hash }) end |
#parse_error_logs(logs_array) ⇒ Object
110 111 112 113 114 115 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 110 def parse_error_logs(logs_array) logs_array .reject { |n| n["output"].to_s.empty?} .map { |n| n["output"].scan(/"message":\s*"([^"]+)"/)[0] } .reject {|n| n.nil?} end |
#read_coder_output(latest_build) ⇒ Object
123 124 125 126 127 128 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 123 def read_coder_output(latest_build) = latest_build.dig("resources") &.find { |resource| resource["name"] == "coder_output" } &.dig("metadata") &.map { || [["key"].to_sym, ["value"]] }&.to_h || {} end |
#start_time(json_data) ⇒ Object
180 181 182 183 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 180 def start_time(json_data) start_time_string = json_data.dig("updated_at") DateTime.parse(start_time_string).to_time.to_i end |
#submit(script) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 43 def submit(script) project_id = script.native[:project_id] app_credentials = @credentials.generate_credentials(project_id) workspace_name = generate_coder_workspace_name(script.native[:workspace_name]) create_coder_workspace( script.native[:org_id], project_id, script.native[:template_version_id], script.native[:coder_parameters], app_credentials, workspace_name) @credentials.save_credentials(workspace_name, app_credentials) workspace_name end |
#username ⇒ Object
220 221 222 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 220 def username @username ||= Etc.getlogin end |
#wait_for_workspace_deletion(id) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 96 def wait_for_workspace_deletion(id) max_attempts = @deletion_max_attempts timeout_interval = @deletion_timeout_interval_seconds max_attempts.times do |attempt| workspace_info = get_workspace_info(id) break unless workspace_info && workspace_status(workspace_info) == "deleting" yield(attempt + 1) sleep(timeout_interval) end end |
#wallclock_time(json_data, status) ⇒ Object
174 175 176 177 178 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 174 def wallclock_time(json_data, status) start_time = start_time(json_data) end_time = end_time(json_data, status) end_time - start_time end |
#workspace_status(workspace_info) ⇒ Object
107 108 109 |
# File 'lib/ood_core/job/adapters/coder/batch.rb', line 107 def workspace_status(workspace_info) workspace_info.dig("latest_build", "status") end |