Page Menu
Home
GRNET
Search
Configure Global Search
Log In
Files
F886122
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
Fri, Aug 8, 8:44 PM
Size
12 KB
Mime Type
text/x-diff
Expires
Sun, Aug 10, 8:44 PM (1 d, 3 h)
Engine
blob
Format
Raw Data
Handle
246071
Attached To
rARCHIVING archiving
View Options
diff --git a/app/models/fileset.rb b/app/models/fileset.rb
index 4b31562..0b50436 100644
--- a/app/models/fileset.rb
+++ b/app/models/fileset.rb
@@ -1,131 +1,131 @@
# Fileset model is the application representation of Bacula's Fileset.
# It has references to a host and job templates.
class Fileset < ActiveRecord::Base
establish_connection ARCHIVING_CONF
serialize :exclude_directions, Array
serialize :include_directions, JSON
attr_accessor :include_files
belongs_to :host
has_many :job_templates
validates :name, presence: true, uniqueness: { scope: :host }
validate :has_included_files, on: :create
validates_with NameValidator
before_save :sanitize_exclude_directions, :sanitize_include_directions
DEFAULT_EXCLUDED = %w{/var/lib/bacula /proc /tmp /.journal /.fsck /bacula}
DEFAULT_INCLUDE_OPTIONS = { signature: :SHA1, compression: :GZIP }
DEFAULT_INCLUDE_FILE_LIST = ['/']
# Constructs an array where each element is a line for the Fileset's bacula config
#
# @return [Array]
def to_bacula_config_array
['FileSet {'] +
[" Name = \"#{name_for_config}\""] +
include_directions_to_config_array +
exclude_directions_to_config_array +
['}']
end
# Provides a human readable projection of the fileset
#
# @return [String]
def human_readable
result = "Directories:\n"
result << "\t* " << include_directions['file'].join("\n\t* ")
if exclude_directions.present?
result << "\n\nExcluded:\n"
result << "\t* " << exclude_directions.join("\n\t*")
end
result
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 fileset
#
# @return [ActiveRecord::Relation] the participating hosts
def participating_hosts
Host.joins(:job_templates).where(job_templates: { enabled: true, fileset_id: id }).uniq
end
# Creates a default fileset resource for a simple config
- def default_resource
+ def default_resource(name, time_hex)
@include_files = DEFAULT_INCLUDE_FILE_LIST
- self.name = "default_fileset"
+ self.name = "files_#{name}_#{time_hex}"
self.exclude_directions = DEFAULT_EXCLUDED
save!
self
end
private
def has_included_files
if include_files.blank? || include_files.all?(&:blank?)
errors.add(:include_files, :cant_be_blank)
end
end
def sanitize_include_directions
files = include_files.compact.uniq.keep_if(&:present?)
return false if files.blank?
self.include_directions = { options: DEFAULT_INCLUDE_OPTIONS, file: files }
end
def sanitize_exclude_directions
self.exclude_directions = exclude_directions.keep_if(&:present?).uniq rescue nil
end
def exclude_directions_to_config_array
return [] if exclude_directions.empty?
[' Exclude {'] +
exclude_directions.map { |x| " File = \"#{x}\"" } +
[' }']
end
def include_directions_to_config_array
return [] if include_directions.blank?
[" Include {"] +
included_options +
included_files +
[' }']
end
def included_options
formatted = [" Options {"]
options = include_directions.deep_symbolize_keys[:options].
reverse_merge(DEFAULT_INCLUDE_OPTIONS)
options.each do |k,v|
if not [:wildfile].include? k
formatted << " #{k} = #{v}"
else
formatted << v.map { |f| " #{k} = \"#{f}\"" }
end
end
formatted << " }"
formatted
end
def included_files
include_directions['file'].map { |f| " File = #{f}" }
end
def included_wildfile
include_directions['wildfile'].map { |f| " wildfile = \"#{f}\"" }.join("\n")
end
end
diff --git a/app/models/job_template.rb b/app/models/job_template.rb
index f03f399..38f09b6 100644
--- a/app/models/job_template.rb
+++ b/app/models/job_template.rb
@@ -1,145 +1,145 @@
# JobTemplate class is a helper class that enables us to configure Bacula job
# configurations, without messing with Bacula's native models (Job).
# It has a unique:
#
# * host
# * fileset
# * schedule
class JobTemplate < ActiveRecord::Base
establish_connection ARCHIVING_CONF
enum job_type: { backup: 0, restore: 1, verify: 2, admin: 3 }
belongs_to :host
belongs_to :fileset
belongs_to :schedule
validates :name, :fileset_id, presence: true
validates :schedule_id, presence: true, unless: :restore?
validates :name, uniqueness: { scope: :host }
validates_with NameValidator
before_save :set_job_type
after_save :notify_host
scope :enabled, -> { where(enabled: true) }
# Constructs an array where each element is a line for the Job's bacula config
#
# @return [Array]
def to_bacula_config_array
['Job {'] +
options_array.map { |x| " #{x}" } +
runscript.map { |x| " #{x}" } +
job_settings.map { |k,v| " #{k.capitalize} = #{v}" } +
['}']
end
# Fetches the Job's priority
def priority
job_settings[:priority]
end
# Helper method for the job template's enabled status
def enabled_human
enabled? ? 'yes' : 'no'
end
# Helper method for the job template's schedule name
#
# @return [String] The schedule's name or nothing
def schedule_human
schedule.present? ? schedule.name : '-'
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}"
end
# Sends a hot backup request to Bacula via BaculaHandler
def backup_now
return false if not (enabled? && baculized? && backup?)
host.backup_now(name)
end
# Handles the returned attribues for api
#
# @return [Hash] of the desired attributes for api use
def api_json
{
id: id,
name: name,
fileset: fileset.name_for_config
}
end
# Creates a default job resource for a simple config
- def default_resource
- self.name = "default_backup_job"
+ def default_resource(name, time_hex)
+ self.name = "job_#{name}_#{time_hex}"
save!
self
end
private
def name_format
unless name =~ /^[a-zA-Z0-1\.-_ ]+$/
self.errors.add(:name, :format)
end
end
def notify_host
host.recalculate
end
# Sets the default job_type as backup
def set_job_type
self.job_type = :backup if job_type.nil?
end
def options_array
result = [
"Name = \"#{name_for_config}\"",
"Enabled = #{enabled_human}",
"FileSet = \"#{fileset.name_for_config}\"",
"Client = \"#{host.name}\"",
"Type = \"#{job_type.capitalize}\"",
"Schedule = \"#{schedule.name_for_config}\""
]
if client_before_run_file.present?
result += ["Client Run Before Job = \"#{client_before_run_file}\""]
end
if client_after_run_file.present?
result += ["Client Run After Job = \"#{client_after_run_file}\""]
end
result
end
def runscript
[
'RunScript {',
" command = \"bash #{Archiving.settings[:quota_checker]} \\\"%c\\\" #{host.quota}\"",
' RunsOnClient = no',
' RunsWhen = Before',
'}'
]
end
# Fetches and memoizes the general configuration settings for Jobs
#
# @see ConfigurationSetting.current_job_settings
# @return [Hash] containing the settings
def job_settings
messages = host.email_recipients.any? ? host.message_name : :Standard
@job_settings ||= ConfigurationSetting.current_job_settings.merge(messages: messages)
end
end
diff --git a/app/models/schedule.rb b/app/models/schedule.rb
index 8348edf..0f7a446 100644
--- a/app/models/schedule.rb
+++ b/app/models/schedule.rb
@@ -1,66 +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)
+ def default_resource(time_hex, 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(':','_')}"
+ self.name = "daily_at_#{time.gsub(':','_')}_#{time_hex}"
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/simple_configuration.rb b/app/models/simple_configuration.rb
index 75bca93..c656c41 100644
--- a/app/models/simple_configuration.rb
+++ b/app/models/simple_configuration.rb
@@ -1,51 +1,54 @@
class SimpleConfiguration < ActiveRecord::Base
establish_connection ARCHIVING_CONF
DAYS = {
monday: :mon,
tuesday: :tue,
wednesday: :wed,
thursday: :thu,
friday: :fri,
saturday: :sat,
sunday: :sun
}
enum day: { monday: 0, tuesday: 1, wednesday: 2, thursday: 3, friday: 4, saturday: 5, sunday: 6 }
belongs_to :host
validates :host, :day, :hour, :minute, presence: true
validates :hour, numericality: { greater_than_or_equal: 0, less_then: 24 }
validates :minute, numericality: { greater_than_or_equal: 0, less_then: 60 }
validates_with NameValidator
# Initializes the configuration's 3 parameters randomnly.
# Default configurations must be randomized in order to distribute the backup server's
# load.
def randomize
self.day = SimpleConfiguration.days.keys.sample
self.hour = rand(24)
self.minute = rand(60)
end
# The day abbreviation
#
# @return [Symbol]
def day_short
DAYS[day.to_sym]
end
# Creates a default config, by adding resources for:
#
# * schedule
# * fileset
# * job
#
# Each resource handles its own defaults.
def create_config
- schedule = host.schedules.new.default_resource(day_short, hour, minute)
- fileset = host.filesets.new.default_resource
- job = host.job_templates.new(fileset_id: fileset.id, schedule_id: schedule.id).default_resource
+ time_hex = Digest::MD5.hexdigest(Time.now.to_f.to_s).first(4)
+
+ schedule = host.schedules.new.default_resource(time_hex, day_short, hour, minute)
+ fileset = host.filesets.new.default_resource(name, time_hex)
+ host.job_templates.new(fileset_id: fileset.id, schedule_id: schedule.id).
+ default_resource(name, time_hex)
end
end
Event Timeline
Log In to Comment