Page Menu
Home
GRNET
Search
Configure Global Search
Log In
Files
F887763
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Aug 10, 5:22 AM
Size
6 KB
Mime Type
text/x-diff
Expires
Tue, Aug 12, 5:22 AM (12 h, 44 m)
Engine
blob
Format
Raw Data
Handle
246358
Attached To
rARCHIVING archiving
View Options
diff --git a/app/models/schedule.rb b/app/models/schedule.rb
index 11cb7c9..8348edf 100644
--- a/app/models/schedule.rb
+++ b/app/models/schedule.rb
@@ -1,50 +1,66 @@
# Schedule model is the application representation of Bacula's Schedule.
# It has references to a host and multiple schedule run in order to provide
# the desired Bacula configuration
class Schedule < ActiveRecord::Base
establish_connection ARCHIVING_CONF
has_many :schedule_runs
belongs_to :host
has_many :job_templates
validates :name, presence: true
validates :name, uniqueness: { scope: :host }
validates_with NameValidator
accepts_nested_attributes_for :schedule_runs, allow_destroy: true
# Constructs an array where each element is a line for the Schedule's bacula config
#
# @return [Array]
def to_bacula_config_array
['Schedule {'] +
[" Name = \"#{name_for_config}\""] +
schedule_runs.map {|r| " Run = #{r.schedule_line}" } +
['}']
end
# Provide a human readable projection of the schedule
#
# @return [String]
def human_readable
schedule_runs.map(&:human_readable).join("\n")
end
# Generates a name that will be used for the configuration file.
# It is the name that will be sent to Bacula through the configuration
# files.
#
# @return [String]
def name_for_config
[host.name, name].join(' ')
end
# Returns the hosts that have enabled jobs that use this schedule
#
# @return [ActiveRecord::Colletion] the participating hosts
def participating_hosts
Host.joins(:job_templates).where(job_templates: { enabled: true, schedule_id: id }).uniq
end
+
+ # Creates a default schedule resource for a simple config
+ def default_resource(day, hour, minute)
+ time = [hour, minute].map { |x| x.to_s.rjust(2, '0') }.join(':')
+ full_day = "first #{day}"
+ diff_days = "second-fifth #{day}"
+ inc_days = (SimpleConfiguration::DAYS.values - [day]).join(',')
+
+ self.name = "daily_at_#{time.gsub(':','_')}"
+ save!
+ self.schedule_runs.create(level: :full, time: time, day: full_day)
+ self.schedule_runs.create(level: :differential, time: time, day: diff_days)
+ self.schedule_runs.create(level: :incremental , time: time, day: inc_days)
+
+ self
+ end
end
diff --git a/app/models/schedule_run.rb b/app/models/schedule_run.rb
index 1d65c76..0416838 100644
--- a/app/models/schedule_run.rb
+++ b/app/models/schedule_run.rb
@@ -1,159 +1,164 @@
# ScheduleRun is a helper class that modelizes the run directives of a schedule
# resource.
#
# It can have 3 levels:
#
# * full
# * differential
# * incremental
#
# Each ScheduleRun instance holds info about the execution time of the schedule:
#
# * month specification is optional and is described by:
# - month: full name (eg april) | month name three first letters (eg jul)
# - month_range: month-month
# - monthly: 'monthly'
# * day specification is required and is described by:
# - week_number (optional): weeks number in full text (eg: third, fourth)
# - week_range (optional): week_number-week_number
# - day: first three letters of day (eg: mon, fri)
# - day_range: day-day
# * time specification is required and is described by:
# - 24h time (eg: 03:00)
#
# Schedule Run examples:
#
# Level=Full monthly first mon at 12:21
# Level=Full first sun at 12:34
# Level=Differential second-fifth sat at 15:23
# Level=Incremental mon-sat at 08:00
class ScheduleRun < ActiveRecord::Base
establish_connection ARCHIVING_CONF
enum level: { full: 0, differential: 1, incremental: 2 }
MONTH_KW = %w{jan feb mar apr may jun jul aug sep oct nov dec january february march
april may june july august september october november december}
DAYS = (1..31).to_a
WDAY_KW = %w{mon tue wed thu fri sat sun}
WEEK_KW = %w{first second third fourth fifth}
belongs_to :schedule
validates :day, :time, :level, presence: true
validate :correct_chars
validate :month_valid, if: "month.present?"
validate :time_valid
validate :day_valid
def self.options_for_select
levels.keys.zip levels.keys
end
# Builds a sane default schedule_run
#
# @return [ScheduleRun]
def default_run
self.level = :full
self.day = "first sun"
self.time = '04:00'
end
# Composes the schedule line for the bacula configuration
#
# @return [String]
def schedule_line
[ level_to_config, pool_to_config, month, day, "at #{time}"].join(" ")
end
# Provides a human readable projection of the schedule run
#
# @return [String]
def human_readable
["#{level.capitalize} backup", month, day, "at #{time}"].join(' ')
end
private
def correct_chars
[:month, :day, :time].each do |x|
- if self.send(x) && self.send(x).to_s.gsub(/[0-9a-zA-Z\-:]/, '').present?
+ if self.send(x) && self.send(x).to_s.gsub(/[0-9a-zA-Z\-:,]/, '').present?
self.errors.add(x, 'Invalid characters')
end
end
end
def month_valid
if !month_format? && !valid_month_range?
self.errors.add(:month, 'Invalid month')
end
end
def month_format?
month_regex = "^(#{MONTH_KW.join('|')}|monthly)$"
month.match(month_regex).present?
end
def valid_month_range?
months = month.split('-')
return false if months.length != 2
MONTH_KW.index(months.last) % 12 - MONTH_KW.index(months.first) % 12 > 0
end
def time_valid
if !time.match(/^([01][0-9]|2[0-3]):[0-5][0-9]$/)
self.errors.add(:time, 'Invalid time')
end
end
def day_valid
components = day.split(' ')
if components.length < 1 || components.length > 2
self.errors.add(:day, 'Invalid day')
return false
end
- if !valid_day?(components.last) && !valid_day_range?(components.last)
+ if !valid_day?(components.last) && !valid_day_range?(components.last) &&
+ !valid_day_listing?(components.last)
self.errors.add(:day, 'Invalid day')
return false
end
if components.length == 2 && !valid_week?(components.first) &&
!valid_week_range?(components.first)
self.errors.add(:day, 'Invalid day')
return false
end
true
end
+ def valid_day_listing?(listing)
+ listing.split(',').all? { |d| WDAY_KW.include? d }
+ end
+
def valid_day?(a_day)
WDAY_KW.include? a_day
end
def valid_day_range?(a_range)
days = a_range.split('-')
return false if days.length != 2
WDAY_KW.index(days.last) - WDAY_KW.index(days.first) > 0
end
def valid_week?(a_week)
WEEK_KW.include? a_week
end
def valid_week_range?(a_range)
weeks = a_range.split('-')
return false if weeks.length != 2
WEEK_KW.index(weeks.last) - WEEK_KW.index(weeks.first) > 0
end
def level_to_config
"Level=#{level.capitalize}"
end
def pool_to_config
"Pool=#{ConfigurationSetting.current_pool_settings[level.to_sym]}"
end
end
Event Timeline
Log In to Comment