Commit 03778d5f authored by Florent Didier's avatar Florent Didier
Browse files

Add disk reservations display in status API

We add the disks key as in the following example:

  "nodes": {
    ...
  },
  "disks": {
    sdb.grimoire-1.nancy.grid5000.fr": {
      "diskpath": "/dev/disk/by-path/pci-0000:02:00.0-scsi-0:0:1:0"
      "soft": free/busy (depending if the disk is free or not)
      "reservations": [...] (the jobs which reserved that disk)
    }
  }
parent 78efe5b9
......@@ -26,6 +26,7 @@ class ClustersController < ResourcesController
result = {
"uid" => Time.now.to_i,
"nodes" => OAR::Resource.status(:clusters => params[:id]),
"disks" => OAR::Resource.disk_status(:clusters => params[:id]),
"links" => [
{
"rel" => "self",
......
......@@ -27,6 +27,7 @@ class SitesController < ResourcesController
result = {
"uid" => Time.now.to_i,
"nodes" => OAR::Resource.status(:clusters => valid_clusters),
"disks" => OAR::Resource.disk_status(:clusters => valid_clusters),
"links" => [
{
"rel" => "self",
......
......@@ -85,45 +85,7 @@ module OAR
end
end # .each do |resource_id, resource|
active_jobs_by_moldable_id = {}
Job.expanded.active.
find(:all, :include => [:job_types]).
each{|job|
active_jobs_by_moldable_id[job.moldable_id] = {
:resources => Set.new,
:job => job
}
}
# if there are jobs
if active_jobs_by_moldable_id.length > 0
moldable_ids = active_jobs_by_moldable_id.keys.
map{|moldable_id| "'#{moldable_id}'"}.join(",")
# get all resources assigned to these jobs
%w{assigned_resources gantt_jobs_resources}.each do |table|
self.connection.execute(
QUERY_ASSIGNED_RESOURCES.gsub(
/%TABLE%/, table
).gsub(
/%MOLDABLE_IDS%/, moldable_ids
)
).each do |row|
if row.is_a?(Hash)
moldable_job_id=row["moldable_job_id"]
resource_id=row["resource_id"].to_i
else
(moldable_job_id,resource_id)=row
resource_id=resource_id.to_i
end
active_jobs_by_moldable_id[moldable_job_id][:resources].
add(resource_id)
end # .each do |(moldable_job_id, resource_id)|
end # .each do |table|
end # if active_jobs_by_moldable_id
active_jobs_by_moldable_id.each do |moldable_id, h|
get_active_jobs_by_moldable_id().each do |moldable_id, h|
current = h[:job].running?
# prepare job description now, since it will be added to each resource
......@@ -184,6 +146,47 @@ module OAR
result
end # def status
def get_active_jobs_by_moldable_id()
active_jobs_by_moldable_id = {}
Job.expanded.active.
find(:all, :include => [:job_types]).
each{|job|
active_jobs_by_moldable_id[job.moldable_id] = {
:resources => Set.new,
:job => job
}
}
# if there are jobs
if active_jobs_by_moldable_id.length > 0
moldable_ids = active_jobs_by_moldable_id.keys.
map{|moldable_id| "'#{moldable_id}'"}.join(",")
# get all resources assigned to these jobs
%w{assigned_resources gantt_jobs_resources}.each do |table|
self.connection.execute(
QUERY_ASSIGNED_RESOURCES.gsub(
/%TABLE%/, table
).gsub(
/%MOLDABLE_IDS%/, moldable_ids
)
).each do |row|
if row.is_a?(Hash)
moldable_job_id=row["moldable_job_id"]
resource_id=row["resource_id"].to_i
else
(moldable_job_id,resource_id)=row
resource_id=resource_id.to_i
end
active_jobs_by_moldable_id[moldable_job_id][:resources].
add(resource_id)
end # .each do |(moldable_job_id, resource_id)|
end # .each do |table|
end # if active_jobs_by_moldable_id
active_jobs_by_moldable_id
end
# Returns the initial status hash for a resource.
def initial_status_for(resource)
hard = resource.state
......@@ -199,6 +202,87 @@ module OAR
h[:comment] = resource.comment if resource.respond_to?(:comment)
h
end # def initial_status_for
# Returns the status of all disks, indexed by the disk location.
# So, it returns only one entry per disk.
#
# Returns a hash of the following format:
#
# {
# 'disk.host' => {
# :soft => "free|busy",
# :disk => disk identifier,
# :diskpath => disk path,
# :reservations => [...]
# },
# {...}
# }
#
def disk_status(options = {})
result = {}
resources = Resource.select(
"resource_id, cluster, host, disk, diskpath"
)
# Keep only disks
resources = resources.where(
:type => 'disk'
)
resources = resources.where(
:cluster => options[:clusters]
) unless options[:clusters].blank?
resources = resources.index_by(&:resource_id)
get_active_jobs_by_moldable_id().each do |moldable_id, h|
current = h[:job].running?
# prepare job description now, since it will be added to each resource
# For Result hash table, do not include events
# (otherwise the Set does not work with nested hash)
jobh = h[:job].to_reservation(:without => :events)
h[:resources].each do |resource_id|
resource = resources[resource_id]
# The resource is not a disk or does not belong to a valid cluster.
next if resource.nil?
disk_key = disk_key(resource.disk, resource.host)
result[disk_key] ||= initial_disk_status_for(resource)
if current
result[disk_key][:soft] = 'busy'
else
result[disk_key][:soft] = 'free'
end # if current
result[disk_key][:reservations].add(jobh)
end # .each do |resource_id|
end # .each do |moldable_id, h|
# fallback for resources without jobs
resources.each do |resource_id, resource|
result[disk_key(resource.disk, resource.host)] ||= initial_disk_status_for(resource)
end # .each do |resource_id, resource|
result
end # def disk_status
def disk_key(disk, host)
[disk.split('.').first, host].join('.')
end
# Returns the initial status hash for a disk.
def initial_disk_status_for(resource)
h = {
:soft => "free",
:diskpath => resource.diskpath,
:reservations => Set.new
}
h
end # def initial_disk_status
end # class << self
end # class Resource
......
......@@ -136,4 +136,67 @@ describe OAR::Resource do
end.map{|(node, status)| node}.should == ["paramount-2.rennes.grid5000.fr"]
end
end
it "should return the status of all disks" do
expected_statuses = {
"sdb.parasilo-1.rennes.grid5000.fr" => {
soft: "busy",
diskpath: "/dev/disk/by-path/pci-0000:02:00.0-scsi-0:0:1:0",
reservations: [374198]
},
"sdc.parasilo-1.rennes.grid5000.fr" => {
soft: "busy",
diskpath: "/dev/disk/by-path/pci-0000:02:00.0-scsi-0:0:2:0",
reservations: [374198]
},
"sdb.parasilo-5.rennes.grid5000.fr" => {
soft: "free",
diskpath: "/dev/disk/by-path/pci-0000:02:00.0-scsi-0:0:1:0",
reservations: [374199]
},
"sdc.parasilo-5.rennes.grid5000.fr" => {
soft: "free",
diskpath: "/dev/disk/by-path/pci-0000:02:00.0-scsi-0:0:2:0",
reservations: [374199]
},
"sdb.paradent-9.rennes.grid5000.fr" => {
soft: "free",
diskpath: "/dev/disk/by-path/pci-0000:02:00.0-scsi-0:0:1:0",
reservations: []
},
"sdc.paradent-9.rennes.grid5000.fr" => {
soft: "free",
diskpath: "/dev/disk/by-path/pci-0000:02:00.0-scsi-0:0:2:0",
reservations: []
}
}
OAR::Resource.disk_status.each do |disk, status|
expected_status = expected_statuses[disk]
expected_jobs = expected_status[:reservations].sort
reservations = status[:reservations].map{|r| r[:uid]}.sort
reservations.should == expected_jobs
status[:soft].should == expected_status[:soft]
status[:diskpath].should == expected_status[:diskpath]
end
end
it "should return the status only for the disks belonging to the given clusters" do
OAR::Resource.disk_status(:clusters => ['parasilo']).keys.
map{|n| n.split('.')[1].split("-")[0]}.uniq.sort.should == ['parasilo']
end
it "should return all disks with status busy" do
OAR::Resource.disk_status.select do |disk, status|
status[:soft] == "busy"
end.map{|disk, status| disk}.sort.should == ["sdb.parasilo-1.rennes.grid5000.fr", "sdc.parasilo-1.rennes.grid5000.fr"].sort
end
it "should return all disk reservations with status free" do
OAR::Resource.disk_status.select do |disk, status|
status[:soft] == "free"
end.map{|disk, status| disk}.sort.should == ["sdb.parasilo-5.rennes.grid5000.fr", "sdc.parasilo-5.rennes.grid5000.fr", "sdb.paradent-9.rennes.grid5000.fr", "sdc.paradent-9.rennes.grid5000.fr"].sort
end # it "should return all disks with status free"
end # describe OAR::Resource
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment