class OSC::Reservations::Adapters::OSCMoab

This adapter is designed for OSC systems using the Moab scheduler. This adapter requires the parameters torque_name and mrsvctl in the Batch object to work. Only tested on Torque >4.

Public Instance Methods

query_reservation(batch, id) click to toggle source

Queries the batch server for a given reservation. @param batch [Batch] The batch server to query for the reservation. @param id [String] The ID of the reservation. @return [Reservation, nil] @raise [CommandLineError] if a command run from the shell exits with error

# File lib/osc/reservations/adapters/osc_moab.rb, line 20
def query_reservation(batch, id)
  cmd = "#{batch.mrsvctl} --host=#{batch.server} -q #{id} --xml"
  begin
    xml = get_xml(cmd, batch)
  rescue CommandLineError
    return
  end

  r_xml = xml.xpath("//rsv")
  rsv = parse_rsv(r_xml)
  query_nodes(rsv, batch)
  query_node_users(rsv, batch)

  rsv
end
query_reservations(batch) click to toggle source

Queries the batch server for a list of reservations. @param batch [Batch] The batch server to query for the reservation. @return [Array<Reservation>] @raise [CommandLineError] if a command run from the shell exits with error

# File lib/osc/reservations/adapters/osc_moab.rb, line 40
def query_reservations(batch)
  cmd = "#{batch.mrsvctl} --host=#{batch.server} -q ALL --xml"
  xml = get_xml(cmd, batch)
  xml = filter(xml) # filter out "fake" reservations

  rsv_list = []
  xml.xpath("//rsv").each do |r_xml|
    rsv_list << parse_rsv(r_xml)
  end
  query_nodes(rsv_list, batch)
  query_node_users(rsv_list, batch)

  rsv_list
end
submit_reservation(batch, reservation) click to toggle source

Submits a given reservation to the batch server. @param batch [Batch] The batch server to submit the reservation at. @param reservation [Reservation] A reservation with necessary information. @return [Reservation] @raise [CommandLineError] if a command run from the shell exits with error

# File lib/osc/reservations/adapters/osc_moab.rb, line 60
def submit_reservation(batch, reservation)
end

Private Instance Methods

filter(xml) click to toggle source

Filter out unwanted reservations in a query @param xml [Nokogiri::XML::Document] The XML document to filter for this adapter. @return [Nokogiri::XML::Document] The filtered XML document.

# File lib/osc/reservations/adapters/osc_moab.rb, line 134
def filter(xml)
  # Remove running jobs
  xml.xpath("//rsv[@SubType='JobReservation']").remove

  # Remove debug queue from Glenn cluster
  # xml.xpath("//rsv[@SubType='StandingReservation']").remove

  xml
end
get_xml(cmd, batch) click to toggle source

Get reservation list as xml @param cmd [String] Command used in terminal to get XML reservation list. @param batch [Batch] The batch server object to use. @return [Nokogiri::XML::Document] The XML document corresponding to the queried reservation list.

# File lib/osc/reservations/adapters/osc_moab.rb, line 120
def get_xml(cmd, batch)
  Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
    exit_status = wait_thr.value
    unless exit_status.success?
      raise CommandLineError, "Bad exit status for: #{cmd}"
    end

    Nokogiri::XML(stdout.read)
  end
end
parse_rsv(xml) click to toggle source

Parse a reservation from a “rsv” element in XML @param xml [Nokogiri::XML::Element] The XML element corresponding to a reservation. @return [Reservation] The reservation object.

# File lib/osc/reservations/adapters/osc_moab.rb, line 147
def parse_rsv(xml)
  id = xml.xpath("@Name").to_s
  starttime = Time.at(xml.xpath("@starttime").to_s.to_i)
  endtime = Time.at(xml.xpath("@endtime").to_s.to_i)
  auser = xml.xpath("@AUser").to_s
  users = xml.xpath("ACL[@type='USER']/@name").map { |v| v.value }
  nodes = xml.xpath("@AllocNodeList").to_s.split(',')

  Reservation.new(
     id: id,
     starttime: starttime,
     endtime: endtime,
     auser: auser,
     users: users,
     nodes: nodes
  )
end
query_node_users(rsvs, batch) click to toggle source

Query what users are running jobs on the nodes for list of reservations @param rsvs [Array<Reservation>] An array of reservations to check. @param batch [Batch] The batch server object to use.

# File lib/osc/reservations/adapters/osc_moab.rb, line 99
def query_node_users(rsvs, batch)
  # make list of job ids
  jobs = [*rsvs].map{|r| r.nodes.map(&:jobs)}.flatten.uniq

  c = PBS::Conn.batch(batch.torque_name)
  q = PBS::Query.new(conn: c, type: :job)
  job_list = {}
  jobs.each do |j|
    job_list[j] = q.find(id: j)[0][:attribs][:Job_Owner].split('@')[0]
  end

  [*rsvs].each{|r| r.nodes.each{|n| n.users = n.jobs.map{|j| job_list[j]}.uniq}}
end
query_nodes(rsvs, batch) click to toggle source

Query the nodes from the batch server @param rsvs [Array<Reservation>] An array of reservations to check. @param batch [Batch] The batch server object to use. @return [Array<Reservation>] The array of reservations on this batch server.

# File lib/osc/reservations/adapters/osc_moab.rb, line 69
def query_nodes(rsvs, batch)
  # make list of unique nodes for all reservations
  nodes = [*rsvs].map(&:nodes).flatten.uniq

  c = PBS::Conn.batch(batch.torque_name)
  q = PBS::Query.new(conn: c, type: :node)
  node_list = {}
  nodes.each do |n|
    node_hash = q.find(id: n)[0][:attribs]
    np = node_hash[:np].to_i
    props = node_hash[:properties].split(',')
    jobs = node_hash.fetch(:jobs, '').split(',').map{|j| j.split('/')[1]}
    users = []

    node_list[n] = Node.new(
      id: n,
      np: np,
      props: props,
      jobs: jobs,
      users: users
    )
  end

  # replace node lists with lists of Node objects
  [*rsvs].each{|r| r.nodes.map!{|n| node_list[n]}}
end