Skip to content

Commit

Permalink
Auto scripts (#2661)
Browse files Browse the repository at this point in the history
add the auto_scripts smart attribute and go ahead and add cluster config too

This also fixed next_id not working right and form_item_id needs to be a symbol.
  • Loading branch information
johrstrom authored Mar 21, 2023
1 parent b71cc4d commit b83dc55
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 12 deletions.
1 change: 1 addition & 0 deletions apps/dashboard/app/lib/smart_attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module SmartAttributes
require "smart_attributes/attributes/auto_primary_group"
require "smart_attributes/attributes/auto_queues"
require "smart_attributes/attributes/auto_qos"
require "smart_attributes/attributes/auto_scripts"
require "smart_attributes/attributes/bc_account"
require "smart_attributes/attributes/bc_email_on_started"
require "smart_attributes/attributes/bc_num_hours"
Expand Down
51 changes: 51 additions & 0 deletions apps/dashboard/app/lib/smart_attributes/attributes/auto_scripts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

module SmartAttributes
class AttributeFactory

AUTO_SCRIPT_EXTENSIONS = ['sh', 'csh', 'bash', 'slurm', 'sbatch', 'qsub'].freeze

# Build this attribute object. Must specify a valid directory in opts
#
# @param opts [Hash] attribute's options
# @return [Attributes::AutoScripts] the attribute object
def self.build_auto_scripts(opts = {})
dir = Pathname.new(opts[:directory].to_s)
options = script_options_from_directory(dir)

static_opts = {
options: options
}.merge(opts.without(:options).to_h)

Attributes::AutoScripts.new('auto_scripts', static_opts)
end

def self.script_options_from_directory(dir)
return [] unless dir.directory? && dir.readable?

Dir.glob("#{dir}/*.{#{AUTO_SCRIPT_EXTENSIONS.join(',')}}").map do |file|
[File.basename(file), file]
end
end
end

module Attributes
class AutoScripts < Attribute
def widget
'select'
end

def label(*)
(opts[:label] || 'Script').to_s
end

# Submission hash describing how to submit this attribute
# @param fmt [String, nil] formatting of hash
# @return [Hash] submission hash
def submit(*)
content = File.read(value)
{ script: { content: content } }
end
end
end
end
64 changes: 52 additions & 12 deletions apps/dashboard/app/models/script.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@
class Script
include ActiveModel::Model

attr_reader :title

attr_reader :id
attr_reader :title, :id, :project_dir, :smart_attributes

class << self

def scripts_dir(project_dir)
@scripts_dir ||= Pathname.new("#{project_dir}/.ondemand/scripts").tap do |path|
path.mkpath unless path.exist?
Expand Down Expand Up @@ -41,24 +38,42 @@ def next_id(project_dir)
all(project_dir)
.map(&:id)
.map(&:to_i)
.max || 0 + 1
.prepend(0)
.max + 1
end

def batch_clusters
Rails.cache.fetch('script_batch_clusters', expires_in: 4.hours) do
Configuration.job_clusters.reject do |c|
reject_cluster?(c)
end.map(&:id).map(&:to_s)
end
end
end

attr_reader :project_dir, :smart_attributes
def reject_cluster?
c.kubernetes? || c.linux_host? || c.systemd?
end
end

def initialize(opts = {})
opts = opts.to_h.with_indifferent_access

@project_dir = opts[:project_dir] || raise(StandardError, 'You must set the project directory')
@id = opts[:id]
@title = opts[:title].to_s
@smart_attributes = build_smart_attributes(opts[:form] || [])
sm_opts = {
form: opts[:form] || [],
attributes: opts[:attributes] || {}
}
add_cluster_to_form(**sm_opts, clusters: Script.batch_clusters)

@smart_attributes = build_smart_attributes(**sm_opts)
end

def build_smart_attributes(form_list)
form_list.map do |form_item_id|
SmartAttributes::AttributeFactory.build(form_item_id, {})
def build_smart_attributes(form: [], attributes: {})
form.map do |form_item_id|
attrs = attributes[form_item_id.to_sym].to_h.symbolize_keys
SmartAttributes::AttributeFactory.build(form_item_id, attrs)
end
end

Expand All @@ -73,7 +88,7 @@ def to_h
end
end
end
alias_method :inspect, :to_h
alias inspect to_h

# Delegate methods to smart_attributes' getter
#
Expand Down Expand Up @@ -112,4 +127,29 @@ def save
end

private

def add_cluster_to_form(form: [], attributes: {}, clusters: [])
form.prepend('cluster') unless form.include?('cluster')

attributes[:cluster] = if clusters.size > 1
select_clusters(clusters)
else
fixed_cluster(clusters)
end
end

def select_clusters(clusters)
{
widget: 'select',
label: 'Cluster',
options: clusters
}
end

def fixed_cluster(clusters)
{
value: clusters.first.id.to_s,
fixed: true
}
end
end

0 comments on commit b83dc55

Please sign in to comment.