Module: Supermicro::Jobs

Included in:
Client
Defined in:
lib/supermicro/jobs.rb

Instance Method Summary collapse

Instance Method Details

#cancel_job(job_id) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/supermicro/jobs.rb', line 124

def cancel_job(job_id)
  puts "Cancelling job #{job_id}...".yellow
  
  response = authenticated_request(
    :delete,
    "/redfish/v1/TaskService/Tasks/#{job_id}"
  )
  
  if response.status.between?(200, 299)
    puts "Job cancelled successfully.".green
    return true
  else
    raise Error, "Failed to cancel job: #{response.status} - #{response.body}"
  end
end

#clear_jobs!Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/supermicro/jobs.rb', line 140

def clear_jobs!
  # Note: Supermicro doesn't actually delete tasks - DELETE just marks them as "Killed"
  # The BMC maintains a rolling buffer of tasks (typically ~28-30) with oldest being overwritten
  # This method will "kill" any running tasks but won't remove them from the list
  
  response = authenticated_request(:get, "/redfish/v1/TaskService/Tasks")
  return true unless response.status == 200
  
  data = JSON.parse(response.body)
  members = data["Members"] || []
  
  if members.empty?
    puts "No jobs to clear.".yellow
    return true
  end
  
  # Only try to kill tasks that are actually running
  running_count = 0
  members.each do |member|
    task_id = member["@odata.id"].split('/').last
    task_response = authenticated_request(:get, member["@odata.id"])
    
    if task_response.status == 200
      task = JSON.parse(task_response.body)
      if ["Running", "Starting", "New", "Pending"].include?(task["TaskState"])
        running_count += 1
        puts "Killing task #{task_id}: #{task['Name']} (#{task['TaskState']})".yellow
        authenticated_request(:delete, member["@odata.id"])
      end
    end
  end
  
  if running_count > 0
    puts "Killed #{running_count} running tasks.".green
  else
    puts "No running tasks to kill (#{members.length} completed/killed tasks remain in history).".yellow
  end
  
  true
end

#job_status(job_id) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/supermicro/jobs.rb', line 58

def job_status(job_id)
  response = authenticated_request(:get, "/redfish/v1/TaskService/Tasks/#{job_id}")
  
  if response.status == 200
    begin
      data = JSON.parse(response.body)
      
      {
        "id" => data["Id"],
        "name" => data["Name"],
        "state" => data["TaskState"],
        "status" => data["TaskStatus"],
        "percent_complete" => data["PercentComplete"] || data.dig("Oem", "Supermicro", "PercentComplete"),
        "start_time" => data["StartTime"],
        "end_time" => data["EndTime"],
        "messages" => data["Messages"]
      }
    rescue JSON::ParserError
      raise Error, "Failed to parse job status response: #{response.body}"
    end
  else
    raise Error, "Failed to get job status. Status code: #{response.status}"
  end
end

#jobsObject



8
9
10
11
12
13
14
15
16
17
# File 'lib/supermicro/jobs.rb', line 8

def jobs
  tasks = jobs_detail
  
  # Return summary format consistent with iDRAC
  {
    completed_count: tasks.count { |t| t["state"] == "Completed" },
    incomplete_count: tasks.count { |t| t["state"] != "Completed" },
    total_count: tasks.count
  }
end

#jobs_detailObject



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/supermicro/jobs.rb', line 19

def jobs_detail
  response = authenticated_request(:get, "/redfish/v1/TaskService/Tasks")
  
  if response.status == 200
    begin
      data = JSON.parse(response.body)
      members = data["Members"] || []
      
      # Supermicro doesn't support expand, so fetch each task individually
      tasks = members.map do |member|
        task_id = member["@odata.id"].split('/').last
        task_response = authenticated_request(:get, member["@odata.id"])
        
        if task_response.status == 200
          task = JSON.parse(task_response.body)
          {
            "id" => task["Id"],
            "name" => task["Name"],
            "state" => task["TaskState"],
            "status" => task["TaskStatus"],
            "percent_complete" => task["PercentComplete"],
            "start_time" => task["StartTime"],
            "end_time" => task["EndTime"],
            "messages" => task["Messages"]
          }
        else
          nil
        end
      end.compact
      
      return tasks
    rescue JSON::ParserError
      raise Error, "Failed to parse tasks response"
    end
  else
    []
  end
end

#jobs_summaryObject



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/supermicro/jobs.rb', line 181

def jobs_summary
  all_jobs = jobs_detail
  
  puts "\n=== Jobs Summary ===".green
  
  if all_jobs.empty?
    puts "No jobs found.".yellow
    return all_jobs
  end
  
  by_state = all_jobs.group_by { |j| j["state"] }
  
  by_state.each do |state, state_jobs|
    puts "\n#{state}:".cyan
    state_jobs.each do |job|
      percent = job["percent_complete"] ? " (#{job["percent_complete"]}%)" : ""
      puts "  #{job["name"]} - #{job["status"]}#{percent}".light_cyan
      puts "    ID: #{job["id"]}"
      puts "    Started: #{job["start_time"]}" if job["start_time"]
      puts "    Ended: #{job["end_time"]}" if job["end_time"]
    end
  end
  
  all_jobs
end

#wait_for_job(job_id, timeout: 600) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/supermicro/jobs.rb', line 83

def wait_for_job(job_id, timeout: 600)
  start_time = Time.now
  
  puts "Waiting for job #{job_id} to complete...".yellow
  
  loop do
    if Time.now - start_time > timeout
      raise Error, "Job #{job_id} timed out after #{timeout} seconds"
    end
    
    begin
      status = job_status(job_id)
      
      case status["state"]
      when "Completed", "Killed", "Exception", "Cancelled"
        if status["status"] == "OK" || status["status"] == "Completed"
          puts "Job completed successfully.".green
          return { status: :success, job: status }
        else
          puts "Job failed: #{status["status"]}".red
          return { status: :failed, job: status, error: status["messages"] }
        end
      when "Running", "Starting", "New", "Pending"
        percent = status["percent_complete"]
        if percent
          puts "Job progress: #{percent}%".cyan
        else
          puts "Job is #{status["state"]}...".cyan
        end
        sleep 5
      else
        puts "Unknown job state: #{status["state"]}".yellow
        sleep 5
      end
    rescue => e
      debug "Error checking job status: #{e.message}", 1, :yellow
      sleep 5
    end
  end
end