Page MenuHomeGRNET

No OneTemporary

File Metadata

Created
Wed, Sep 30, 11:48 AM
diff --git a/app/assets/javascripts/filesets.js b/app/assets/javascripts/filesets.js
index 1cf8042..0ffab2e 100644
--- a/app/assets/javascripts/filesets.js
+++ b/app/assets/javascripts/filesets.js
@@ -1,47 +1,47 @@
$(document).ready(function() {
if ($('.include_files-plus-sign').size() > 0) {
$(".include_files-plus-sign").click(function() {
addIncludedFileTextArea();
});
};
if ($('.exclude_directions-plus-sign').size() > 0) {
$(".exclude_directions-plus-sign").click(function() {
addExcludeDirectionsTextArea();
});
};
if ($('.include_files-remove-sign').size() > 0) {
$(".include_files-remove-sign").click(function() {
removeIncludedFileTextArea($(this));
});
};
if ($('.exclude_directions-remove-sign').size() > 0) {
$(".exclude_directions-remove-sign").click(function() {
removeExcludeDirectionsTextArea($(this));
});
};
});
function addIncludedFileTextArea() {
var textArrea = $('.templates .include_files:last').clone(true).val("");
textArrea.insertBefore('.here-included');
if ($('.include_files').size() > 1) {
$('.include_files-remove-sign').show();
};
}
function addExcludeDirectionsTextArea() {
var textArrea = $('.templates .exclude_directions:last').clone(true).val("");
textArrea.insertAfter('.here-excluded');
$('.exclude_directions:last input').val("");
}
function removeIncludedFileTextArea(element) {
element.closest('div.include_files').remove();
- if ($('.include_files').size() <= 1) {
+ if ($('form .include_files').size() <= 1) {
$('.include_files-remove-sign').hide();
};
}
function removeExcludeDirectionsTextArea(element) {
element.closest('div.exclude_directions').remove()
}
diff --git a/app/controllers/filesets_controller.rb b/app/controllers/filesets_controller.rb
index 3cde529..438f879 100644
--- a/app/controllers/filesets_controller.rb
+++ b/app/controllers/filesets_controller.rb
@@ -1,94 +1,94 @@
class FilesetsController < ApplicationController
before_action :require_logged_in
before_action :fetch_host, only: [:new, :create, :show, :edit, :update]
before_action :fetch_job_id, only: [:new, :create, :edit, :update]
before_action :fetch_fileset, only: [:show, :edit, :update]
# GET /hosts/:host_id/filesets/new
def new
@fileset = @host.filesets.new
@fileset.include_directions = { 'file' => [nil] }
@fileset.exclude_directions = ['']
end
# GET /hosts/:host_id/filesets/:id
def show
@fileset = @host.filesets.find(params[:id])
respond_to do |format|
format.js {}
end
end
# GET /hosts/:host_id/filesets/:id/edit
def edit
@fileset.include_files = @fileset.include_directions['file']
- @fileset.exclude_directions ||= ['']
+ @fileset.exclude_directions = [''] if @fileset.exclude_directions.empty?
end
# PATCH /hosts/:host_id/filesets/:id/
def update
fileset_params = fetch_params
if fileset_params[:exclude_directions].nil?
fileset_params[:exclude_directions] = []
end
if @fileset.update(fileset_params)
flash[:success] = 'Fileset updated successfully'
participating_hosts = @fileset.participating_hosts
if participating_hosts.size.nonzero?
participating_hosts.each(&:recalculate)
flash[:alert] = 'You will need to redeploy the afffected clients: ' +
participating_hosts.map(&:name).join(', ')
end
if @job_id
redirect_to edit_host_job_path(@host, @job_id, fileset_id: @fileset.id)
else
redirect_to new_host_job_path(@host, fileset_id: @fileset.id)
end
else
render :edit
end
end
# POST /hosts/:host_id/filesets
def create
@fileset = @host.filesets.new(fetch_params)
if @fileset.save
flash[:success] = 'Fileset created'
if @job_id.present?
redirect_to edit_host_job_path(@host, @job_id, fileset_id: @fileset.id)
else
redirect_to new_host_job_path(@host, fileset_id: @fileset.id)
end
else
@fileset.include_files = nil
@fileset.exclude_directions = ['']
@fileset.include_directions = { 'file' => [nil] }
render :new
end
end
# DELETE /hosts/:host_id/filesets/:id
def destroy
end
private
def fetch_host
@host = current_user.hosts.find(params[:host_id])
end
def fetch_job_id
@job_id = @host.job_templates.find(params[:job_id]).id if params[:job_id].present?
end
def fetch_fileset
@fileset = @host.filesets.find(params[:id])
end
def fetch_params
params.require(:fileset).permit(:name, exclude_directions: [], include_files: [])
end
end
diff --git a/app/models/fileset.rb b/app/models/fileset.rb
index 981b640..659f905 100644
--- a/app/models/fileset.rb
+++ b/app/models/fileset.rb
@@ -1,140 +1,143 @@
# 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(name, time_hex, opts = {})
@include_files = opts[:files].presence || DEFAULT_INCLUDE_FILE_LIST
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?) rescue nil
- return false if files.blank?
+ if files.blank?
+ self.errors[:include_files] << "Include files can't be empty"
+ return false
+ end
files = files.map {|file| Shellwords.escape(file) }
self.include_directions = { options: DEFAULT_INCLUDE_OPTIONS, file: files }
end
def sanitize_exclude_directions
self.exclude_directions =
begin
exclude_directions.keep_if(&:present?).uniq.map do |x|
Shellwords.escape(x)
end
rescue
nil
end
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/views/filesets/_form.html.erb b/app/views/filesets/_form.html.erb
index 78c7f5f..5a28390 100644
--- a/app/views/filesets/_form.html.erb
+++ b/app/views/filesets/_form.html.erb
@@ -1,59 +1,58 @@
<%= bootstrap_form_for(@fileset, url: url, method: method, layout: :horizontal,
label_col: 'col-xs-3', control_col: 'col-xs-8') do |f| %>
<div>
<%= f.text_field :name %>
<% no_remove_sign = @fileset.include_directions['file'].length <= 1 %>
<% @fileset.include_directions['file'].each do |file| %>
<%= text_with_errors_and_remove(
@fileset, :fileset, :include_files, 'Files', '/', file, no_remove_sign) %>
<% end %>
<p class='here-included' />
<div class="form-group">
<div class="col-xs-offset-3 col-xs-1">
- <%= link_to '#', class: 'include_files-plus-sign' do %>
+ <%= link_to '#', class: 'include_files-plus-sign', title: 'New File' do %>
<span class="glyphicon glyphicon-plus text-success"></span>
<% end %>
</div>
</div>
<hr />
<% @fileset.exclude_directions.each do |file| %>
<%= text_with_errors_and_remove(@fileset, :fileset, :exclude_directions, 'Exclude', '/an_exluded_dir', file) %>
<% end %>
<p class='here-excluded' />
<div class="form-group">
<div class="col-xs-offset-3 col-xs-1">
- <%= link_to '#', class: 'exclude_directions-plus-sign' do %>
+ <%= link_to '#', class: 'exclude_directions-plus-sign', title: 'New Excluded File' do %>
<span class="glyphicon glyphicon-plus text-success"></span>
<% end %>
</div>
</div>
<%= (hidden_field_tag :job_id, @job_id) if @job_id%>
</div>
- <div class='templates hidden'>
- <%= text_with_errors_and_remove(@fileset, :fileset, :include_files, 'Files', '/') %>
- <%= text_with_errors_and_remove(@fileset, :fileset, :exclude_directions, 'Exclude',
- '/an_excluded_dir', '') %>
- </div>
-
-
<div class="form-group">
<div class="col-xs-offset-3 col-xs-3">
<%= f.submit class: 'btn btn-success' %>
</div>
<div class="col-xs-3">
<%= link_to 'Cancel',
@job_id.present? ? edit_host_job_path(@host, @job_id) : new_host_job_path(@host),
role: 'button', class: 'btn btn-danger'%>
</div>
</div>
<% end %>
+
+<div class='templates hidden'>
+ <%= text_with_errors_and_remove(@fileset, :fileset, :include_files, 'Files', '/', '') %>
+ <%= text_with_errors_and_remove(@fileset, :fileset, :exclude_directions, 'Exclude',
+ '/an_excluded_dir', '') %>
+</div>

Event Timeline