diff --git a/app/controllers/jobs_controller.rb b/app/controllers/jobs_controller.rb index c6af6b8..8894b78 100644 --- a/app/controllers/jobs_controller.rb +++ b/app/controllers/jobs_controller.rb @@ -1,67 +1,66 @@ class JobsController < ApplicationController before_action :fetch_host, only: [:new, :edit, :show, :create, :update, :toggle_enable, :backup_now] before_action :fetch_job, only: [:show, :edit, :update, :destroy, :toggle_enable, :backup_now] # GET /jobs def new @job = @host.job_templates.new end # POST /jobs def create @job = @host.job_templates.new(fetch_params) - @restore_location = params[:job_template][:restore_location] - if @restore_location && @job.save_and_create_restore_job(@restore_location) + if @job.save redirect_to host_path(@host) else render :new end end # GET /jobs/1 def show; end # GET /jobs/1/edit def edit;end # PUT /jobs/1 def update if @job.update_attributes(fetch_params) redirect_to host_job_path(@host, @job) else render :edit end end # DELETE /jobs/1 def destroy end # PATCH /hosts/1/jobs/1/enable def toggle_enable @job.enabled = !@job.enabled @job.save redirect_to host_path(@host) end # POST /hosts/1/jobs/1/backup_now def backup_now @job.backup_now redirect_to client_path(@host.client) end private def fetch_job @job = @host.job_templates.find(params[:id]) end def fetch_host @host = current_user.hosts.find(params[:host_id]) end def fetch_params params.require(:job_template).permit(:name, :fileset_id, :schedule_id) end end diff --git a/app/models/job_template.rb b/app/models/job_template.rb index b3460c4..6b7bbfb 100644 --- a/app/models/job_template.rb +++ b/app/models/job_template.rb @@ -1,94 +1,82 @@ class JobTemplate < ActiveRecord::Base establish_connection Baas::settings[:local_db] 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 } before_save :set_job_type after_save :notify_host scope :enabled, -> { where(enabled: true) } # configurable DEFAULT_OPTIONS = { storage: :File, pool: :Default, messages: :Standard, priority: 10, :'Write Bootstrap' => '"/var/lib/bacula/%c.bsr"' } def to_bacula_config_array ['Job {'] + options_array.map { |x| " #{x}" } + DEFAULT_OPTIONS.map { |k,v| " #{k.capitalize} = #{v}" } + ['}'] end def priority DEFAULT_OPTIONS[:priority] end def enabled_human enabled? ? 'yes' : 'no' end def schedule_human schedule.present? ? schedule.name : '-' end 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?) BaculaHandler.new(host).backup_now(name) end - def save_and_create_restore_job(location) - if save_status = save - restore_job = JobTemplate.new( - host: host, job_type: :restore, - fileset: fileset, name: 'Restore ' + name, - restore_location: location - ) - restore_job.save - end - save_status - end - private 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}\"", "FileSet = \"#{fileset.name_for_config}\"", "Client = \"#{host.name}\"", "Type = \"#{job_type.capitalize}\"" ] if restore? result += ["Where = \"#{restore_location}\""] else result += ["Schedule = \"#{schedule.name_for_config}\""] end result end end diff --git a/app/views/jobs/_form.html.erb b/app/views/jobs/_form.html.erb index a07e4b4..c2151fb 100644 --- a/app/views/jobs/_form.html.erb +++ b/app/views/jobs/_form.html.erb @@ -1,27 +1,25 @@ <%= bootstrap_form_for(@job, url: @job.new_record? ? host_jobs_path : host_job_path(@host, @job), layout: :horizontal, label_col: 'col-xs-4', control_col: 'col-xs-6') do |f| %> <%= f.text_field :name %> <%= select_with_errors_and_button( @job, :job_template, :fileset_id, 'Fileset', options_from_collection_for_select(@host.filesets, :id, :name, params[:fileset_id] || @job.fileset_id), new_host_fileset_path(@host, job_id: @job.id)) %> <% if !@job.restore? %> <%= select_with_errors_and_button( @job, :job_template, :schedule_id, 'Schedule', options_from_collection_for_select(@host.schedules, :id, :name, params[:schedule_id] || @job.schedule_id), new_host_schedule_path(@host, job_id: @job.id)) %> <% end %> - <%= f.text_field :restore_location, label: 'Restore Location', placeholder: '/tmp/bacula' %> -
<%= f.submit class: "btn btn-success" %>
<% end %> diff --git a/spec/controllers/jobs_controller_spec.rb b/spec/controllers/jobs_controller_spec.rb index 7632c50..f31fc08 100644 --- a/spec/controllers/jobs_controller_spec.rb +++ b/spec/controllers/jobs_controller_spec.rb @@ -1,76 +1,70 @@ require 'spec_helper' describe JobsController do let!(:host) { FactoryGirl.create(:host) } let(:user) { FactoryGirl.create(:user) } before do host.users << user controller.stub(:current_user) { user } end describe 'GET #new' do before { get :new, host_id: host.id } it 'initializes a job' do expect(assigns(:job)).to be end it 'renders' do expect(response).to render_template(:new) end end describe 'POST #create' do context 'with valid params' do let(:params) do { host_id: host.id, job_template: FactoryGirl.build(:job_template, restore_location: '/foo'). attributes.symbolize_keys.slice(:name, :schedule_id, :fileset_id, :restore_location) } end - it 'creates the jobs (:backup, :restore)' do + it 'creates the backup job' do expect { post :create, params }. - to change { JobTemplate.count }.by(2) + to change { JobTemplate.count }.by(1) end it 'redirects to host' do post :create, params expect(response).to redirect_to(host_path(host)) end - - it 'calls save_and_create_restore_job' do - JobTemplate.any_instance. - should_receive(:save_and_create_restore_job).with('/foo') - post :create, params - end end context 'with invalid params' do let(:params) do { host_id: host.id, job_template: FactoryGirl.build(:job_template).attributes.symbolize_keys. slice(:name, :fileset_id) } end it 'initializes a job with errors' do post :create, params expect(assigns(:job)).to be end it 'does not create the job' do expect { post :create, params }. to_not change { JobTemplate.count } end it 'renders :new' do post :create, params expect(response).to render_template(:new) end end end end diff --git a/spec/models/job_template_spec.rb b/spec/models/job_template_spec.rb index d2019fe..a183b64 100644 --- a/spec/models/job_template_spec.rb +++ b/spec/models/job_template_spec.rb @@ -1,185 +1,156 @@ require 'spec_helper' describe JobTemplate do context 'validates' do it 'name must be present' do expect(JobTemplate.new).to have(1).errors_on(:name) end it 'name must be unique on host\'s scope' do job_1 = FactoryGirl.create(:job_template, name: 'a name') job_2 = FactoryGirl.build(:job_template, name: 'a name') job_3 = FactoryGirl.build(:job_template, name: 'a name', host: job_1.host) expect(job_2).to be_valid expect(job_3).to_not be_valid end it 'fileset_id must be present' do expect(JobTemplate.new).to have(1).errors_on(:fileset_id) end it 'schedule_id must be present' do expect(JobTemplate.new).to have(1).errors_on(:schedule_id) end it 'schedule_id must NOT be present for :restore jobs' do expect(JobTemplate.new(job_type: :restore)).to have(0).errors_on(:schedule_id) end end # automatic assignments context 'when no job_type is given' do let(:job_template) { FactoryGirl.create(:job_template) } it 'sets the job_type to :backup' do expect(job_template).to be_backup end end context 'when enabling a job' do [:pending, :dispatched].each do |status| context "of a #{status} host" do let(:host) { FactoryGirl.create(:host) } let!(:job) { FactoryGirl.create(:job_template, host: host) } before { host.update_column(:status, Host::STATUSES[status]) } it 'becomes configured' do expect { job.enabled = true job.save }.to change { host.reload.human_status_name }.from(status.to_s).to('configured') end end end context 'of a configured host' do let(:host) { FactoryGirl.create(:host) } let!(:job) { FactoryGirl.create(:job_template, host: host) } before { host.update_column(:status, Host::STATUSES[:configured]) } it 'stays configured' do expect { job.enabled = true job.save }.to_not change { host.reload.human_status_name } end end context 'of a updated host' do let(:host) { FactoryGirl.create(:host) } let!(:job) { FactoryGirl.create(:job_template, host: host) } before { host.update_column(:status, Host::STATUSES[:updated]) } it 'stays updated' do expect { job.enabled = true job.save }.to_not change { host.reload.human_status_name } end end [:deployed, :redispatched].each do |status| context "of a #{status} host" do let(:host) { FactoryGirl.create(:host) } let!(:job) { FactoryGirl.create(:job_template, host: host) } before { host.update_column(:status, Host::STATUSES[status]) } it 'becomes updated' do expect { job.enabled = true job.save }.to change { host.reload.human_status_name }.from(status.to_s).to('updated') end end end end describe '#to_bacula_config_array' do let(:job_template) { FactoryGirl.create(:job_template) } subject { job_template.to_bacula_config_array } it 'has a Job structure' do expect(subject.first).to eq('Job {') expect(subject.last).to eq('}') end JobTemplate::DEFAULT_OPTIONS.each do |k, v| it "assigns #{k.capitalize} param" do expect(subject).to include(" #{k.capitalize} = #{v}") end end it 'assigns Name param prefixed with the host\'s name' do expect(subject).to include(" Name = \"#{job_template.name_for_config}\"") end it 'assigns FileSet param' do expect(subject).to include(" FileSet = \"#{job_template.fileset.name_for_config}\"") end it 'assigns Client param' do expect(subject).to include(" Client = \"#{job_template.host.name}\"") end it 'assigns Type param' do expect(subject).to include(" Type = \"#{job_template.job_type.capitalize}\"") end it 'assigns Schedule param' do expect(subject).to include(" Schedule = \"#{job_template.schedule.name_for_config}\"") end context 'for a restore job' do let(:restore_job) { FactoryGirl.create(:job_template, :restore) } subject { restore_job.to_bacula_config_array } it 'does not assign a Schedule param' do expect(subject).to_not include(" Schedule = \"#{restore_job.schedule.name}\"") end it 'assigns Where param' do expect(subject).to include(" Where = \"#{restore_job.restore_location}\"") end end end - - describe '#save_and_create_restore_job' do - let(:host) { FactoryGirl.create(:host) } - let(:backup_job_template) do - FactoryGirl.build(:job_template, job_type: nil, host: host) - end - - it 'calls save' do - backup_job_template.should_receive(:save) - backup_job_template.save_and_create_restore_job('/foo') - end - - it 'creates a restore job for the same host' do - expect { backup_job_template.save_and_create_restore_job('/foo') }. - to change { host.job_templates.restore.count }.by(1) - end - - it 'creates a restore job for fileset' do - backup_job_template.save_and_create_restore_job('/foo') - expect(host.job_templates.restore.pluck(:fileset_id)). - to eq([backup_job_template.fileset_id]) - end - - it 'sets the correct restore location' do - backup_job_template.save_and_create_restore_job('/foo') - expect(host.job_templates.restore.pluck(:restore_location)). - to eq(['/foo']) - end - end end