diff --git a/app/controllers/simple_configs_controller.rb b/app/controllers/simple_configs_controller.rb index 8efb7e7..f0f2d1c 100644 --- a/app/controllers/simple_configs_controller.rb +++ b/app/controllers/simple_configs_controller.rb @@ -1,31 +1,31 @@ class SimpleConfigsController < ApplicationController before_action :require_logged_in before_action :fetch_host # GET /hosts/1/simple_configs/new def new - @simple_config = @host.simple_configurations.new + @simple_config = SimpleConfiguration.new @simple_config.randomize end # POST /hosts/1/simple_configs def create - @simple_config = @host.simple_configurations.new(fetch_config_params) - if @simple_config.save - @simple_config.create_config + @simple_config = SimpleConfiguration.new(fetch_config_params) + + if @simple_config.valid? && @simple_config.create_config(@host) redirect_to host_path(@host, anchor: :jobs) else render :new end end private def fetch_host @host = current_user.hosts.find(params[:host_id]) end def fetch_config_params params.require(:simple_configuration).permit(:name, :day, :hour, :minute, included_files: []) end end diff --git a/app/models/job_template.rb b/app/models/job_template.rb index 586ab86..fb39a0d 100644 --- a/app/models/job_template.rb +++ b/app/models/job_template.rb @@ -1,145 +1,146 @@ # 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(name, time_hex) self.name = "job_#{name}_#{time_hex}" + self.enabled = true 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 = \"#{Shellwords.escape(client_before_run_file)}\""] end if client_after_run_file.present? result += ["Client Run After Job = \"#{Shellwords.escape(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/simple_configuration.rb b/app/models/simple_configuration.rb index af81afa..3d9cc02 100644 --- a/app/models/simple_configuration.rb +++ b/app/models/simple_configuration.rb @@ -1,67 +1,62 @@ -class SimpleConfiguration < ActiveRecord::Base - establish_connection ARCHIVING_CONF +class SimpleConfiguration + include ActiveModel::Model - attr_accessor :included_files + attr_accessor :included_files, :day, :hour, :minute, :name INCLUDED_FILE_OPTIONS = %w{/ /bin /boot /etc /home /lib /media /mnt /opt /root /run /sbin /srv /usr /var} 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 } + DAY_NAMES = %w{monday tuesday wednesday thursday friday saturday sunday } - belongs_to :host - - validates :host, :day, :hour, :minute, presence: true + validates_inclusion_of :day, in: DAY_NAMES + validates :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 - before_save :sanitize_included_files - # 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.day = DAY_NAMES.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 + # + # @param host[Host] the host that will receive the config + def create_config(host) + self.included_files = included_files.keep_if(&:present?).uniq.presence + 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, files: included_files) host.job_templates.new(fileset_id: fileset.id, schedule_id: schedule.id). default_resource(name, time_hex) end - - private - - def sanitize_included_files - self.included_files = included_files.keep_if(&:present?).uniq.presence - end end diff --git a/app/views/simple_configs/new.html.erb b/app/views/simple_configs/new.html.erb index 2998dd1..64cbf13 100644 --- a/app/views/simple_configs/new.html.erb +++ b/app/views/simple_configs/new.html.erb @@ -1,44 +1,44 @@
This the basic Backup configuration.
Your server is going to receive daily backups, on the selected hour and minute.
The backup plan is optimized to have the minimum overhead to your system, while maintaining a high performance restore system.
The most time consuming backups will be on the selected day.
You can specify a set of files you want to backup from a list of preselected Fileset
You can alter this configuration later on according to your specific needs.