mirror of
https://github.com/cliffe/SecGen.git
synced 2026-02-21 11:18:06 +00:00
Merge branch 'auto_grading071220' into auto_grading180621
# Conflicts: # lib/batch/batch_secgen.rb # lib/readers/system_reader.rb # lib/schemas/scenario_schema.xsd # lib/templates/Puppetfile.erb # modules/generators/structured_content/metactf_challenge/secgen_metadata.xml # modules/utilities/unix/ctf/metactf/manifests/configure.pp # modules/utilities/unix/ctf/metactf/manifests/install.pp
This commit is contained in:
82
Gemfile.lock
82
Gemfile.lock
@@ -19,9 +19,9 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (2.3.6)
|
||||
CFPropertyList (3.0.1)
|
||||
PriorityQueue (0.1.2)
|
||||
activesupport (5.2.3)
|
||||
activesupport (5.2.4)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
@@ -34,21 +34,21 @@ GEM
|
||||
concurrent-ruby (1.1.5)
|
||||
credy (0.2.1)
|
||||
thor (~> 0.19.1)
|
||||
deep_merge (1.2.1)
|
||||
digest-simple (1.1.0)
|
||||
digest-siphash (1.0.1)
|
||||
digest-simple
|
||||
digest-whirlpool (1.0.3)
|
||||
duplicate (1.1.1)
|
||||
facter (2.5.1)
|
||||
CFPropertyList (~> 2.2)
|
||||
faker (1.9.3)
|
||||
i18n (>= 0.7)
|
||||
faraday (0.13.1)
|
||||
facter (2.5.6)
|
||||
faker (2.7.0)
|
||||
i18n (>= 1.6, < 1.8)
|
||||
faraday (0.14.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
faraday_middleware (0.12.2)
|
||||
faraday (>= 0.7.4, < 1.0)
|
||||
fast_gettext (1.1.2)
|
||||
ffi (1.11.1)
|
||||
ffi (1.11.3)
|
||||
ffi-compiler (1.0.1)
|
||||
ffi (>= 1.0.0)
|
||||
rake
|
||||
@@ -56,21 +56,21 @@ GEM
|
||||
gettext (3.2.9)
|
||||
locale (>= 2.0.5)
|
||||
text (>= 1.3.0)
|
||||
gettext-setup (0.30)
|
||||
gettext-setup (0.31)
|
||||
fast_gettext (~> 1.1.0)
|
||||
gettext (>= 3.0.2)
|
||||
locale
|
||||
gpgmeh (0.1.6)
|
||||
activesupport (>= 2.3)
|
||||
nio4r (~> 2.2)
|
||||
hiera (3.5.0)
|
||||
hocon (1.2.5)
|
||||
hiera (3.6.0)
|
||||
hocon (1.3.0)
|
||||
httpclient (2.8.3)
|
||||
huffman (0.0.1)
|
||||
PriorityQueue
|
||||
activesupport
|
||||
ruby-graphviz
|
||||
i18n (1.6.0)
|
||||
i18n (1.7.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
json (2.2.0)
|
||||
librarian-puppet (3.0.0)
|
||||
@@ -80,17 +80,18 @@ GEM
|
||||
librarianp (0.6.4)
|
||||
thor (~> 0.15)
|
||||
locale (2.1.2)
|
||||
mini_exiftool (2.9.0)
|
||||
mini_exiftool (2.9.1)
|
||||
mini_exiftool_vendored (9.2.7.v1)
|
||||
mini_exiftool (>= 1.6.0)
|
||||
mini_portile2 (2.4.0)
|
||||
minitar (0.8)
|
||||
minitest (5.11.3)
|
||||
multi_json (1.13.1)
|
||||
minitar (0.9)
|
||||
minitest (5.13.0)
|
||||
multi_json (1.14.1)
|
||||
multipart-post (2.1.1)
|
||||
mustermann (1.0.3)
|
||||
net-ntp (2.1.3)
|
||||
nio4r (2.3.1)
|
||||
nokogiri (1.10.3)
|
||||
nio4r (2.5.2)
|
||||
nokogiri (1.10.5)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
nori (2.6.0)
|
||||
ovirt-engine-sdk (4.3.0)
|
||||
@@ -100,49 +101,61 @@ GEM
|
||||
pcaprub (0.13.0)
|
||||
pg (1.1.4)
|
||||
process_helper (0.1.2)
|
||||
puppet (6.4.2)
|
||||
CFPropertyList (~> 2.2)
|
||||
puppet (6.11.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
deep_merge (~> 1.0)
|
||||
facter (> 2.0.1, < 4)
|
||||
fast_gettext (~> 1.1.2)
|
||||
fast_gettext (~> 1.1)
|
||||
hiera (>= 3.2.1, < 4)
|
||||
httpclient (~> 2.8)
|
||||
locale (~> 2.1)
|
||||
multi_json (~> 1.10)
|
||||
puppet-resource_api (~> 1.5)
|
||||
semantic_puppet (~> 1.0)
|
||||
puppet-resource_api (1.8.3)
|
||||
puppet-resource_api (1.8.7)
|
||||
hocon (>= 1.0)
|
||||
puppet_forge (2.2.9)
|
||||
faraday (>= 0.9.0, < 0.14.0)
|
||||
puppet_forge (2.3.1)
|
||||
faraday (>= 0.9.0, < 0.15.0, != 0.13.1)
|
||||
faraday_middleware (>= 0.9.0, < 0.13.0)
|
||||
gettext-setup (~> 0.11)
|
||||
minitar
|
||||
semantic_puppet (~> 1.0)
|
||||
rake (12.3.2)
|
||||
rdoc (6.1.1)
|
||||
redcarpet (3.4.0)
|
||||
rmagick (3.2.0)
|
||||
rqrcode (0.10.1)
|
||||
rack (2.0.7)
|
||||
rack-protection (2.0.7)
|
||||
rack
|
||||
rake (13.0.1)
|
||||
rdoc (6.2.0)
|
||||
redcarpet (3.5.0)
|
||||
rmagick (4.0.0)
|
||||
rqrcode (1.1.2)
|
||||
chunky_png (~> 1.0)
|
||||
rqrcode_core (~> 0.1)
|
||||
rqrcode_core (0.1.1)
|
||||
rsa (0.1.4)
|
||||
rsync (1.0.9)
|
||||
ruby-graphviz (1.2.4)
|
||||
rubyzip (1.2.3)
|
||||
scrypt (3.0.6)
|
||||
rubyzip (1.3.0)
|
||||
scrypt (3.0.7)
|
||||
ffi-compiler (>= 1.0, < 2.0)
|
||||
semantic_puppet (1.0.2)
|
||||
sinatra (2.0.7)
|
||||
mustermann (~> 1.0)
|
||||
rack (~> 2.0)
|
||||
rack-protection (= 2.0.7)
|
||||
tilt (~> 2.0)
|
||||
smbhash (1.0.2)
|
||||
spidr (0.6.0)
|
||||
spidr (0.6.1)
|
||||
nokogiri (~> 1.3)
|
||||
sshkey (2.0.0)
|
||||
text (1.3.1)
|
||||
thor (0.19.4)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.10)
|
||||
tzinfo (1.2.5)
|
||||
thread_safe (~> 0.1)
|
||||
wordlist (0.1.1)
|
||||
spidr (~> 0.2)
|
||||
yard (0.9.19)
|
||||
yard (0.9.20)
|
||||
zip-zip (0.3)
|
||||
rubyzip (>= 1.0.0)
|
||||
zipruby (0.3.6)
|
||||
@@ -186,6 +199,7 @@ DEPENDENCIES
|
||||
rsa
|
||||
ruby-graphviz
|
||||
scrypt
|
||||
sinatra
|
||||
smbhash
|
||||
sshkey
|
||||
wordlist
|
||||
@@ -194,4 +208,4 @@ DEPENDENCIES
|
||||
zipruby
|
||||
|
||||
BUNDLED WITH
|
||||
1.11.2
|
||||
1.17.3
|
||||
|
||||
@@ -143,7 +143,7 @@ def parse_opts(opts)
|
||||
when '--failed'
|
||||
options[:failed] = true
|
||||
when '--affinity-group'
|
||||
options[:affinity_group] = true
|
||||
options[:affinity_group] = true
|
||||
else
|
||||
Print.err 'Invalid argument'
|
||||
exit(false)
|
||||
|
||||
@@ -78,6 +78,9 @@ VAGRANT_TEMPLATE_FILE = "#{ROOT_DIR}/lib/templates/Vagrantfile.erb"
|
||||
|
||||
PUPPET_TEMPLATE_FILE = "#{ROOT_DIR}/lib/templates/Puppetfile.erb"
|
||||
|
||||
AUDITBEAT_RULES_TEMPLATE_FILE = "#{ROOT_DIR}/lib/templates/auditbeat_goal_rules.erb"
|
||||
ELASTALERT_RULES_TEMPLATE_FILE = "#{ROOT_DIR}/lib/templates/elastalert_goal_rules.erb"
|
||||
|
||||
## INTEGER CONSTANTS ##
|
||||
RETRIES_LIMIT = 10
|
||||
|
||||
|
||||
16
lib/helpers/json_functions.rb
Normal file
16
lib/helpers/json_functions.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
require "json"
|
||||
|
||||
# With thanks, from https://gist.github.com/ascendbruce/7070951
|
||||
class JSONFunctions
|
||||
def self.is_json?(value)
|
||||
result = JSON.parse(value)
|
||||
result.is_a?(Hash)
|
||||
rescue JSON::ParserError, TypeError
|
||||
false
|
||||
end
|
||||
|
||||
# prepare eval string by removing all characters other than #{}[].'_/a-zA-Z0-9
|
||||
def self.sanitise_eval_string(string)
|
||||
string.gsub(/[^A-Za-z0-9\[\]'\/\_\#\{\}.]/, '')
|
||||
end
|
||||
end
|
||||
@@ -14,35 +14,43 @@ class Print
|
||||
def self.bright_yellow(text); colorize(text, "\e[93m"); end
|
||||
def self.bold(text); colorize(text, "\e[2m"); end
|
||||
|
||||
def self.debug(msg)
|
||||
def self.debug(msg, logger=nil)
|
||||
logger.debug(msg) if logger
|
||||
puts purple(' ' + msg)
|
||||
end
|
||||
|
||||
def self.verbose(msg)
|
||||
def self.verbose(msg, logger=nil)
|
||||
logger.info(msg) if logger
|
||||
puts grey(' ' + msg)
|
||||
end
|
||||
|
||||
def self.err(msg)
|
||||
def self.err(msg, logger=nil)
|
||||
logger.error(msg) if logger
|
||||
$stderr.puts red(msg)
|
||||
end
|
||||
|
||||
def self.info(msg)
|
||||
def self.info(msg, logger=nil)
|
||||
logger.info(msg) if logger
|
||||
puts green(msg)
|
||||
end
|
||||
|
||||
def self.std(msg)
|
||||
def self.std(msg, logger=nil)
|
||||
logger.info(msg) if logger
|
||||
puts yellow(msg)
|
||||
end
|
||||
|
||||
def self.warn(msg)
|
||||
def self.warn(msg, logger=nil)
|
||||
logger.warn(msg) if logger
|
||||
puts bright_yellow(msg)
|
||||
end
|
||||
|
||||
# local encoders/generators write messages to stderr (stdout used to return values)
|
||||
def self.local(msg)
|
||||
def self.local(msg, logger=nil)
|
||||
logger.info(msg) if logger
|
||||
$stderr.puts cyan(msg)
|
||||
end
|
||||
def self.local_verbose(msg)
|
||||
def self.local_verbose(msg, logger=nil)
|
||||
logger.info(msg) if logger
|
||||
$stderr.puts cyan(' ' + msg)
|
||||
end
|
||||
|
||||
|
||||
101
lib/helpers/rules.rb
Normal file
101
lib/helpers/rules.rb
Normal file
@@ -0,0 +1,101 @@
|
||||
require_relative './print.rb'
|
||||
require_relative './scenario.rb'
|
||||
|
||||
class Rules
|
||||
# Generate audit and alerting rules
|
||||
|
||||
def self.generate_auditbeat_rules(goals)
|
||||
rules = []
|
||||
goals.each do |goal|
|
||||
# Generate auditbeat rules based on rule type
|
||||
rule_type = RuleTypes.get_rule_type(goal['goal_type'])
|
||||
case rule_type
|
||||
when RuleTypes::READ_FILE
|
||||
rules << greedy_auditbeat_rule(goal['file_path'], 'r')
|
||||
when RuleTypes::MODIFY_FILE
|
||||
when RuleTypes::ACCESS_ACCOUNT
|
||||
when RuleTypes::SERVICE_DOWN
|
||||
when RuleTypes::SYSTEM_DOWN
|
||||
else
|
||||
Print.err('Unknown goal type')
|
||||
raise
|
||||
end
|
||||
end
|
||||
rules
|
||||
end
|
||||
|
||||
# Generates a greedy read or write rule for auditbeat (e.g. /home/user/file_name resolves to /home)
|
||||
def self.greedy_auditbeat_rule(path, r_w)
|
||||
base_path = path.split('/')[0..1].join('/') + '/'
|
||||
key = base_path.gsub(/[^A-Za-z0-9\-\_]/, '')
|
||||
"-w #{base_path} -p #{r_w} -k #{key}"
|
||||
end
|
||||
|
||||
|
||||
def self.generate_elastalert_rule(hostname, module_name, goal, counter)
|
||||
rule = ''
|
||||
# switch case to determine which type of rule we're returning (read file, etc.)
|
||||
rule_type = RuleTypes.get_rule_type(goal['goal_type'])
|
||||
case rule_type
|
||||
when RuleTypes::READ_FILE
|
||||
rule = generate_elastalert_rule_rf(hostname, module_name, goal, counter)
|
||||
when RuleTypes::MODIFY_FILE
|
||||
# rule = generate_elastalert_rule_mf(hostname, module_name, goal, sub_goal)
|
||||
when RuleTypes::ACCESS_ACCOUNT
|
||||
# rule = generate_elastalert_rule_aa(hostname, module_name, goal, sub_goal)
|
||||
when RuleTypes::SERVICE_DOWN
|
||||
# rule = generate_elastalert_rule_svcd(hostname, module_name, goal, sub_goal)
|
||||
when RuleTypes::SYSTEM_DOWN
|
||||
# rule = generate_elastalert_rule_sysd(hostname, module_name, goal, sub_goal)
|
||||
else
|
||||
raise 'unknown_goal_type'
|
||||
end
|
||||
rule
|
||||
end
|
||||
|
||||
def self.generate_elastalert_rule_rf(hostname, module_name, goal, counter)
|
||||
"name: #{get_ea_rulename(hostname, module_name, goal, counter)}\n" +
|
||||
"type: any\n" +
|
||||
"index: auditbeat-*\n" +
|
||||
"filter:\n" +
|
||||
" - query:\n" +
|
||||
" query_string:\n" +
|
||||
' query: "combined_path: \"' + goal['file_path'] + '\" AND auditd.result: success AND event.action: opened-file"' + "\n" +
|
||||
"alert:\n" +
|
||||
" - \"elastalert.modules.alerter.exec.ExecAlerter\"\n" +
|
||||
"command: [\"/usr/bin/ruby\", \"/opt/alert_actioner/alert_router.rb\"]\n" +
|
||||
"pipe_match_json: true\n" +
|
||||
"realert:\n" +
|
||||
" minutes: 0\n"
|
||||
end
|
||||
|
||||
def self.get_ea_rulename(hostname, module_name, goal, counter)
|
||||
rule_type = RuleTypes.get_rule_type(goal['goal_type'])
|
||||
return "#{hostname}-#{module_name}-#{rule_type}-#{counter}"
|
||||
end
|
||||
|
||||
class RuleTypes
|
||||
READ_FILE = 'rf'
|
||||
MODIFY_FILE = 'mf'
|
||||
ACCESS_ACCOUNT = 'aa'
|
||||
SERVICE_DOWN = 'svcd'
|
||||
SYSTEM_DOWN = 'sysd'
|
||||
|
||||
def self.get_rule_type(rule_type)
|
||||
case rule_type
|
||||
when 'read_file'
|
||||
READ_FILE
|
||||
when 'modify_file'
|
||||
MODIFY_FILE
|
||||
when 'access_account'
|
||||
ACCESS_ACCOUNT
|
||||
when 'service_down'
|
||||
SERVICE_DOWN
|
||||
when 'system_down'
|
||||
SYSTEM_DOWN
|
||||
else
|
||||
raise 'unknown_rule_type'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
15
lib/helpers/scenario.rb
Normal file
15
lib/helpers/scenario.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
class ScenarioHelper
|
||||
|
||||
def self.get_scenario_name(scenario_path)
|
||||
scenario_path.split('/').last.split('.').first + '-'
|
||||
end
|
||||
|
||||
def self.get_prefix(options, scenario_name)
|
||||
options[:prefix] ? (options[:prefix] + '-' + scenario_name) : ('SecGen-' + scenario_name)
|
||||
end
|
||||
|
||||
def self.get_hostname(options, scenario_path, system_name)
|
||||
"#{get_prefix(options, get_scenario_name(scenario_path))}#{system_name}".tr('_', '-')
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,12 +1,16 @@
|
||||
require_relative '../helpers/constants.rb'
|
||||
require_relative '../helpers/json_functions.rb'
|
||||
|
||||
require 'digest/md5'
|
||||
require 'securerandom'
|
||||
require 'duplicate'
|
||||
require 'yaml'
|
||||
|
||||
class Module
|
||||
#Vulnerability attributes hash
|
||||
attr_accessor :module_path # vulnerabilities/unix/ftp/vsftp_234_backdoor
|
||||
attr_accessor :module_type # vulnerability|service|utility
|
||||
attr_accessor :attributes # attributes are hashes that contain arrays of values
|
||||
attr_accessor :attributes # attributes are hashes that contain arrays of values
|
||||
# Each attribute is stored in a hash containing an array of values (because elements such as author can repeat).
|
||||
# Module *selectors*, store filters in the attributes hash.
|
||||
# XML validity ensures valid and complete information.
|
||||
@@ -22,6 +26,7 @@ class Module
|
||||
|
||||
attr_accessor :conflicts
|
||||
attr_accessor :requires
|
||||
attr_accessor :goals
|
||||
attr_accessor :puppet_file
|
||||
attr_accessor :puppet_other_path
|
||||
attr_accessor :local_calc_file
|
||||
@@ -34,6 +39,7 @@ class Module
|
||||
self.module_type = module_type
|
||||
self.conflicts = []
|
||||
self.requires = []
|
||||
self.goals = []
|
||||
self.attributes = {}
|
||||
self.output = []
|
||||
self.write_to_module_with_id = write_output_variable = ''
|
||||
@@ -52,10 +58,11 @@ class Module
|
||||
# @return [Object] a string for console output
|
||||
def to_s
|
||||
(<<-END)
|
||||
#{module_type}: #{module_path}
|
||||
#{module_type}: #{module_path}
|
||||
attributes: #{attributes.inspect}
|
||||
conflicts: #{conflicts.inspect}
|
||||
requires: #{requires.inspect}
|
||||
goals: #{goals.inspect}
|
||||
puppet file: #{puppet_file}
|
||||
puppet path: #{puppet_other_path}
|
||||
END
|
||||
@@ -76,6 +83,7 @@ class Module
|
||||
# id: #{unique_id}
|
||||
# attributes: #{attributes.inspect}
|
||||
# conflicts: #{conflicts.inspect}
|
||||
# goals: #{goals.inspect}
|
||||
# requires: #{requires.inspect}#{input}#{out}
|
||||
END
|
||||
end
|
||||
@@ -89,7 +97,7 @@ class Module
|
||||
# @return [Object] the module path with _ rather than / for use as a variable name
|
||||
def module_path_name
|
||||
module_path_name = module_path.clone
|
||||
module_path_name.gsub!('/','_')
|
||||
module_path_name.gsub!('/', '_')
|
||||
end
|
||||
|
||||
# @return [Object] a list of attributes that can be used to re-select the same modules
|
||||
@@ -97,7 +105,7 @@ class Module
|
||||
attr_flattened = {}
|
||||
|
||||
attributes.each do |key, array|
|
||||
unless "#{key}" == 'module_type' || "#{key}" == 'conflict' || "#{key}" == 'default_input' || "#{key}" == 'requires'
|
||||
unless "#{key}" == 'module_type' || "#{key}" == 'conflict' || "#{key}" == 'default_input' || "#{key}" == 'requires' || "#{key}" == 'goals'
|
||||
# creates a valid regexp that can match the original module
|
||||
attr_flattened["#{key}"] = Regexp.escape(array.join('~~~')).gsub(/\n\w*/, '.*').gsub(/\\ /, ' ').gsub(/~~~/, '|')
|
||||
end
|
||||
@@ -176,8 +184,93 @@ class Module
|
||||
end
|
||||
end
|
||||
|
||||
# Get unique rule id for the module based on a rule key/value pair
|
||||
def get_unique_rule_id(prefix, system_name, rule_key, rule_value)
|
||||
# TODO: This might be too long, see if there is a length limit for rule identities
|
||||
prefix = prefix + "_" if prefix and prefix != ''
|
||||
"#{prefix}#{system_name}_#{module_path_end}_#{rule_key}_#{rule_value.gsub(/[^\w]/, '_')}"
|
||||
end
|
||||
|
||||
def printable_name
|
||||
"#{self.attributes['name'].first} (#{self.module_path})"
|
||||
end
|
||||
|
||||
# Resolve the string interpolation for received inputs
|
||||
# e.g. convert "/home#{accounts[0].username}/#{leaked_files}" into the correct string.
|
||||
def resolve_received_inputs
|
||||
received_inputs_to_hash
|
||||
self.received_inputs.each do |input|
|
||||
# Resolve the received inputs which contain #{}
|
||||
input[1].each_with_index do |string, c|
|
||||
input[1][c] = interp_string(string) if contains_interp(string)
|
||||
end
|
||||
end
|
||||
received_inputs_to_json_str
|
||||
end
|
||||
|
||||
# Resolve the string interpolation for goals
|
||||
|
||||
def resolve_goals(hostname)
|
||||
new_goals = []
|
||||
self.goals.each do |goal|
|
||||
new_goal = {}
|
||||
|
||||
# Add hostname to module goals
|
||||
new_goal.merge!({'hostname' => hostname}) unless goal.has_key? 'hostname'
|
||||
|
||||
# Interpolate values that require it
|
||||
goal.each_key do |key|
|
||||
value = goal[key]
|
||||
new_goal.merge!(key => (contains_interp(value) ? interp_string(value) : value))
|
||||
end
|
||||
new_goals << new_goal
|
||||
end
|
||||
self.goals = new_goals
|
||||
end
|
||||
|
||||
def contains_interp(string)
|
||||
string.include?('#{') and string.include?('}')
|
||||
end
|
||||
|
||||
def received_inputs_to_hash
|
||||
self.received_inputs.each do |_, array|
|
||||
array.each_with_index do |value, i|
|
||||
if JSONFunctions.is_json?(value)
|
||||
array[i] = JSON.parse(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def received_inputs_to_json_str
|
||||
self.received_inputs.each do |_, array|
|
||||
array.each_with_index do |value, i|
|
||||
if value.is_a? Hash
|
||||
array[i] = value.to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def interp_string(string)
|
||||
begin
|
||||
# identify the indices of the #{ characters within the string
|
||||
start_indices = string.enum_for(:scan, /#\{/).map {Regexp.last_match.begin(0)}
|
||||
reference_string = "self.received_inputs"
|
||||
start_indices.each_with_index do |index, counter|
|
||||
rolling_index = index + 2 # we add 2 for the #{ characters
|
||||
if counter > 0
|
||||
rolling_index = reference_string.length + index + 2
|
||||
end
|
||||
string.insert(rolling_index, reference_string)
|
||||
end
|
||||
|
||||
string = JSONFunctions.sanitise_eval_string(string)
|
||||
# evaluate and parse evaluated string into required data types(e.g. "['a',['b','c']]" into ['a',['b','c']])
|
||||
YAML.load(instance_eval("\"#{string}\""))
|
||||
rescue NoMethodError, SyntaxError, Psych::Exception => err
|
||||
Print.err "#{err}"
|
||||
raise 'failed'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,30 +2,42 @@ require 'json'
|
||||
require 'base64'
|
||||
require 'duplicate'
|
||||
|
||||
require_relative '../helpers/scenario'
|
||||
|
||||
class System
|
||||
|
||||
attr_accessor :name
|
||||
attr_accessor :hostname
|
||||
attr_accessor :attributes # (basebox selection)
|
||||
attr_accessor :module_selectors # (filters)
|
||||
attr_accessor :module_selections # (after resolution)
|
||||
attr_accessor :num_actioned_module_conflicts
|
||||
attr_accessor :memory # (RAM allocation for the system)
|
||||
attr_accessor :options # (command line options hash)
|
||||
attr_accessor :scenario_path # (path to scenario file associated with this system)
|
||||
attr_accessor :goals # scenario-level goals []
|
||||
|
||||
# Attributes for resetting retry loop
|
||||
attr_accessor :available_mods #(command line options hash)
|
||||
attr_accessor :original_datastores #(command line options hash)
|
||||
attr_accessor :original_module_selectors #(command line options hash)
|
||||
attr_accessor :original_available_modules #(command line options hash)
|
||||
attr_accessor :available_mods
|
||||
attr_accessor :original_datastores
|
||||
attr_accessor :original_module_selectors
|
||||
attr_accessor :original_available_modules
|
||||
|
||||
# Initalizes System object
|
||||
# @param [Object] name of the system
|
||||
# @param [Object] attributes such as base box selection
|
||||
# @param [Object] module_selectors these are modules that define filters for selecting the actual modules to use
|
||||
def initialize(name, attributes, module_selectors)
|
||||
def initialize(name, attributes, module_selectors, scenario_file, options)
|
||||
self.name = name
|
||||
self.attributes = attributes
|
||||
self.module_selectors = module_selectors
|
||||
self.module_selections = []
|
||||
self.num_actioned_module_conflicts = 0
|
||||
self.memory = "512"
|
||||
self.options = options
|
||||
self.scenario_path = scenario_file
|
||||
self.goals = []
|
||||
set_hostname
|
||||
end
|
||||
|
||||
# selects from the available modules, based on the selection filters that have been specified
|
||||
@@ -260,8 +272,8 @@ class System
|
||||
# parse the datastore
|
||||
parsed_datastore_element = JSON.parse(datastore_retrieved.first)
|
||||
|
||||
# Sanitise with whitelist of used characters: ' [ ]
|
||||
access_json = datastore_access_json.gsub(/[^A-Za-z0-9\[\]'_]/, '')
|
||||
# Sanitise with whitelist
|
||||
access_json = JSONFunctions.sanitise_eval_string(datastore_access_json)
|
||||
|
||||
# get data from access_json string
|
||||
begin
|
||||
@@ -463,4 +475,36 @@ class System
|
||||
modules_to_add
|
||||
end
|
||||
|
||||
def has_module(module_name)
|
||||
has_module = false
|
||||
module_selections.each do |mod|
|
||||
if mod.module_path_end == module_name
|
||||
has_module = true
|
||||
end
|
||||
end
|
||||
has_module
|
||||
end
|
||||
|
||||
def get_module(module_name)
|
||||
selected_module = nil
|
||||
module_selections.each do |mod|
|
||||
if mod.module_path_end == module_name
|
||||
selected_module = mod
|
||||
end
|
||||
end
|
||||
selected_module
|
||||
end
|
||||
|
||||
def set_options(opts)
|
||||
self.options = opts if opts != nil and self.options == {}
|
||||
end
|
||||
|
||||
def set_hostname
|
||||
self.hostname = ScenarioHelper.get_hostname(self.options, self.scenario_path, self.name)
|
||||
end
|
||||
|
||||
def get_hostname
|
||||
set_hostname
|
||||
self.hostname
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
require 'erb'
|
||||
require_relative '../helpers/constants.rb'
|
||||
require_relative '../helpers/rules.rb'
|
||||
require_relative 'xml_scenario_generator.rb'
|
||||
require_relative 'xml_marker_generator.rb'
|
||||
require_relative 'xml_alertaction_config_generator.rb'
|
||||
require_relative 'ctfd_generator.rb'
|
||||
require 'fileutils'
|
||||
require 'librarian'
|
||||
@@ -30,11 +32,12 @@ class ProjectFilesCreator
|
||||
@scenario = scenario
|
||||
@time = Time.new.to_s
|
||||
@options = options
|
||||
@scenario_networks = Hash.new { |h, k| h[k] = 1 }
|
||||
@scenario_networks = Hash.new {|h, k| h[k] = 1}
|
||||
@option_range_map = {}
|
||||
|
||||
# Packer builder type
|
||||
@builder_type = @options.has_key?(:esxi_url) ? :vmware_iso : :virtualbox_iso
|
||||
resolve_interp_strings
|
||||
end
|
||||
|
||||
# Generate all relevant files for the project
|
||||
@@ -44,13 +47,13 @@ class ProjectFilesCreator
|
||||
if File.exists? "#{@out_dir}/Vagrantfile" or File.exists? "#{@out_dir}/puppet"
|
||||
dest_dir = "#{@out_dir}/MOVED_#{Time.new.strftime("%Y%m%d_%H%M%S")}"
|
||||
Print.warn "Project already built to this directory -- moving last build to: #{dest_dir}"
|
||||
Dir.glob( "#{@out_dir}/**/*" ).select { |f| File.file?( f ) }.each do |f|
|
||||
Dir.glob("#{@out_dir}/**/*").select {|f| File.file?(f)}.each do |f|
|
||||
dest = "#{dest_dir}/#{f}"
|
||||
FileUtils.mkdir_p( File.dirname( dest ) )
|
||||
FileUtils.mkdir_p(File.dirname(dest))
|
||||
if f =~ /\.vagrant/
|
||||
FileUtils.cp( f, dest )
|
||||
FileUtils.cp(f, dest)
|
||||
else
|
||||
FileUtils.mv( f, dest )
|
||||
FileUtils.mv(f, dest)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -89,7 +92,7 @@ class ProjectFilesCreator
|
||||
if File.file? packerfile_path
|
||||
Print.info "Would you like to use the packerfile to create the packerfile from the given url (y/n)"
|
||||
# TODO: remove user interaction, this should be set via a config option
|
||||
(Print.info "Exiting as vagrant needs the basebox to continue"; abort) unless ['y','yes'].include?(STDIN.gets.chomp.downcase)
|
||||
(Print.info "Exiting as vagrant needs the basebox to continue"; abort) unless ['y', 'yes'].include?(STDIN.gets.chomp.downcase)
|
||||
|
||||
Print.std "Packerfile #{packerfile_path.split('/').last} found, building basebox #{url.split('/').last} via packer"
|
||||
template_based_file_write(packerfile_path, packerfile_path.split(/.erb$/).first)
|
||||
@@ -108,6 +111,82 @@ class ProjectFilesCreator
|
||||
end
|
||||
end
|
||||
end
|
||||
# Create client side auto-grading config files (auditbeat)
|
||||
if system.has_module('auditbeat')
|
||||
auditbeat_rules_file = "#{path}/modules/auditbeat/files/rules/auditbeat_rules_file.conf"
|
||||
@rules = []
|
||||
system.module_selections.each do |module_selection|
|
||||
if module_selection.goals != []
|
||||
@rules << Rules.generate_auditbeat_rules(module_selection.goals)
|
||||
end
|
||||
end
|
||||
|
||||
if system.goals != []
|
||||
@rules << Rules.generate_auditbeat_rules(system.goals)
|
||||
end
|
||||
|
||||
@rules = @rules.flatten.uniq
|
||||
Print.std "Creating client side auditing rules: #{auditbeat_rules_file}"
|
||||
if @rules.size > 0
|
||||
template_based_file_write(AUDITBEAT_RULES_TEMPLATE_FILE, auditbeat_rules_file)
|
||||
end
|
||||
end
|
||||
|
||||
# Create server-side auto-grading config files (elastalert)
|
||||
if system.has_module('elastalert')
|
||||
@systems.each do |sys|
|
||||
@hostname = sys.get_hostname
|
||||
|
||||
if sys.goals != []
|
||||
sys.goals.each_with_index do |goal, i|
|
||||
@system_name = sys.name
|
||||
@goal = goal
|
||||
@counter = i
|
||||
rule_name = Rules.get_ea_rulename(@hostname, @system_name, @goal, @counter)
|
||||
elastalert_rules_file = "#{path}/modules/elastalert/files/rules/#{rule_name}.yaml"
|
||||
Print.std "Creating server side alerting rules (system): #{elastalert_rules_file}"
|
||||
template_based_file_write(ELASTALERT_RULES_TEMPLATE_FILE, elastalert_rules_file)
|
||||
end
|
||||
end
|
||||
|
||||
sys.module_selections.each do |module_selection|
|
||||
if module_selection.goals != {}
|
||||
module_selection.goals.each_with_index do |goal, i|
|
||||
@module_name = module_selection.module_path_end
|
||||
@goal = goal
|
||||
@counter = i
|
||||
rule_name = Rules.get_ea_rulename(@hostname, @module_name, @goal, @counter)
|
||||
elastalert_rules_file = "#{path}/modules/elastalert/files/rules/#{rule_name}.yaml"
|
||||
Print.std "Creating server side alerting rules: #{elastalert_rules_file}"
|
||||
template_based_file_write(ELASTALERT_RULES_TEMPLATE_FILE, elastalert_rules_file)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Refactor to include in the loop above if possible
|
||||
if system.has_module('analysis_alert_action_server')
|
||||
Print.info 'AlertActioner: Copying shared libs...'
|
||||
aa_lib_dir = "#{path}/modules/analysis_alert_action_server/files/alert_actioner/lib"
|
||||
FileUtils.mkdir_p(aa_lib_dir)
|
||||
FileUtils.cp_r("#{ROOT_DIR}/lib/helpers/print.rb", "#{aa_lib_dir}/print.rb")
|
||||
FileUtils.cp_r("#{ROOT_DIR}/lib/readers/xml_reader.rb", "#{aa_lib_dir}/xml_reader.rb")
|
||||
FileUtils.cp_r("#{ROOT_DIR}/lib/schemas/alertactioner_config_schema.xsd", "#{aa_lib_dir}/alertactioner_config_schema.xsd")
|
||||
FileUtils.cp_r("#{ROOT_DIR}/lib/helpers/ovirt.rb", "#{aa_lib_dir}/ovirt.rb")
|
||||
|
||||
Print.info 'AlertActioner: Generating AA configs...'
|
||||
aa_conf_dir = "#{path}/modules/analysis_alert_action_server/files/alert_actioner/config/"
|
||||
FileUtils.mkdir_p(aa_conf_dir)
|
||||
# Get the config json object from the alert_actioner
|
||||
aa_confs = JSON.parse(system.get_module('analysis_alert_action_server').received_inputs['aaa_config'][0])['aa_configs']
|
||||
xml_aa_conf_file = "#{aa_conf_dir}#{@out_dir.split('/')[-1]}.xml"
|
||||
xml_aa_conf_generator = XmlAlertActionConfigGenerator.new(@systems, @scenario, @time, aa_confs, @options)
|
||||
xml = xml_aa_conf_generator.output
|
||||
Print.std "AlertActioner: Creating alert_actioner configuration file: #{xml_aa_conf_file}"
|
||||
write_data_to_file(xml, xml_aa_conf_file)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Create environments/production/environment.conf - Required in Puppet 4+
|
||||
@@ -125,14 +204,7 @@ class ProjectFilesCreator
|
||||
xml_report_generator = XmlScenarioGenerator.new(@systems, @scenario, @time)
|
||||
xml = xml_report_generator.output
|
||||
Print.std "Creating scenario definition file: #{xfile}"
|
||||
begin
|
||||
File.open(xfile, 'w+') do |file|
|
||||
file.write(xml)
|
||||
end
|
||||
rescue StandardError => e
|
||||
Print.err "Error writing file: #{e.message}"
|
||||
abort
|
||||
end
|
||||
write_data_to_file(xml, xfile)
|
||||
|
||||
# Create the marker xml file
|
||||
x2file = "#{@out_dir}/#{FLAGS_FILENAME}"
|
||||
@@ -140,14 +212,7 @@ class ProjectFilesCreator
|
||||
xml_marker_generator = XmlMarkerGenerator.new(@systems, @scenario, @time)
|
||||
xml = xml_marker_generator.output
|
||||
Print.std "Creating flags and hints file: #{x2file}"
|
||||
begin
|
||||
File.open(x2file, 'w+') do |file|
|
||||
file.write(xml)
|
||||
end
|
||||
rescue StandardError => e
|
||||
Print.err "Error writing file: #{e.message}"
|
||||
abort
|
||||
end
|
||||
write_data_to_file(xml, x2file)
|
||||
|
||||
# Create the CTFd zip file for import
|
||||
ctfdfile = "#{@out_dir}/CTFd_importable.zip"
|
||||
@@ -158,10 +223,10 @@ class ProjectFilesCreator
|
||||
|
||||
# zip up the CTFd export
|
||||
begin
|
||||
Zip::ZipFile.open(ctfdfile, Zip::ZipFile::CREATE) { |zipfile|
|
||||
Zip::ZipFile.open(ctfdfile, Zip::ZipFile::CREATE) {|zipfile|
|
||||
zipfile.mkdir("db")
|
||||
ctfd_files.each do |ctfd_file_name, ctfd_file_content|
|
||||
zipfile.get_output_stream("db/#{ctfd_file_name}") { |f|
|
||||
zipfile.get_output_stream("db/#{ctfd_file_name}") {|f|
|
||||
f.print ctfd_file_content
|
||||
}
|
||||
end
|
||||
@@ -187,6 +252,31 @@ class ProjectFilesCreator
|
||||
|
||||
end
|
||||
|
||||
def write_data_to_file(data, path)
|
||||
begin
|
||||
File.open(path, 'w+') do |file|
|
||||
file.write(data)
|
||||
end
|
||||
rescue StandardError => e
|
||||
Print.err "Error writing file: #{e.message}"
|
||||
abort
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Goal string interpolation for the whole system
|
||||
# prior to calling the rule generator multiple times
|
||||
def resolve_interp_strings
|
||||
@systems.each do |system|
|
||||
system.module_selections.each do |module_selection|
|
||||
module_selection.resolve_received_inputs
|
||||
end
|
||||
system.module_selections.each do |module_selection|
|
||||
module_selection.resolve_goals(system.get_hostname)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @param [Object] template erb path
|
||||
# @param [Object] filename file to write to
|
||||
def template_based_file_write(template, filename)
|
||||
@@ -213,15 +303,15 @@ class ProjectFilesCreator
|
||||
if current_network.received_inputs.include? 'IP_address'
|
||||
ip_address = current_network.received_inputs['IP_address'].first
|
||||
elsif @options.has_key? :ip_ranges
|
||||
# if we have options[:ip_ranges] we want to use those instead of the ip_range argument.
|
||||
# Store the mappings of scenario_ip_ranges => @options[:ip_range] in @option_range_map
|
||||
# if we have options[:ip_ranges] we want to use those instead of the ip_range argument.
|
||||
# Store the mappings of scenario_ip_ranges => @options[:ip_range] in @option_range_map
|
||||
# Have we seen this scenario_ip_range before? If so, use the value we've assigned
|
||||
if @option_range_map.has_key? scenario_ip_range
|
||||
ip_range = @option_range_map[scenario_ip_range]
|
||||
else
|
||||
# Remove options_ips that have already been used
|
||||
options_ips = @options[:ip_ranges]
|
||||
options_ips.delete_if { |ip| @option_range_map.has_value? ip }
|
||||
options_ips.delete_if {|ip| @option_range_map.has_value? ip}
|
||||
@option_range_map[scenario_ip_range] = options_ips.first
|
||||
ip_range = options_ips.first
|
||||
end
|
||||
@@ -246,13 +336,33 @@ class ProjectFilesCreator
|
||||
split_ip.join('.')
|
||||
end
|
||||
|
||||
# Replace 'network' with 'snoop' where the system name contains snoop
|
||||
# Replace 'network' with 'snoop' where the system name contains snoop
|
||||
def get_ovirt_network_name(system_name, network_name)
|
||||
split_name = network_name.split('-')
|
||||
split_name[1] = 'snoop' if system_name.include? 'snoop'
|
||||
split_name.join('-')
|
||||
end
|
||||
|
||||
# Determine how much memory the system requires for Vagrantfile
|
||||
def resolve_memory(system)
|
||||
if @options.has_key? :memory_per_vm
|
||||
memory = @options[:memory_per_vm]
|
||||
elsif @options.has_key? :total_memory
|
||||
memory = @options[:total_memory].to_i / @systems.length.to_i
|
||||
elsif (@options.has_key? :ovirtuser) && (@options.has_key? :ovirtpass) && (@base_type.include? 'desktop')
|
||||
memory = '1536'
|
||||
else
|
||||
memory = '512'
|
||||
end
|
||||
|
||||
system.module_selections.each do |mod|
|
||||
if mod.module_path_name.include? "elasticsearch"
|
||||
memory = '8192'
|
||||
end
|
||||
end
|
||||
memory
|
||||
end
|
||||
|
||||
# Returns binding for erb files (access to variables in this classes scope)
|
||||
# @return binding
|
||||
def get_binding
|
||||
|
||||
155
lib/output/xml_alertaction_config_generator.rb
Normal file
155
lib/output/xml_alertaction_config_generator.rb
Normal file
@@ -0,0 +1,155 @@
|
||||
require 'nokogiri'
|
||||
|
||||
require_relative '../helpers/rules'
|
||||
|
||||
# Convert systems objects into alertactioner xml configuration
|
||||
class XmlAlertActionConfigGenerator
|
||||
|
||||
# @param [Object] systems the list of systems
|
||||
# @param [Object] scenario the scenario file used to generate
|
||||
# @param [Object] time the current time as a string
|
||||
# @param [Array[Hash]] the alert_actioner configuration settings (list of aa_conf JSON hashes)
|
||||
def initialize(systems, scenario, time, aa_confs, options)
|
||||
@systems = systems
|
||||
@scenario = scenario
|
||||
@time = time
|
||||
@aa_confs = aa_confs
|
||||
@options = options
|
||||
@alert_actions = []
|
||||
end
|
||||
|
||||
# outputs a XML AlertActioner configuration file
|
||||
# @return [Object] xml string
|
||||
def output
|
||||
create_alert_actions
|
||||
generate_xml_config
|
||||
end
|
||||
|
||||
def create_alert_actions
|
||||
Print.info 'AlertActioner: Creating alert actions from aa_conf.'
|
||||
@aa_confs.each do |aa_conf|
|
||||
if aa_conf['mapping_type']
|
||||
case aa_conf['mapping_type']
|
||||
when 'all_goal_flags_to_hacktivity'
|
||||
all_goal_flags_to_hacktivity(aa_conf)
|
||||
when 'all_goal_messages_to_host'
|
||||
all_goal_message_host(aa_conf)
|
||||
else
|
||||
Print.err("AlertActioner Config: Invalid mapping type #{aa_conf['mapping_type']}")
|
||||
exit(1)
|
||||
end
|
||||
elsif aa_conf['mapping']
|
||||
# TODO: Implement me later
|
||||
else
|
||||
Print.err "AlertActioner Config: Either mapping_type or mapping required."
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def all_goal_message_host(aa_conf)
|
||||
@systems.each do |system|
|
||||
system.module_selections.each do |module_selection|
|
||||
module_name = module_selection.module_path_end
|
||||
module_goals = module_selection.goals
|
||||
if module_goals != []
|
||||
# Iterate over the goals
|
||||
module_selection.goals.each_with_index do |goal, i|
|
||||
@alert_actions << {'alert_name' => Rules.get_ea_rulename(system.hostname, module_name, goal, i),
|
||||
'action_type' => 'MessageAction',
|
||||
'host' => aa_conf['host'],
|
||||
'sender' => aa_conf['sender'],
|
||||
'password' => aa_conf['password'],
|
||||
'recipient' => aa_conf['recipient'],
|
||||
'message_header' => aa_conf['message_header'],
|
||||
'message_subtext' => aa_conf['message_subtext']
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def all_goal_flags_to_hacktivity(aa_conf)
|
||||
@systems.each do |system|
|
||||
if system.goals != []
|
||||
@alert_actions = @alert_actions + get_web_alertactions(aa_conf, system.name, system.goals, $datastore['goal_flags'], system.hostname)
|
||||
end
|
||||
system.module_selections.each do |module_selection|
|
||||
@alert_actions = @alert_actions + get_web_alertactions(aa_conf, module_selection.module_path_end, module_selection.goals, module_selection.received_inputs['goal_flags'], system.hostname)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_web_alertactions(aa_conf, name, goals, goal_flags, hostname)
|
||||
alert_actions = []
|
||||
|
||||
# Validate whether there are an equal number of goals and goal_flags + warn / error here if not...
|
||||
if goals != [] or goal_flags != nil
|
||||
goals_qty = goals.size
|
||||
flags_qty = goal_flags.size
|
||||
unless goals_qty == flags_qty
|
||||
Print.err "AlertActioner: ERROR for mapping_type: #{aa_conf['mapping_type']}"
|
||||
Print.err "Unequal number of goals and goal_flags for: #{name}"
|
||||
Print.err "Goals qty: #{goals_qty} vs Flags qty: #{flags_qty}"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
if goals != [] and goal_flags != nil
|
||||
# Iterate over the goals
|
||||
goals.each_with_index do |goal, i|
|
||||
alert_actions << {'alert_name' => Rules.get_ea_rulename(hostname, name, goal, i),
|
||||
'action_type' => 'WebAction',
|
||||
'target' => aa_conf['target'],
|
||||
'request_type' => 'POST',
|
||||
'data' => goal_flags[i]
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
alert_actions
|
||||
end
|
||||
|
||||
def generate_xml_config
|
||||
Print.info 'Creating AlertActioner xml config...'
|
||||
ns = {
|
||||
'xmlns' => "http://www.github/cliffe/SecGen/alertactioner_config",
|
||||
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
||||
'xsi:schemaLocation' => "http://www.github/cliffe/SecGen/alertactioner_config"
|
||||
}
|
||||
builder = Nokogiri::XML::Builder.new do |xml|
|
||||
xml.alertactioner(ns) {
|
||||
xml.comment 'This AlertActioner configuration file was generated by SecGen'
|
||||
xml.comment "#{@time}"
|
||||
xml.comment "Based on a fulfilment of scenario: #{@scenario}"
|
||||
|
||||
@alert_actions.each {|alert_action|
|
||||
xml.alertaction {
|
||||
xml.alert_name alert_action['alert_name']
|
||||
case alert_action['action_type']
|
||||
when 'WebAction'
|
||||
xml.WebAction {
|
||||
xml.target alert_action['target']
|
||||
xml.request_type alert_action['request_type']
|
||||
xml.data alert_action['data']
|
||||
}
|
||||
when 'MessageAction'
|
||||
xml.MessageAction {
|
||||
xml.host alert_action['host']
|
||||
xml.sender alert_action['sender']
|
||||
xml.password alert_action['password']
|
||||
xml.recipient alert_action['recipient']
|
||||
xml.message_header alert_action['message_header']
|
||||
xml.message_subtext alert_action['message_subtext']
|
||||
}
|
||||
else
|
||||
# TODO: Add more actions
|
||||
Print.err "XmlAlertActionConfigGenerator: Invalid alertaction type - #{alert_action['action_type']}"
|
||||
end
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
builder.to_xml
|
||||
end
|
||||
end
|
||||
@@ -2,9 +2,9 @@ require 'nokogiri'
|
||||
|
||||
require_relative '../helpers/constants.rb'
|
||||
require_relative '../objects/module'
|
||||
require_relative 'system_reader.rb'
|
||||
require_relative 'xml_reader.rb'
|
||||
|
||||
class ModuleReader
|
||||
class ModuleReader < XMLReader
|
||||
|
||||
def self.get_all_available_modules
|
||||
Print.info 'Reading available base modules...'
|
||||
@@ -105,30 +105,9 @@ class ModuleReader
|
||||
end
|
||||
|
||||
Print.verbose "Reading #{module_type}: #{module_path}"
|
||||
doc, xsd = nil
|
||||
begin
|
||||
doc = Nokogiri::XML(File.read(file))
|
||||
rescue
|
||||
Print.err "Failed to read #{module_type} metadata file (#{file})"
|
||||
exit
|
||||
end
|
||||
|
||||
# validate scenario XML against schema
|
||||
begin
|
||||
xsd = Nokogiri::XML::Schema(File.read(schema_file))
|
||||
xsd.validate(doc).each do |error|
|
||||
Print.err "Error in #{module_type} metadata file (#{file}):"
|
||||
Print.err ' ' + error.message
|
||||
exit
|
||||
end
|
||||
rescue Exception => e
|
||||
Print.err "Failed to validate #{module_type} metadata file (#{file}): against schema (#{schema_file})"
|
||||
Print.err e.message
|
||||
exit
|
||||
end
|
||||
|
||||
# remove xml namespaces for ease of processing
|
||||
doc.remove_namespaces!
|
||||
# Parse and validate the schema
|
||||
doc = parse_doc(file, schema_file, module_type)
|
||||
|
||||
new_module = Module.new(module_type)
|
||||
# save module path (and as an attribute for filtering)
|
||||
@@ -159,12 +138,8 @@ class ModuleReader
|
||||
|
||||
# for each element in the vulnerability
|
||||
doc.xpath("/#{module_type}/*").each do |module_doc|
|
||||
|
||||
# new_module.attributes[module_doc.name] = module_doc.content
|
||||
|
||||
# creates the array if null
|
||||
(new_module.attributes[module_doc.name] ||= []).push(module_doc.content)
|
||||
|
||||
end
|
||||
|
||||
# for each conflict in the module
|
||||
@@ -185,6 +160,22 @@ class ModuleReader
|
||||
new_module.requires.push(require)
|
||||
end
|
||||
|
||||
# for each goal in the module
|
||||
doc.xpath("/#{module_type}/goals").each do |goals_doc|
|
||||
goals = []
|
||||
goals_doc.elements.each {|node|
|
||||
goal_type = node.name
|
||||
goal_hash = {'goal_type' => goal_type,}
|
||||
node.children.each {|subnode|
|
||||
unless subnode.text?
|
||||
goal_hash.merge!({subnode.name => subnode.content.strip})
|
||||
end
|
||||
}
|
||||
goals << goal_hash
|
||||
}
|
||||
new_module.goals = goals
|
||||
end
|
||||
|
||||
# for each default input
|
||||
doc.xpath("/#{module_type}/default_input").each do |inputs_doc|
|
||||
inputs_doc.xpath('descendant::vulnerability | descendant::service | descendant::utility | descendant::network | descendant::base | descendant::encoder | descendant::generator').each do |module_node|
|
||||
@@ -220,9 +211,7 @@ class ModuleReader
|
||||
|
||||
(new_module.default_inputs_selectors["#{into}"] ||= []).unshift(module_selector)
|
||||
|
||||
module_node.xpath('@*').each do |attr|
|
||||
module_selector.attributes["#{attr.name}"] = [attr.text] unless attr.text.nil? || attr.text == ''
|
||||
end
|
||||
module_selector.attributes = read_attributes(module_node)
|
||||
Print.verbose " #{module_node.name} (#{module_selector.unique_id}), selecting based on:"
|
||||
module_selector.attributes.each do |attr|
|
||||
if attr[0] && attr[1] && attr[0].to_s != "module_type"
|
||||
|
||||
@@ -3,52 +3,27 @@ require 'digest'
|
||||
|
||||
require_relative '../objects/system'
|
||||
require_relative '../objects/module'
|
||||
require_relative 'xml_reader.rb'
|
||||
|
||||
class SystemReader
|
||||
class SystemReader < XMLReader
|
||||
|
||||
# uses nokogiri to extract all system information from scenario.xml
|
||||
# This includes module filters, which are module objects that contain filters for selecting
|
||||
# from the actual modules that are available
|
||||
# @return [Array] Array containing Systems objects
|
||||
def self.read_scenario(scenario_file)
|
||||
def self.read_scenario(scenario_file, options)
|
||||
systems = []
|
||||
Print.verbose "Reading scenario file: #{scenario_file}"
|
||||
doc, xsd = nil
|
||||
begin
|
||||
doc = Nokogiri::XML(File.read(scenario_file))
|
||||
rescue
|
||||
Print.err "Failed to read scenario configuration file (#{scenario_file})"
|
||||
exit
|
||||
end
|
||||
|
||||
# validate scenario XML against schema
|
||||
begin
|
||||
xsd = Nokogiri::XML::Schema(File.open(SCENARIO_SCHEMA_FILE))
|
||||
xsd.validate(scenario_file).each do |error|
|
||||
Print.err "Error in scenario configuration file (#{scenario_file}):"
|
||||
Print.err " #{error.line}: #{error.message}"
|
||||
exit
|
||||
end
|
||||
rescue Exception => e
|
||||
Print.err "Failed to validate scenario configuration file (#{scenario_file}): against schema (#{SCENARIO_SCHEMA_FILE})"
|
||||
Print.err e.message
|
||||
exit
|
||||
end
|
||||
|
||||
# remove xml namespaces for ease of processing
|
||||
doc.remove_namespaces!
|
||||
# Parse and validate the schema
|
||||
doc = parse_doc(scenario_file, SCENARIO_SCHEMA_FILE, 'scenario')
|
||||
|
||||
doc.xpath('/scenario/system').each_with_index do |system_node, system_index|
|
||||
module_selectors = []
|
||||
system_attributes = {}
|
||||
|
||||
system_name = system_node.at_xpath('system_name').text
|
||||
Print.verbose "system: #{system_name}"
|
||||
|
||||
# system attributes, such as basebox selection
|
||||
system_node.xpath('@*').each do |attr|
|
||||
system_attributes["#{attr.name}"] = attr.text unless attr.text.nil? || attr.text == ''
|
||||
end
|
||||
system_attributes = read_attributes(system_node)
|
||||
|
||||
# literal values to store directly in a datastore
|
||||
system_node.xpath('*[@into_datastore]/value').each do |value|
|
||||
@@ -146,9 +121,28 @@ class SystemReader
|
||||
end
|
||||
|
||||
end
|
||||
systems << System.new(system_name, system_attributes, module_selectors)
|
||||
|
||||
# Create new system object before reading goals as we need the hostname
|
||||
system = System.new(system_name, system_attributes, module_selectors, scenario_file, options)
|
||||
|
||||
# Parse goals
|
||||
system_node.xpath("goals").each do |goals_doc|
|
||||
goals_doc.elements.each {|node|
|
||||
goal_type = node.name
|
||||
goal_hash = {'goal_type' => goal_type, }
|
||||
node.children.each {|subnode|
|
||||
unless subnode.text?
|
||||
goal_hash.merge!({subnode.name => subnode.content.strip})
|
||||
end
|
||||
}
|
||||
goal_hash.merge!({'hostname' => system.get_hostname}) unless goal_hash.has_key? 'hostname'
|
||||
system.goals << goal_hash
|
||||
}
|
||||
end
|
||||
|
||||
systems << system
|
||||
end
|
||||
|
||||
return systems
|
||||
end
|
||||
end
|
||||
end
|
||||
49
lib/readers/xml_reader.rb
Normal file
49
lib/readers/xml_reader.rb
Normal file
@@ -0,0 +1,49 @@
|
||||
require 'nokogiri'
|
||||
require 'digest'
|
||||
|
||||
class XMLReader
|
||||
|
||||
# uses nokogiri to extract all system information from scenario.xml
|
||||
# This includes module filters, which are module objects that contain filters for selecting
|
||||
# from the actual modules that are available
|
||||
# @return [Array] Array containing Systems objects
|
||||
|
||||
def self.parse_doc(file_path, schema, type)
|
||||
doc = nil
|
||||
begin
|
||||
doc = Nokogiri::XML(File.read(file_path))
|
||||
rescue
|
||||
Print.err "Failed to read #{type} configuration file (#{file_path})"
|
||||
exit
|
||||
end
|
||||
validate_xml(doc, file_path, schema, type)
|
||||
# remove xml namespaces for ease of processing
|
||||
doc.remove_namespaces!
|
||||
end
|
||||
|
||||
def self.validate_xml(doc, file_path, schema, type)
|
||||
# validate XML against schema
|
||||
begin
|
||||
xsd = Nokogiri::XML::Schema(File.open(schema))
|
||||
xsd.validate(doc).each do |error|
|
||||
Print.err "Error in #{type} configuration file (#{file_path}):"
|
||||
Print.err ' ' + error.message
|
||||
exit
|
||||
end
|
||||
rescue Exception => e
|
||||
Print.err "Failed to validate #{type} xml file (#{file_path}): against schema (#{schema})"
|
||||
Print.err e.message
|
||||
exit
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def self.read_attributes(node)
|
||||
attributes = {}
|
||||
node.xpath('@*').each do |attr|
|
||||
attributes["#{attr.name}"] = [attr.text] unless attr.text.nil? || attr.text == ''
|
||||
end
|
||||
attributes
|
||||
end
|
||||
|
||||
end
|
||||
114
lib/schemas/alertactioner_config_schema.xsd
Normal file
114
lib/schemas/alertactioner_config_schema.xsd
Normal file
@@ -0,0 +1,114 @@
|
||||
<?xml version="1.0"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.github/cliffe/SecGen/alertactioner_config"
|
||||
xmlns="http://www.github/cliffe/SecGen/alertactioner_config"
|
||||
elementFormDefault="qualified">
|
||||
<xs:element name="alertactioner">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name='alertaction' type='AlertActionType' minOccurs='1' maxOccurs='unbounded' />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:complexType name="AlertActionType">
|
||||
<xs:sequence>
|
||||
<xs:element name="alert_name" minOccurs="1" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[a-zA-Z0-9_\-]+"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="WebAction" type="WebActionType" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:element name="MessageAction" type="MessageActionType" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:element name="VirtAction" type="VirtActionType" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:element name="VirtAddNICAction" type="VirtAddNICActionType" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:element name="VirtRemoveNICAction" type="VirtRemoveNICActionType" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:element name="VirtAddDiskAction" type="VirtAddDiskActionType" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:element name="VirtRemoveDiskAction" type="VirtRemoveDiskActionType" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:element name="VMCommandAction" type="CommandActionType" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xs:element name="IRCAction" type="xs:string" minOccurs="1" maxOccurs="unbounded" />
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="WebActionType">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="target" type="xs:anyURI" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="request_type" minOccurs="1" maxOccurs="1" >
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="GET"/>
|
||||
<xs:enumeration value="POST"/>
|
||||
<xs:enumeration value="PUT"/>
|
||||
<xs:enumeration value="DELETE"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="data" type="xs:string" minOccurs="0" maxOccurs="1"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="CommandActionType">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="host" type="xs:anyURI" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="username" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="password" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="command_string" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="MessageActionType">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="host" type="xs:anyURI" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="sender" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="password" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="recipient" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="message_header" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="message_subtext" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="VirtActionType">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="virt_config" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="vm_name" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="command_string" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="VirtAddNICActionType">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="virt_config" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="vm_name" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="network_name" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="VirtRemoveNICActionType">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="virt_config" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="vm_name" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="network_name" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="VirtAddDiskActionType">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="virt_config" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="vm_name" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="disk_alias" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="VirtRemoveDiskActionType">
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="virt_config" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="vm_name" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
<xs:element name="disk_alias" type="xs:string" minOccurs="1" maxOccurs="1"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
|
||||
</xs:schema>
|
||||
@@ -70,6 +70,41 @@
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
|
||||
<xs:complexType name="GoalsType">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name='read_file' minOccurs='0' maxOccurs='unbounded' >
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name='file_path' type='xs:string' minOccurs="1" maxOccurs="1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name='modify_file' minOccurs='0' maxOccurs='unbounded' >
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name='file_path' type='xs:string' minOccurs="1" maxOccurs="unbounded"/>
|
||||
<!-- file_contents: either a hash or regexp to match -->
|
||||
<xs:element name='file_contents' type='xs:string' minOccurs="0" maxOccurs="unbounded"/>
|
||||
<!-- written_by: include username or uid range (e.g. uid>=1000) -->
|
||||
<xs:element name='written_by' type='xs:string' minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name='access_account' minOccurs='0' maxOccurs='unbounded' >
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name='account_name' type='xs:string' minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name='service_down' type='xs:string' minOccurs='0' maxOccurs='unbounded' />
|
||||
<xs:element name='system_down' type='xs:string' minOccurs='0' maxOccurs='unbounded' />
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="SystemType">
|
||||
<xs:sequence>
|
||||
<xs:element name="system_name" minOccurs="1" maxOccurs="1">
|
||||
@@ -81,6 +116,7 @@
|
||||
</xs:element>
|
||||
<xs:element name='base' type='BaseType' minOccurs='1' maxOccurs='1' />
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="goals" type="GoalsType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="input" type="InputElements" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name='vulnerability' type='VulnerabilityType' minOccurs='0' maxOccurs='unbounded' />
|
||||
<xs:element name='service' type='ServiceUtilityBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
|
||||
@@ -103,6 +139,7 @@
|
||||
<xs:attribute name='distro' type='xs:string'/>
|
||||
<xs:attribute name='url' type='xs:string'/>
|
||||
<xs:attribute name='vagrantbase' type='xs:string'/>
|
||||
<xs:attribute name='esxi_url' type='xs:string'/>
|
||||
<xs:attribute name='ovirt_template' type='xs:string'/>
|
||||
<xs:attribute name='reference' type='xs:string'/>
|
||||
<xs:attribute name='software_license' type='xs:string'/>
|
||||
|
||||
@@ -93,6 +93,45 @@
|
||||
<xs:enumeration value="base64"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="GoalsType">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name='read_file' minOccurs='0' maxOccurs='unbounded' >
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<!-- Hostname automatically populated from module goals -->
|
||||
<xs:element name='hostname' type='xs:string' minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name='file_path' type='xs:string' minOccurs="1" maxOccurs="1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name='modify_file' minOccurs='0' maxOccurs='unbounded' >
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<!-- Hostname automatically populated from module goals -->
|
||||
<xs:element name='hostname' type='xs:string' minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name='file_path' type='xs:string' minOccurs="1" maxOccurs="unbounded"/>
|
||||
<!-- file_contents: either a hash or regexp to match -->
|
||||
<xs:element name='file_contents' type='xs:string' minOccurs="0" maxOccurs="unbounded"/>
|
||||
<!-- written_by: include username or uid range (e.g. uid>=1000) -->
|
||||
<xs:element name='written_by' type='xs:string' minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name='access_account' minOccurs='0' maxOccurs='unbounded' >
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<!-- Hostname automatically populated from module goals -->
|
||||
<xs:element name='hostname' type='xs:string' minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name='account_name' type='xs:string' minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name='service_down' type='xs:string' minOccurs='0' maxOccurs='unbounded' />
|
||||
<xs:element name='system_down' type='xs:string' minOccurs='0' maxOccurs='unbounded' />
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="InputElements">
|
||||
<xs:sequence>
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
@@ -129,6 +168,7 @@
|
||||
<xs:attribute name="challenge_type" type="xs:string"/>
|
||||
<xs:attribute name="challenge_subtype" type="xs:string"/>
|
||||
<xs:attribute name="difficulty" type="xs:string"/>
|
||||
<xs:attribute name="goals" type="xs:string"/>
|
||||
|
||||
<!--optional vulnerability inputs-->
|
||||
<xs:attribute name="read_fact" type="xs:string"/>
|
||||
@@ -205,6 +245,7 @@
|
||||
<xs:element name="challenge_type" type="challengeTypeOptions" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="challenge_subtype" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="difficulty" type="difficultyOptions" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="goals" type="GoalsType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
|
||||
<!--optional input values-->
|
||||
<xs:element name="read_fact" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
forge "https://forgeapi.puppetlabs.com"
|
||||
|
||||
mod 'puppetlabs-stdlib', '4.24.0' # stdlib enables parsejson() in manifests and other useful functions
|
||||
mod 'puppetlabs-stdlib', '4.25.1' # stdlib enables parsejson() in manifests and other useful functions
|
||||
mod 'puppetlabs-concat', '5.2.0'
|
||||
mod 'puppetlabs-vcsrepo', '2.0.0'
|
||||
mod 'puppetlabs-apt', '7.4.0' # pin apt to 7.4.0 as current version is incompatible with our base boxes
|
||||
mod 'SecGen-secgen_functions', :path => '<%= SECGEN_FUNCTIONS_PUPPET_DIR %>'
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
# Based on <%= @scenario %>
|
||||
<% require 'json'
|
||||
require 'base64'
|
||||
require 'securerandom' -%>
|
||||
require 'securerandom'
|
||||
require_relative './lib/helpers/scenario.rb'-%>
|
||||
<% scenario_name = @scenario.split('/').last.split('.').first + '-'
|
||||
prefix = @options[:prefix] ? (@options[:prefix] + '-' + scenario_name) : ('SecGen-' + scenario_name) -%>
|
||||
|
||||
@@ -28,7 +29,8 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
end
|
||||
end
|
||||
end
|
||||
end -%>
|
||||
end
|
||||
system.memory = resolve_memory(system) -%>
|
||||
config.vm.define "<%= system.name %>" do |<%= system.name %>|
|
||||
<% if (@options.has_key? :ovirtuser) && (@options.has_key? :ovirtpass) %>
|
||||
#oVirt provider begin
|
||||
@@ -44,13 +46,12 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
end %>
|
||||
<%=
|
||||
" ovirt.template = '#{@ovirt_base_template}'" %>
|
||||
<%= if @options.has_key? :memory_per_vm
|
||||
" ovirt.memory_size = '#{@options[:memory_per_vm]} MB'\n"
|
||||
elsif @options.has_key? :total_memory
|
||||
" ovirt.memory_size = '#{(@options[:total_memory].to_i / @systems.length.to_i)} MB'\n"
|
||||
else
|
||||
" ovirt.memory_size = '3000 MB'
|
||||
ovirt.memory_guaranteed = '512 MB'\n"
|
||||
<%=
|
||||
" ovirt.memory_size = '#{system.memory} MB'\n" -%>
|
||||
<%= if @base_type.include? 'desktop'
|
||||
" ovirt.memory_guaranteed = '512 MB'\n"
|
||||
elsif system.memory.to_i >= 4096
|
||||
" ovirt.memory_guaranteed = '4096 MB'\n"
|
||||
end -%>
|
||||
<%= if @options.has_key? :cpu_cores
|
||||
" ovirt.cpu_cores = #{@options[:cpu_cores]}\n"
|
||||
@@ -77,9 +78,8 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
<%= if @options.has_key? :esxi_disktype
|
||||
" esxi.guest_disk_type = '#{@options[:esxi_disktype]}'"
|
||||
end -%>
|
||||
<%= if @options.has_key? :memory_per_vm
|
||||
" esxi.guest_memsize = '#{@options[:memory_per_vm]}'"
|
||||
end -%>
|
||||
<%= " esxi.guest_memsize = '#{system.memory} MB'\n"
|
||||
-%>
|
||||
<%= if @options.has_key? :cpu_cores
|
||||
" esxi.guest_numvcpus = #{@options[:cpu_cores]}\n"
|
||||
end -%>
|
||||
@@ -87,7 +87,7 @@ end
|
||||
# End ESXi provider
|
||||
<%
|
||||
else %>
|
||||
config.vm.provider :virtualbox do |vb|
|
||||
<%= system.name %>.vm.provider :virtualbox do |vb|
|
||||
<% system.module_selections.each do |selected_module|
|
||||
if selected_module.module_type == 'base'
|
||||
@cpu_word_size = selected_module.attributes['cpu_word_size'].first.downcase
|
||||
@@ -108,11 +108,7 @@ end
|
||||
end -%>
|
||||
<%= vtxpid = (@options.has_key? :vtxvpid) ? 'on' : 'off'
|
||||
" vb.customize ['modifyvm', :id, '--vtxvpid', '#{vtxpid}']\n" -%>
|
||||
<%= if @options.has_key? :memory_per_vm
|
||||
" vb.memory = #{@options[:memory_per_vm]}\n"
|
||||
elsif @options.has_key? :total_memory
|
||||
" vb.memory = #{@options[:total_memory]}/#{@systems.length}\n"
|
||||
end -%>
|
||||
<%= " vb.memory = '#{system.memory}'\n"-%>
|
||||
<%= if @options.has_key? :cpu_cores
|
||||
" vb.cpus = #{@options[:cpu_cores]}\n"
|
||||
end -%>
|
||||
@@ -144,12 +140,12 @@ end
|
||||
<% if (@options.has_key? :ovirtuser) && (@options.has_key? :ovirtpass) %> # TODO
|
||||
<%# if selected_module.attributes['platform'].first.downcase != 'windows' %>
|
||||
<%# gets stuck setting host name on Windows XP %>
|
||||
<%= system.name %>.vm.hostname = '<%= "#{prefix}#{system.name}".tr('_', '-') %>'
|
||||
<%= system.name %>.vm.hostname = '<%= system.get_hostname %>'
|
||||
<%# end %>
|
||||
<%= system.name %>.vm.box = 'ovirt4'
|
||||
<%= system.name %>.vm.box_url = 'https://github.com/myoung34/vagrant-ovirt4/blob/master/example_box/dummy.box?raw=true'
|
||||
<% elsif (@options.has_key? :esxiuser) && (@options.has_key? :esxipass) %>
|
||||
<%= system.name %>.vm.hostname = '<%= "#{prefix}#{system.name}".tr('_', '-') %>'
|
||||
<%= system.name %>.vm.hostname = '<%= system.get_hostname %>'
|
||||
<%= system.name %>.vm.box = "<%= selected_module.module_path_name %>"
|
||||
<%= system.name %>.vm.box_url = "<%= selected_module.attributes['esxi_url'].first %>"
|
||||
<% else %>
|
||||
@@ -219,7 +215,9 @@ end
|
||||
<% end -%>
|
||||
<%=module_name%>.module_path = "<%="puppet/#{system.name}/modules"%>"
|
||||
<% if selected_module.attributes['platform'].first.downcase != 'windows' %>
|
||||
<%=module_name%>.options = "--disable_warnings=deprecations"
|
||||
<%=module_name%>.environment_path = "environments/"
|
||||
<%=module_name%>.environment_variables = {'RUBYOPT' => '-W0'}
|
||||
<%=module_name%>.environment = "production"
|
||||
<%=module_name%>.synced_folder_type = "rsync"
|
||||
<% end %>
|
||||
|
||||
1
lib/templates/auditbeat_goal_rules.erb
Normal file
1
lib/templates/auditbeat_goal_rules.erb
Normal file
@@ -0,0 +1 @@
|
||||
<%= @rules.join("\n")%>
|
||||
2
lib/templates/elastalert_goal_rules.erb
Normal file
2
lib/templates/elastalert_goal_rules.erb
Normal file
@@ -0,0 +1,2 @@
|
||||
<% require './lib/helpers/rules' -%>
|
||||
<%= Rules.generate_elastalert_rule(@hostname, @module_name, @goal, @counter) %>
|
||||
@@ -91,7 +91,7 @@ def generate_scenarios(selected_base)
|
||||
module_selections << mod
|
||||
module_selections << get_network_module
|
||||
|
||||
system = System.new(system_name, {}, [])
|
||||
system = System.new(system_name, {}, [], 'testing.xml', {} )
|
||||
system.module_selections = module_selections
|
||||
|
||||
xml_generator = XmlScenarioGenerator.new([system], system_name, Time.new.to_s)
|
||||
|
||||
227
modules/build/unix/swap_file/CHANGELOG.md
Normal file
227
modules/build/unix/swap_file/CHANGELOG.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [v4.0.0](https://github.com/petems/petems-swap_file/tree/v4.0.0) (2017-07-09)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v3.1.4...v4.0.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Push v3.1.3 to Forge [\#72](https://github.com/petems/petems-swap_file/issues/72)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Linting fixes [\#76](https://github.com/petems/petems-swap_file/pull/76) ([petems](https://github.com/petems))
|
||||
- Update metadata.json [\#75](https://github.com/petems/petems-swap_file/pull/75) ([petems](https://github.com/petems))
|
||||
- Fixes issue with empty fact [\#74](https://github.com/petems/petems-swap_file/pull/74) ([petems](https://github.com/petems))
|
||||
- Update to Augeas systcl module [\#73](https://github.com/petems/petems-swap_file/pull/73) ([antyale](https://github.com/antyale))
|
||||
|
||||
## [v3.1.4](https://github.com/petems/petems-swap_file/tree/v3.1.4) (2017-02-22)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v3.1.3...v3.1.4)
|
||||
|
||||
## [v3.1.3](https://github.com/petems/petems-swap_file/tree/v3.1.3) (2017-02-22)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v3.0.2...v3.1.3)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fixes Travis [\#71](https://github.com/petems/petems-swap_file/pull/71) ([petems](https://github.com/petems))
|
||||
- Make json file RFC 4627 valid [\#70](https://github.com/petems/petems-swap_file/pull/70) ([greglint](https://github.com/greglint))
|
||||
- Change to use vagrant-libvirt over custom [\#69](https://github.com/petems/petems-swap_file/pull/69) ([petems](https://github.com/petems))
|
||||
- Add testing for custom Vagrantfile [\#68](https://github.com/petems/petems-swap_file/pull/68) ([petems](https://github.com/petems))
|
||||
- Add basic Jenkinsfile [\#67](https://github.com/petems/petems-swap_file/pull/67) ([petems](https://github.com/petems))
|
||||
- Set seltype for swapfile [\#66](https://github.com/petems/petems-swap_file/pull/66) ([petems](https://github.com/petems))
|
||||
|
||||
## [v3.0.2](https://github.com/petems/petems-swap_file/tree/v3.0.2) (2016-08-07)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v3.0.1...v3.0.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Directory not empty @ dir\_s\_rmdir [\#63](https://github.com/petems/petems-swap_file/issues/63)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fix error in documentation [\#64](https://github.com/petems/petems-swap_file/pull/64) ([petems](https://github.com/petems))
|
||||
|
||||
## [v3.0.1](https://github.com/petems/petems-swap_file/tree/v3.0.1) (2016-05-26)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v3.0.0...v3.0.1)
|
||||
|
||||
## [v3.0.0](https://github.com/petems/petems-swap_file/tree/v3.0.0) (2016-05-26)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v2.5.0...v3.0.0)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Updating the module to latest version will create additional fstab entries for the same swapfile [\#20](https://github.com/petems/petems-swap_file/issues/20)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Type and provider refactor [\#15](https://github.com/petems/petems-swap_file/pull/15) ([petems](https://github.com/petems))
|
||||
|
||||
## [v2.5.0](https://github.com/petems/petems-swap_file/tree/v2.5.0) (2016-05-24)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v2.4.1...v2.5.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Adds ability set swappiness with the module [\#62](https://github.com/petems/petems-swap_file/pull/62) ([petems](https://github.com/petems))
|
||||
|
||||
## [v2.4.1](https://github.com/petems/petems-swap_file/tree/v2.4.1) (2016-05-11)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v2.4.0...v2.4.1)
|
||||
|
||||
## [v2.4.0](https://github.com/petems/petems-swap_file/tree/v2.4.0) (2016-05-11)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v2.3.0...v2.4.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Create workaround for stringify\_facts true [\#57](https://github.com/petems/petems-swap_file/issues/57)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Cannot change size of existing swap file [\#13](https://github.com/petems/petems-swap_file/issues/13)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Allows removing existing swap from a CSV fact [\#61](https://github.com/petems/petems-swap_file/pull/61) ([petems](https://github.com/petems))
|
||||
- Add a swapfile fact as a CSV [\#60](https://github.com/petems/petems-swap_file/pull/60) ([petems](https://github.com/petems))
|
||||
|
||||
## [v2.3.0](https://github.com/petems/petems-swap_file/tree/v2.3.0) (2016-05-04)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v2.2.2...v2.3.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Update CHANGELOG with 2.2.2 changes [\#45](https://github.com/petems/petems-swap_file/issues/45)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Move coverage shim to spec\_helper [\#59](https://github.com/petems/petems-swap_file/pull/59) ([petems](https://github.com/petems))
|
||||
- Update main class documentation [\#58](https://github.com/petems/petems-swap_file/pull/58) ([petems](https://github.com/petems))
|
||||
- Add older listen gem for older Ruby versions [\#56](https://github.com/petems/petems-swap_file/pull/56) ([petems](https://github.com/petems))
|
||||
- New feature: resizing existing swapfiles [\#55](https://github.com/petems/petems-swap_file/pull/55) ([petems](https://github.com/petems))
|
||||
- Linting fixes in examples [\#54](https://github.com/petems/petems-swap_file/pull/54) ([petems](https://github.com/petems))
|
||||
- Updates swap file fact to only show swap files [\#53](https://github.com/petems/petems-swap_file/pull/53) ([petems](https://github.com/petems))
|
||||
- Make things a little less strict [\#52](https://github.com/petems/petems-swap_file/pull/52) ([petems](https://github.com/petems))
|
||||
- Renaming sizes fact [\#51](https://github.com/petems/petems-swap_file/pull/51) ([petems](https://github.com/petems))
|
||||
- Add contributing.json \(GitMagic\) [\#49](https://github.com/petems/petems-swap_file/pull/49) ([gitmagic-bot](https://github.com/gitmagic-bot))
|
||||
- Update stdlib versions [\#48](https://github.com/petems/petems-swap_file/pull/48) ([petems](https://github.com/petems))
|
||||
- Adding a fact to show you swap file sizes [\#47](https://github.com/petems/petems-swap_file/pull/47) ([petems](https://github.com/petems))
|
||||
|
||||
## [v2.2.2](https://github.com/petems/petems-swap_file/tree/v2.2.2) (2016-04-03)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v2.2.1...v2.2.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Created file size is incorrect [\#43](https://github.com/petems/petems-swap_file/issues/43)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fixes MB size accuracy [\#44](https://github.com/petems/petems-swap_file/pull/44) ([petems](https://github.com/petems))
|
||||
|
||||
## [v2.2.1](https://github.com/petems/petems-swap_file/tree/v2.2.1) (2016-02-16)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v2.2.0...v2.2.1)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Move to petems-swap\_file [\#42](https://github.com/petems/petems-swap_file/pull/42) ([petems](https://github.com/petems))
|
||||
- Make testing matrix a little simpler... [\#41](https://github.com/petems/petems-swap_file/pull/41) ([petems](https://github.com/petems))
|
||||
|
||||
## [v2.2.0](https://github.com/petems/petems-swap_file/tree/v2.2.0) (2016-02-15)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v2.1.0...v2.2.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Module should be tested on multiple Ruby and Puppet versions [\#38](https://github.com/petems/petems-swap_file/issues/38)
|
||||
- Release version 2.1.0 on Puppet Forge [\#36](https://github.com/petems/petems-swap_file/issues/36)
|
||||
- dd vs fallocate [\#26](https://github.com/petems/petems-swap_file/issues/26)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Wrapper [\#40](https://github.com/petems/petems-swap_file/pull/40) ([Phil-Friderici](https://github.com/Phil-Friderici))
|
||||
- Modernize Travis setup [\#39](https://github.com/petems/petems-swap_file/pull/39) ([Phil-Friderici](https://github.com/Phil-Friderici))
|
||||
- Satisfy puppet-lint [\#37](https://github.com/petems/petems-swap_file/pull/37) ([Phil-Friderici](https://github.com/Phil-Friderici))
|
||||
|
||||
## [v2.1.0](https://github.com/petems/petems-swap_file/tree/v2.1.0) (2015-12-30)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v2.0.0...v2.1.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Missing 2.0.0 tag [\#24](https://github.com/petems/petems-swap_file/issues/24)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Adds `cmd` parameter. [\#35](https://github.com/petems/petems-swap_file/pull/35) ([petems](https://github.com/petems))
|
||||
- Updating Beaker acceptance machines [\#34](https://github.com/petems/petems-swap_file/pull/34) ([petems](https://github.com/petems))
|
||||
- Enable travis docker [\#32](https://github.com/petems/petems-swap_file/pull/32) ([petems](https://github.com/petems))
|
||||
- Adds spec.opts file [\#31](https://github.com/petems/petems-swap_file/pull/31) ([petems](https://github.com/petems))
|
||||
- Add cmd param [\#29](https://github.com/petems/petems-swap_file/pull/29) ([petems](https://github.com/petems))
|
||||
- Added timeout parameter for exec when using dd [\#27](https://github.com/petems/petems-swap_file/pull/27) ([petems](https://github.com/petems))
|
||||
|
||||
## [v2.0.0](https://github.com/petems/petems-swap_file/tree/v2.0.0) (2015-07-27)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v1.1.1...v2.0.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- swap\_file::files fails when you set the ensure attribute to absent [\#21](https://github.com/petems/petems-swap_file/issues/21)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Remove Class for Swap file [\#23](https://github.com/petems/petems-swap_file/pull/23) ([petems](https://github.com/petems))
|
||||
- Fix: exec contains swapfile name when absent [\#22](https://github.com/petems/petems-swap_file/pull/22) ([juame](https://github.com/juame))
|
||||
- Update README.markdown [\#18](https://github.com/petems/petems-swap_file/pull/18) ([yalcinsurkultay](https://github.com/yalcinsurkultay))
|
||||
|
||||
## [v1.1.1](https://github.com/petems/petems-swap_file/tree/v1.1.1) (2015-03-17)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v1.1.0...v1.1.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- mount resource should be unique [\#14](https://github.com/petems/petems-swap_file/issues/14)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Add defined type for swap and give unique names [\#16](https://github.com/petems/petems-swap_file/pull/16) ([petems](https://github.com/petems))
|
||||
|
||||
## [v1.1.0](https://github.com/petems/petems-swap_file/tree/v1.1.0) (2015-03-17)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v1.0.1...v1.1.0)
|
||||
|
||||
## [v1.0.1](https://github.com/petems/petems-swap_file/tree/v1.0.1) (2015-01-17)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v1.0.0...v1.0.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Not issue, ask a question [\#11](https://github.com/petems/petems-swap_file/issues/11)
|
||||
- missed "default" in fstab [\#5](https://github.com/petems/petems-swap_file/issues/5)
|
||||
- Docker Beaker tests always fail [\#4](https://github.com/petems/petems-swap_file/issues/4)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fix License code [\#12](https://github.com/petems/petems-swap_file/pull/12) ([petems](https://github.com/petems))
|
||||
- Add FreeBSD tests [\#10](https://github.com/petems/petems-swap_file/pull/10) ([petems](https://github.com/petems))
|
||||
- Swap fstab settings [\#8](https://github.com/petems/petems-swap_file/pull/8) ([petems](https://github.com/petems))
|
||||
- Fixes to swapfile permissions and to implied OS support [\#7](https://github.com/petems/petems-swap_file/pull/7) ([mattock](https://github.com/mattock))
|
||||
|
||||
## [v1.0.0](https://github.com/petems/petems-swap_file/tree/v1.0.0) (2014-09-24)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v0.3.0...v1.0.0)
|
||||
|
||||
## [v0.3.0](https://github.com/petems/petems-swap_file/tree/v0.3.0) (2014-09-01)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v0.2.0...v0.3.0)
|
||||
|
||||
## [v0.2.0](https://github.com/petems/petems-swap_file/tree/v0.2.0) (2014-09-01)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/0.3.0...v0.2.0)
|
||||
|
||||
## [0.3.0](https://github.com/petems/petems-swap_file/tree/0.3.0) (2014-09-01)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/0.2.0...0.3.0)
|
||||
|
||||
## [0.2.0](https://github.com/petems/petems-swap_file/tree/0.2.0) (2014-08-22)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v0.1.2...0.2.0)
|
||||
|
||||
## [v0.1.2](https://github.com/petems/petems-swap_file/tree/v0.1.2) (2014-05-29)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v0.1.1...v0.1.2)
|
||||
|
||||
## [v0.1.1](https://github.com/petems/petems-swap_file/tree/v0.1.1) (2014-05-29)
|
||||
[Full Changelog](https://github.com/petems/petems-swap_file/compare/v0.1.0...v0.1.1)
|
||||
|
||||
## [v0.1.0](https://github.com/petems/petems-swap_file/tree/v0.1.0) (2014-02-27)
|
||||
**Merged pull requests:**
|
||||
|
||||
- Removing custom fact for memory size in bytes [\#1](https://github.com/petems/petems-swap_file/pull/1) ([petems](https://github.com/petems))
|
||||
|
||||
|
||||
|
||||
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
||||
83
modules/build/unix/swap_file/CONTRIBUTING.md
Normal file
83
modules/build/unix/swap_file/CONTRIBUTING.md
Normal file
@@ -0,0 +1,83 @@
|
||||
This module has grown over time based on a range of contributions from
|
||||
people using it. If you follow these contributing guidelines your patch
|
||||
will likely make it into a release a little quicker.
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repo.
|
||||
|
||||
2. Run the tests. We only take pull requests with passing tests, and
|
||||
it's great to know that you have a clean slate
|
||||
|
||||
3. Add a test for your change. Only refactoring and documentation
|
||||
changes require no new tests. If you are adding functionality
|
||||
or fixing a bug, please add a test.
|
||||
|
||||
4. Make the test pass.
|
||||
|
||||
5. Push to your fork and submit a pull request.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
The testing and development tools have a bunch of dependencies,
|
||||
all managed by [bundler](http://bundler.io/) according to the
|
||||
[Puppet support matrix](http://docs.puppetlabs.com/guides/platforms.html#ruby-versions).
|
||||
|
||||
By default the tests use a baseline version of Puppet.
|
||||
|
||||
If you have Ruby 2.x or want a specific version of Puppet,
|
||||
you must set an environment variable such as:
|
||||
|
||||
export PUPPET_VERSION="~> 3.2.0"
|
||||
|
||||
Install the dependencies like so...
|
||||
|
||||
bundle install
|
||||
|
||||
## Syntax and style
|
||||
|
||||
The test suite will run [Puppet Lint](http://puppet-lint.com/) and
|
||||
[Puppet Syntax](https://github.com/gds-operations/puppet-syntax) to
|
||||
check various syntax and style things. You can run these locally with:
|
||||
|
||||
bundle exec rake lint
|
||||
bundle exec rake syntax
|
||||
|
||||
## Running the unit tests
|
||||
|
||||
The unit test suite covers most of the code, as mentioned above please
|
||||
add tests if you're adding new functionality. If you've not used
|
||||
[rspec-puppet](http://rspec-puppet.com/) before then feel free to ask
|
||||
about how best to test your new feature. Running the test suite is done
|
||||
with:
|
||||
|
||||
bundle exec rake spec
|
||||
|
||||
Note also you can run the syntax, style and unit tests in one go with:
|
||||
|
||||
bundle exec rake test
|
||||
|
||||
## Integration tests
|
||||
|
||||
The unit tests just check the code runs, not that it does exactly what
|
||||
we want on a real machine. For that we're using
|
||||
[beaker](https://github.com/puppetlabs/beaker).
|
||||
|
||||
This fires up a new virtual machine (using vagrant) and runs a series of
|
||||
simple tests against it after applying the module. You can run this
|
||||
with:
|
||||
|
||||
bundle exec rake acceptance
|
||||
|
||||
This will run the tests on an Ubuntu 12.04 virtual machine. You can also
|
||||
run the integration tests against Centos 6.5 with.
|
||||
|
||||
RS_SET=centos-64-x64 bundle exec rake acceptances
|
||||
|
||||
If you don't want to have to recreate the virtual machine every time you
|
||||
can use `RS_DESTROY=no` and `RS_PROVISION=no`. On the first run you will
|
||||
at least need `RS_PROVISION` set to yes (the default). The Vagrantfile
|
||||
for the created virtual machines will be in `.vagrant/beaker_vagrant_fies`.
|
||||
|
||||
2
modules/build/unix/swap_file/CONTRIBUTORS
Normal file
2
modules/build/unix/swap_file/CONTRIBUTORS
Normal file
@@ -0,0 +1,2 @@
|
||||
Peter Souter (@petems)
|
||||
Matt Dainty (@bodgit)
|
||||
48
modules/build/unix/swap_file/Gemfile
Normal file
48
modules/build/unix/swap_file/Gemfile
Normal file
@@ -0,0 +1,48 @@
|
||||
source 'http://rubygems.org'
|
||||
|
||||
group :test do
|
||||
if puppetversion = ENV['PUPPET_GEM_VERSION']
|
||||
gem 'puppet', puppetversion, :require => false
|
||||
else
|
||||
gem 'puppet', ENV['PUPPET_VERSION'] || '~> 3.8.0'
|
||||
end
|
||||
|
||||
# rspec must be v2 for ruby 1.8.7
|
||||
if RUBY_VERSION >= '1.8.7' and RUBY_VERSION < '1.9'
|
||||
gem 'rspec', '~> 2.0'
|
||||
end
|
||||
|
||||
gem 'json_pure', '<= 2.0.1', :require => false if RUBY_VERSION < '2.0.0'
|
||||
gem 'safe_yaml', '~> 1.0.4'
|
||||
|
||||
gem 'rake'
|
||||
gem 'puppet-lint'
|
||||
gem 'rspec-puppet', :git => 'https://github.com/rodjek/rspec-puppet.git'
|
||||
gem 'puppet-syntax'
|
||||
gem 'puppetlabs_spec_helper'
|
||||
gem 'simplecov'
|
||||
gem 'simplecov-console'
|
||||
gem 'metadata-json-lint'
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'puppet-blacksmith'
|
||||
gem 'rubocop' if RUBY_VERSION >= '2.0.0'
|
||||
gem 'rubocop-rspec', '~> 1.6' if RUBY_VERSION >= '2.3.0'
|
||||
gem 'github_changelog_generator'
|
||||
gem 'activesupport', '< 5'
|
||||
end
|
||||
|
||||
group :system_tests do
|
||||
gem "beaker",
|
||||
:git => 'https://github.com/puppetlabs/beaker',
|
||||
:ref => '3d21e843434a2e65152bd352c653511ddea0ce71',
|
||||
:require => false
|
||||
gem "beaker-rspec",
|
||||
:git => 'https://github.com/puppetlabs/beaker-rspec.git',
|
||||
:ref => 'a617f7bbc3e6ebb6ce49df32749d4ce93cef737d',
|
||||
:require => false
|
||||
gem 'serverspec'
|
||||
gem 'specinfra'
|
||||
end
|
||||
|
||||
5
modules/build/unix/swap_file/Guardfile
Normal file
5
modules/build/unix/swap_file/Guardfile
Normal file
@@ -0,0 +1,5 @@
|
||||
notification :off
|
||||
|
||||
guard 'rake', :task => 'test' do
|
||||
watch(%r{^manifests\/(.+)\.pp$})
|
||||
end
|
||||
24
modules/build/unix/swap_file/Jenkinsfile
vendored
Normal file
24
modules/build/unix/swap_file/Jenkinsfile
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
node { // The "node" directive tells Jenkins to run commands on the same slave.
|
||||
checkout scm
|
||||
|
||||
stage 'Bundle install'
|
||||
|
||||
wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'gnome-terminal']) {
|
||||
sh 'bundle install'
|
||||
}
|
||||
|
||||
stage 'Acceptance Testing'
|
||||
|
||||
env.PUPPET_INSTALL_VERSION = "1.5.2"
|
||||
|
||||
env.PUPPET_INSTALL_TYPE = "agent"
|
||||
|
||||
env.BEAKER_set = "centos-7-x64-vagrant_libvirt"
|
||||
|
||||
print "Beaker Settings will be: ${env.PUPPET_INSTALL_VERSION} ${env.PUPPET_INSTALL_TYPE} ${env.BEAKER_set}"
|
||||
|
||||
wrap([$class: 'AnsiColorBuildWrapper', 'colorMapName': 'gnome-terminal']) {
|
||||
sh 'bundle exec rake acceptance'
|
||||
}
|
||||
|
||||
}
|
||||
202
modules/build/unix/swap_file/LICENSE
Normal file
202
modules/build/unix/swap_file/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
179
modules/build/unix/swap_file/README.markdown
Normal file
179
modules/build/unix/swap_file/README.markdown
Normal file
@@ -0,0 +1,179 @@
|
||||
# swap_file
|
||||
|
||||
[](https://forge.puppetlabs.com/petems/swap_file) [](https://travis-ci.org/petems/petems-swap_file) [](https://forge.puppetlabs.com/petems/swap_file) [](https://forge.puppetlabs.com/petems/swap_file)
|
||||
|
||||
#### Table of Contents
|
||||
|
||||
1. [Overview](#overview)
|
||||
2. [Module Description](#module-description)
|
||||
3. [Setup](#setup)
|
||||
* [What swap_file affects](#what-swap_file-affects)
|
||||
4. [Usage](#usage)
|
||||
5. [Limitations](#limitations)
|
||||
6. [Upgrading from 1.0.1 Release](#upgrading-from-101-release)
|
||||
7. [Development](#development)
|
||||
|
||||
## Overview
|
||||
|
||||
Manage [swap files](http://en.wikipedia.org/wiki/Paging) for your Linux environments. This is based on the gist by @Yggdrasil, with a few changes and added specs.
|
||||
|
||||
## Setup
|
||||
|
||||
### What swap_file affects
|
||||
|
||||
* Creating a swap-file on disk. This uses `dd` by default, but can use `fallocate` optionally for performance reasons. **Note: Using fallocate to create a ZFS file system will fail: https://bugzilla.redhat.com/show_bug.cgi?id=1129205**
|
||||
* Swapfiles on the system
|
||||
* Any mounts of swapfiles
|
||||
|
||||
## Usage
|
||||
|
||||
The simplest use of the module is this:
|
||||
|
||||
```puppet
|
||||
swap_file::files { 'default':
|
||||
ensure => present,
|
||||
}
|
||||
```
|
||||
|
||||
By default, the module it will:
|
||||
|
||||
* create a file using /bin/dd at `/mnt/swap.1` with the default size taken from the `$::memorysize` fact in megabytes (eg. 8GB RAM will create an 8GB swap file)
|
||||
* A `mount` for the swapfile created
|
||||
|
||||
For a custom setup, you can do something like this:
|
||||
|
||||
```puppet
|
||||
swap_file::files { 'tmp file swap':
|
||||
ensure => present,
|
||||
swapfile => '/tmp/swapfile',
|
||||
add_mount => false,
|
||||
}
|
||||
```
|
||||
|
||||
To use `fallocate` for swap file creation instead of `dd`:
|
||||
|
||||
```puppet
|
||||
swap_file::files { 'tmp file swap':
|
||||
ensure => present,
|
||||
swapfile => '/tmp/swapfile',
|
||||
cmd => 'fallocate',
|
||||
}
|
||||
```
|
||||
|
||||
To remove a prexisting swap, you can use ensure absent:
|
||||
|
||||
```puppet
|
||||
swap_file::files { 'tmp file swap':
|
||||
ensure => absent,
|
||||
}
|
||||
```
|
||||
|
||||
To choose the size of the swap file instead of defaulting to memory size:
|
||||
|
||||
```
|
||||
swap_file::files { '5GB Swap':
|
||||
ensure => present,
|
||||
swapfile => '/mnt/swap.5gb',
|
||||
swapfilesize => '5GB',
|
||||
}
|
||||
```
|
||||
|
||||
### hiera
|
||||
You can also use hiera to call this module and set the configuration.
|
||||
|
||||
The simplest use of the module with hiera is this:
|
||||
|
||||
```yaml
|
||||
classes:
|
||||
- swap_file
|
||||
|
||||
swap_file::files:
|
||||
'default':
|
||||
ensure: 'present'
|
||||
```
|
||||
|
||||
This hiera setup will create a file using /bin/dd atr `/mnt/swap.1` with the default size taken from the `$::memorysize` fact and add a `mount` resource for it.
|
||||
|
||||
You can use all customizations mentioned above in hiera like this:
|
||||
|
||||
```yaml
|
||||
classes:
|
||||
- swap_file
|
||||
|
||||
swap_file::files:
|
||||
'custom setup':
|
||||
ensure: 'present'
|
||||
swapfile: '/tmp/swapfile.custom'
|
||||
add_mount: false
|
||||
'use fallocate':
|
||||
swapfile: '/tmp/swapfile.fallocate'
|
||||
cmd: 'fallocate'
|
||||
'remove swap file'
|
||||
ensure: 'absent'
|
||||
swapfile: '/tmp/swapfile.old'
|
||||
```
|
||||
|
||||
This hiera config will respectively:
|
||||
* create a file `/tmp/swapfile.custom` using /bin/dd with the default size taken from the `$::memorysize` fact without creating a `mount` for it.
|
||||
* create a file `/tmp/swapfile.fallocate` using /usr/bin/fallocate with the default size taken from the `$::memorysize` fact and creating a `mount` for it.
|
||||
* deactivates the swapfile `/tmp/swapfile.old`, deletes it and removes the `mount`.
|
||||
|
||||
Set `$files_hiera_merge` to `true` to merge all found instances of `swap_file::files` in Hiera. This is useful for specifying swap files at different levels of the hierachy and having them all included in the catalog.
|
||||
|
||||
##Upgrading from 1.0.1 Release
|
||||
|
||||
Previously you would create swapfiles with the `swap_file` class:
|
||||
|
||||
```puppet
|
||||
class { 'swap_file':
|
||||
ensure => 'present',
|
||||
}
|
||||
```
|
||||
|
||||
However, this had many problems, such as not being able to declare more than one swap_file because of duplicate class errors.
|
||||
Since 2.x.x the swapfiles are created by a defined type instead. The `swap_file` class is now a wrapper and can handle multiple swap_files.
|
||||
|
||||
You can now use:
|
||||
|
||||
```puppet
|
||||
class { 'swap_file':
|
||||
files => {
|
||||
'freetext resource name' => {
|
||||
ensure => 'present',
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
You can also safely declare mutliple swap file definitions:
|
||||
|
||||
```puppet
|
||||
class { 'swap_file':
|
||||
files => {
|
||||
'swapfile' => {
|
||||
ensure => 'present',
|
||||
},
|
||||
'use fallocate' => {
|
||||
swapfile => '/tmp/swapfile.fallocate',
|
||||
cmd => 'fallocate',
|
||||
},
|
||||
'remove swap file' => {
|
||||
ensure => 'absent',
|
||||
swapfile => '/tmp/swapfile.old',
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
Primary support is for Debian and RedHat, but should work on all Linux flavours.
|
||||
|
||||
Right now there is no BSD support, but I'm planning on adding it in the future
|
||||
|
||||
## Development
|
||||
|
||||
Follow the CONTRIBUTING guidelines! :)
|
||||
50
modules/build/unix/swap_file/Rakefile
Normal file
50
modules/build/unix/swap_file/Rakefile
Normal file
@@ -0,0 +1,50 @@
|
||||
require 'puppetlabs_spec_helper/rake_tasks'
|
||||
require 'puppet-lint/tasks/puppet-lint'
|
||||
require 'puppet-syntax/tasks/puppet-syntax'
|
||||
|
||||
# These two gems aren't always present, for instance
|
||||
# on Travis with --without development
|
||||
begin
|
||||
require 'puppet_blacksmith/rake_tasks'
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
PuppetLint.configuration.fail_on_warnings
|
||||
PuppetLint.configuration.send('relative')
|
||||
PuppetLint.configuration.send('disable_80chars')
|
||||
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
|
||||
PuppetLint.configuration.send('disable_class_parameter_defaults')
|
||||
PuppetLint.configuration.send('disable_documentation')
|
||||
PuppetLint.configuration.send('disable_single_quote_string_with_variables')
|
||||
PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]
|
||||
|
||||
exclude_paths = [
|
||||
"pkg/**/*",
|
||||
"vendor/**/*",
|
||||
"spec/**/*",
|
||||
]
|
||||
PuppetLint.configuration.ignore_paths = exclude_paths
|
||||
PuppetSyntax.exclude_paths = exclude_paths
|
||||
|
||||
desc "Run acceptance tests"
|
||||
RSpec::Core::RakeTask.new(:acceptance) do |t|
|
||||
t.pattern = 'spec/acceptance'
|
||||
end
|
||||
|
||||
desc "Run syntax, lint, and spec tests."
|
||||
task :test => [
|
||||
:syntax,
|
||||
:lint,
|
||||
:spec,
|
||||
]
|
||||
|
||||
begin
|
||||
require 'github_changelog_generator/task'
|
||||
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
|
||||
version = (Blacksmith::Modulefile.new).version
|
||||
config.future_release = "v#{version}"
|
||||
config.header = "# Change Log\n\nAll notable changes to this project will be documented in this file."
|
||||
config.exclude_labels = %w{duplicate question invalid wontfix modulesync}
|
||||
end
|
||||
rescue LoadError
|
||||
end
|
||||
59
modules/build/unix/swap_file/checksums.json
Normal file
59
modules/build/unix/swap_file/checksums.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"CHANGELOG.md": "af03a4842b5bf7236aa28c65f8b415bd",
|
||||
"CONTRIBUTING.md": "ec539f7912da25760720eebf9756ae65",
|
||||
"CONTRIBUTORS": "805eaeecd42f1a06aa564dabc34e8363",
|
||||
"Gemfile": "6f1069b614dee17b2f6e071a7696fedd",
|
||||
"Guardfile": "3ae8d9a61b870350cc1c8e0d6a9a36e7",
|
||||
"Jenkinsfile": "c8514e059beb9914b8797234d3b48f8d",
|
||||
"LICENSE": "47bbee59c4c1cb14cc3667035a227be0",
|
||||
"README.markdown": "139ac4a23749f12812ab9e65a489b9d3",
|
||||
"Rakefile": "cffd8bfb00c0dd7bd704ff87d91febbe",
|
||||
"contributing.json": "8c4b29954f117223992afe35c1cf6f30",
|
||||
"examples/default_swap.pp": "670840e180b371de36892f7acca89b99",
|
||||
"examples/hiera/common.yaml": "9be8ee98915351bc319911ccacb071ae",
|
||||
"examples/hiera/fqdn/merge_disabled.domain.local.yaml": "c22b93ec67481fb46b8752944aaaa735",
|
||||
"examples/hiera/fqdn/merge_enabled.domain.local.yaml": "f610049aeae43645c2fdc8aed7717c4a",
|
||||
"examples/hiera/hiera.yaml": "3b4c8c00535fb4607ea205fc074988ae",
|
||||
"examples/multiple_swaps.pp": "3b3dd90066b87c6a72d4e9f2669f4eac",
|
||||
"lib/facter/swapfile_sizes.rb": "8e6d7a67c0c9efc9a5d2883f439abd80",
|
||||
"lib/facter/swapfile_sizes_csv.rb": "94ada67fdfc1bc5f48a532735b5e74e4",
|
||||
"lib/puppet/parser/functions/difference_within_margin.rb": "13b0312e33d84bdc604c4e32c3f5d5a1",
|
||||
"lib/puppet/parser/functions/swap_file_size_from_csv.rb": "363763881ef81a6eac12308d3397e918",
|
||||
"lib/puppet/provider/swap_file/linux.rb": "f7a238184e72da1d0f95feee21c11252",
|
||||
"lib/puppet/type/swap_file.rb": "6bc034c8a3cf6770c0b8f8a45d201a2b",
|
||||
"manifests/files.pp": "6e8f8904c08fcdab0e3d8b845fb52444",
|
||||
"manifests/init.pp": "b5c294ce0df3a3aa96a47d734e654572",
|
||||
"manifests/resize.pp": "af12fac873d4ca9220b238a7a377e67e",
|
||||
"manifests/swappiness.pp": "4efe89c04267fed6bb055b83c7e15605",
|
||||
"metadata.json": "b7abb8215638788d83a74dd8a8368355",
|
||||
"spec/acceptance/nodesets/Vagrantfile-vagrant_custom": "099c1dccc5b5ea7a1cc37e967e49c4d7",
|
||||
"spec/acceptance/nodesets/centos-6-x64.yml": "c9d4c88230670fd2f26bfec522883574",
|
||||
"spec/acceptance/nodesets/centos-7-x64-vagrant_libvirt.yml": "35389790c6d18c60370b907cee3ef608",
|
||||
"spec/acceptance/nodesets/centos-7-x64.yml": "31c23abc0148831753e5c2a847ccdd11",
|
||||
"spec/acceptance/nodesets/default.yml": "b9deaf5e0afc5216331da177f273a0a9",
|
||||
"spec/acceptance/nodesets/ubuntu-server-12042-x64.yml": "76d8ebcb03ddd64fa7a45909cdee6240",
|
||||
"spec/acceptance/swap_file_class_spec.rb": "e61e478cb58f1efa87d52edc815c961f",
|
||||
"spec/acceptance/swap_file_files_fallocate_command.rb": "32e93f89f7eb6e782af4cf3c24f28fba",
|
||||
"spec/acceptance/swap_file_files_multiple_spec.rb": "b63a30139ede9041dc66f48110faaf38",
|
||||
"spec/acceptance/swap_file_files_parameters_spec.rb": "802f4b14d8a5bcdbb4ec7606531f7f69",
|
||||
"spec/acceptance/swap_file_files_spec.rb": "e8b7145c3efff1174b8d3298449fdc87",
|
||||
"spec/acceptance/swap_file_resizing_spec.rb": "54b43fb9c4f32fcbf1f462ce4f713cf9",
|
||||
"spec/acceptance/swap_file_resizing_stringify_true_spec.rb": "00a753f91f2ac978a973f7eefed8daf5",
|
||||
"spec/acceptance/swap_file_swappiness_spec.rb": "f11e3fe2975a02db6656142d513fd29e",
|
||||
"spec/classes/init_spec.rb": "293d54f4bfa37917e66050816dd9a02e",
|
||||
"spec/classes/swappiness_spec.rb": "b108f36149300bcf060014ea5e29c10f",
|
||||
"spec/defines/files_spec.rb": "db3ddc3ff587054bae16efd9951aa33f",
|
||||
"spec/defines/resize_spec.rb": "ef7b30ea867d0957847f76cf2b576f88",
|
||||
"spec/fixtures/hiera/fqdn/files.yaml": "c09830704075f3cfe71d7baf2b2f0b9d",
|
||||
"spec/fixtures/hiera/hiera.yaml": "beeeeaf9ff2a7848f66cadedb749b184",
|
||||
"spec/fixtures/hiera/parameter_tests/files_hiera_merge.yaml": "cf0173f27f17b20123b9bd514d4549dc",
|
||||
"spec/functions/difference_within_margin_spec.rb": "4c52adfaee7c34b4c554d4a498c375a1",
|
||||
"spec/functions/swap_file_size_from_csv_array_spec.rb": "44e66b9ddc93a01040c3dd459987d2d9",
|
||||
"spec/spec.opts": "841ff248f09ff26ea499e7621d3fef33",
|
||||
"spec/spec_helper.rb": "9617cb9aa81f0152d7a1cd8820c9b9a9",
|
||||
"spec/spec_helper_acceptance.rb": "e0ea4032fe2842e584b5b073eb438aa3",
|
||||
"spec/unit/facter/swapfiles_fact_csv_spec.rb": "d3e855880eb87dffd40013131ab1529e",
|
||||
"spec/unit/facter/swapfiles_fact_spec.rb": "5cfa5e555c58c23070f533f4a56d8933",
|
||||
"spec/unit/puppet/provider/swap_file/linux_spec.rb": "c95f5ca88149a398babaa4f50029fca6",
|
||||
"spec/unit/puppet/type/swap_file/swap_file_spec.rb": "f7696323957041fed2886eb9b24cf255"
|
||||
}
|
||||
32
modules/build/unix/swap_file/contributing.json
Normal file
32
modules/build/unix/swap_file/contributing.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"commit": {
|
||||
"subject_cannot_be_empty": true,
|
||||
"subject_must_be_longer_than": 4,
|
||||
"subject_must_be_shorter_than": 101,
|
||||
"subject_lines_must_be_shorter_than": 51,
|
||||
"subject_must_be_single_line": true,
|
||||
"subject_must_be_in_tense": "imperative",
|
||||
"subject_must_start_with_case": "upper",
|
||||
"subject_must_not_end_with_dot": true,
|
||||
"body_lines_must_be_shorter_than": 73
|
||||
},
|
||||
"pull_request": {
|
||||
"subject_cannot_be_empty": true,
|
||||
"subject_must_be_longer_than": 4,
|
||||
"subject_must_be_shorter_than": 101,
|
||||
"subject_must_be_in_tense": "imperative",
|
||||
"subject_must_start_with_case": "upper",
|
||||
"subject_must_not_end_with_dot": true,
|
||||
"body_cannot_be_empty": true
|
||||
},
|
||||
"issue": {
|
||||
"subject_cannot_be_empty": true,
|
||||
"subject_must_be_longer_than": 4,
|
||||
"subject_must_be_shorter_than": 101,
|
||||
"subject_must_be_in_tense": "imperative",
|
||||
"subject_must_start_with_case": "upper",
|
||||
"subject_must_not_end_with_dot": true,
|
||||
"body_cannot_be_empty": true,
|
||||
"body_must_include_reproduction_steps": true
|
||||
}
|
||||
}
|
||||
5
modules/build/unix/swap_file/examples/default_swap.pp
Normal file
5
modules/build/unix/swap_file/examples/default_swap.pp
Normal file
@@ -0,0 +1,5 @@
|
||||
node default {
|
||||
swap_file::files { 'default':
|
||||
ensure => present,
|
||||
}
|
||||
}
|
||||
12
modules/build/unix/swap_file/examples/hiera/common.yaml
Normal file
12
modules/build/unix/swap_file/examples/hiera/common.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
classes:
|
||||
- swap_file
|
||||
|
||||
swap_file::files:
|
||||
'from_common':
|
||||
ensure: 'present'
|
||||
swapfile: '/mnt/swap.common'
|
||||
|
||||
# This will:
|
||||
# - call the class swap_file
|
||||
# - create a file '/mnt/swap.common' using /bin/dd with the default size taken from the $::memorysizeinbytes and create a mount for it.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
swap_file::files_hiera_merge: false
|
||||
swap_file::files:
|
||||
'from_fqdn':
|
||||
ensure: 'present'
|
||||
swapfile: '/mnt/swap.fqdn'
|
||||
swapfilesize: '2 GB'
|
||||
cmd: 'fallocate'
|
||||
|
||||
# Because files_hiera_merge is set to false, this will create only the swapfiles specified in the most specific hiera level.
|
||||
|
||||
# This will:
|
||||
# - create a file '/mnt/swap.fqdn' using /usr/bin/fallocate with size set to '2 GB' and creates mount for it.
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
swap_file::files_hiera_merge: true
|
||||
swap_file::files:
|
||||
'from_fqdn':
|
||||
ensure: 'present'
|
||||
swapfile: '/mnt/swap.fqdn'
|
||||
swapfilesize: '2 GB'
|
||||
cmd: 'fallocate'
|
||||
|
||||
# Because files_hiera_merge is set to true, this will create all swapfiles specified in different hiera levels.
|
||||
|
||||
# This will:
|
||||
# - create a file '/mnt/swap.common' using /bin/dd with the default size taken from the $::memorysizeinbytes and create a mount for it.
|
||||
# - create a file '/mnt/swap.fqdn' using /usr/bin/fallocate with size set to '2 GB' and creates mount for it.
|
||||
|
||||
|
||||
6
modules/build/unix/swap_file/examples/hiera/hiera.yaml
Normal file
6
modules/build/unix/swap_file/examples/hiera/hiera.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
:backends:
|
||||
- yaml
|
||||
:hierarchy:
|
||||
- fqdn/%{fqdn}
|
||||
- common
|
||||
17
modules/build/unix/swap_file/examples/multiple_swaps.pp
Normal file
17
modules/build/unix/swap_file/examples/multiple_swaps.pp
Normal file
@@ -0,0 +1,17 @@
|
||||
node default {
|
||||
class { '::swap_file':
|
||||
files => {
|
||||
'swapfile' => {
|
||||
ensure => 'present', # lint:ignore:ensure_first_param
|
||||
},
|
||||
'use fallocate' => {
|
||||
swapfile => '/tmp/swapfile.fallocate',
|
||||
cmd => 'fallocate',
|
||||
},
|
||||
'remove swap file' => {
|
||||
ensure => 'absent', # lint:ignore:ensure_first_param
|
||||
swapfile => '/tmp/swapfile.old',
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
34
modules/build/unix/swap_file/lib/facter/swapfile_sizes.rb
Normal file
34
modules/build/unix/swap_file/lib/facter/swapfile_sizes.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
if File.exists?('/proc/swaps')
|
||||
swap_file_hash = {}
|
||||
|
||||
swap_file_output = Facter::Util::Resolution.exec('cat /proc/swaps')
|
||||
|
||||
# Sample Output
|
||||
# Filename Type Size Used Priority
|
||||
# /dev/dm-1 partition 524284 0 -1
|
||||
# /mnt/swap.1 file 204796 0 -2
|
||||
# /tmp/swapfile.fallocate file 204796 0 -3
|
||||
swap_file_output_array = swap_file_output.split("\n")
|
||||
|
||||
# Remove the header line
|
||||
swap_file_output_array.shift
|
||||
|
||||
swap_file_output_array.each do |line|
|
||||
|
||||
swap_file_line_array = line.gsub(/\s+/m, ' ').strip.split(" ")
|
||||
|
||||
# We only want swap-file information, not paritions
|
||||
if swap_file_line_array[1] == 'file'
|
||||
swap_file_hash[swap_file_line_array[0]] = swap_file_line_array[2]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Facter.add('swapfile_sizes') do
|
||||
confine :kernel => 'Linux'
|
||||
setcode do
|
||||
swap_file_hash
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
if File.exists?('/proc/swaps')
|
||||
swap_file_array = []
|
||||
|
||||
swap_file_output = Facter::Util::Resolution.exec('cat /proc/swaps')
|
||||
|
||||
# Sample Output
|
||||
# Filename Type Size Used Priority
|
||||
# /dev/dm-1 partition 524284 0 -1
|
||||
# /mnt/swap.1 file 204796 0 -2
|
||||
# /tmp/swapfile.fallocate file 204796 0 -3
|
||||
swap_file_output_array = swap_file_output.split("\n")
|
||||
|
||||
# Remove the header line
|
||||
swap_file_output_array.shift
|
||||
|
||||
swap_file_output_array.each do |line|
|
||||
|
||||
swap_file_line_array = line.gsub(/\s+/m, ' ').strip.split(" ")
|
||||
|
||||
# We only want swap-file information, not paritions
|
||||
if swap_file_line_array[1] == 'file'
|
||||
pipe_seperated_string = "#{swap_file_line_array[0]}||#{swap_file_line_array[2]}"
|
||||
swap_file_array << pipe_seperated_string
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
swapfile_csv = swap_file_array.join(',') unless swap_file_array.empty?
|
||||
|
||||
Facter.add('swapfile_sizes_csv') do
|
||||
confine :kernel => 'Linux'
|
||||
setcode do
|
||||
swapfile_csv
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,62 @@
|
||||
# When given an array of two numbers and a margin, returns true
|
||||
# if the difference is less than the margin. Basically statistical
|
||||
# range with a margin.
|
||||
#
|
||||
# @example Difference between 150 and 100 is 50, margin is 60. So true
|
||||
# $within_margin = difference_within_margin([100,150],60)
|
||||
#
|
||||
# @example Difference between 150 and 100 is 50, margin is 40. So false
|
||||
# $within_margin = difference_within_margin([100,150],40)
|
||||
#
|
||||
# @return [Boolean] whether the difference between two numbers is within in a margin
|
||||
#
|
||||
# @param num_a [Array] array of two numbers to compare
|
||||
# @param num_b [Float] the margin to compare the two numbers
|
||||
module Puppet::Parser::Functions
|
||||
newfunction(:difference_within_margin, :type => :rvalue, :doc => <<-EOS
|
||||
Get's the difference between two numbers, with a third argument as a margin
|
||||
|
||||
*Example:*
|
||||
|
||||
compare_with_margin(100,150,60)
|
||||
|
||||
Would result in:
|
||||
|
||||
true
|
||||
|
||||
compare_with_margin(100,150,40)
|
||||
|
||||
Would result in:
|
||||
|
||||
false
|
||||
|
||||
EOS
|
||||
) do |arguments|
|
||||
|
||||
# Check that more than 2 arguments have been given ...
|
||||
raise(Puppet::ParseError, "compare_with_margin(): Wrong number of arguments " +
|
||||
"given (#{arguments.size} for 2)") unless arguments.size == 2
|
||||
|
||||
# Check that the first parameter is an array
|
||||
unless arguments[0].is_a?(Array)
|
||||
raise(Puppet::ParseError, 'difference_within_margin(): Requires array to work with')
|
||||
end
|
||||
|
||||
# Check that the first parameter is an array
|
||||
if arguments[0].empty?
|
||||
raise(Puppet::ParseError, 'difference_within_margin(): arg[0] array cannot be empty')
|
||||
end
|
||||
|
||||
arguments[0].collect! { |i| i.to_f }
|
||||
|
||||
difference = arguments[0].minmax[1].to_f - arguments[0].minmax[0].to_f
|
||||
|
||||
if difference < arguments[1].to_f
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# vim: set ts=2 sw=2 et :
|
||||
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# swap_file_size_from_csv.rb
|
||||
#
|
||||
module Puppet::Parser::Functions
|
||||
newfunction(:swap_file_size_from_csv, :type => :rvalue, :doc => <<-EOS
|
||||
Given a csv of swap files and sizes, split by pipe (||), we can determine the size in bytes of the swapfile
|
||||
Will return false if the swapfile is not found in the csv
|
||||
*Examples:*
|
||||
get_swap_file_size_from_csv('/mnt/swap.1','/mnt/swap.1||1019900,/mnt/swap.1||1019900')
|
||||
Would return: 1019900
|
||||
get_swap_file_size_from_csv('/mnt/swap.2','/mnt/swap.1||1019900,/mnt/swap.1||1019900')
|
||||
Would return: false
|
||||
EOS
|
||||
) do |arguments|
|
||||
raise(Puppet::ParseError, "swap_file_size_from_csv(): Wrong number of arguments " +
|
||||
"given (#{arguments.size} for 2)") if arguments.size < 2
|
||||
unless arguments[0].is_a? String
|
||||
raise(Puppet::ParseError, "swap_file_size_from_csv(): swapfile name but be a string (Got #{arguments[0].class}")
|
||||
end
|
||||
unless arguments[1].is_a? String
|
||||
raise(Puppet::ParseError, "swap_file_size_from_csv(): Requires string to work with (Got #{arguments[1].class}")
|
||||
end
|
||||
lines = arguments[1].strip.split(',')
|
||||
|
||||
swapfile_found = false
|
||||
|
||||
lines.each do | swapfile_csv |
|
||||
swapfile_csv_array = swapfile_csv.split(',')
|
||||
swapfile_name = swapfile_csv.split('||')[0]
|
||||
swapfile_size = swapfile_csv.split('||')[1]
|
||||
swapfile_found = swapfile_size if arguments[0] == swapfile_name
|
||||
end
|
||||
swapfile_found
|
||||
end
|
||||
end
|
||||
# vim: set ts=2 sw=2 et :
|
||||
@@ -0,0 +1,113 @@
|
||||
Puppet::Type.type(:swap_file).provide(:linux) do
|
||||
|
||||
desc "Swap file management via `swapon`, `swapoff` and `mkswap`"
|
||||
|
||||
confine :kernel => :linux
|
||||
commands :swapon => 'swapon'
|
||||
commands :swapoff => 'swapoff'
|
||||
commands :mkswap => 'mkswap'
|
||||
|
||||
mk_resource_methods
|
||||
|
||||
def initialize(value={})
|
||||
super(value)
|
||||
@property_flush = {}
|
||||
end
|
||||
|
||||
def self.get_swap_files
|
||||
swapfiles = swapon(['-s']).split("\n")
|
||||
swapfiles.shift
|
||||
swapfiles.sort
|
||||
end
|
||||
|
||||
def self.prefetch(resources)
|
||||
instances.each do |prov|
|
||||
if resource = resources[prov.name]
|
||||
resource.provider = prov
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.instances
|
||||
get_swap_files.collect do |swapfile_line|
|
||||
new(get_swapfile_properties(swapfile_line))
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_swapfile_properties(swapfile_line)
|
||||
swapfile_properties = {}
|
||||
|
||||
# swapon -s output formats thus:
|
||||
# Filename Type Size Used Priority
|
||||
|
||||
# Split on spaces
|
||||
output_array = swapfile_line.strip.split(/\s+/)
|
||||
|
||||
# Assign properties based on headers
|
||||
swapfile_properties = {
|
||||
:ensure => :present,
|
||||
:name => output_array[0],
|
||||
:file => output_array[0],
|
||||
:type => output_array[1],
|
||||
:size => output_array[2],
|
||||
:used => output_array[3],
|
||||
:priority => output_array[4]
|
||||
}
|
||||
|
||||
swapfile_properties[:provider] = :swap_file
|
||||
Puppet.debug "Swapfile: #{swapfile_properties.inspect}"
|
||||
swapfile_properties
|
||||
end
|
||||
|
||||
def exists?
|
||||
@property_hash[:ensure] == :present
|
||||
end
|
||||
|
||||
def create
|
||||
@property_flush[:ensure] = :present
|
||||
end
|
||||
|
||||
def destroy
|
||||
@property_flush[:ensure] = :absent
|
||||
end
|
||||
|
||||
def create_swap_file(file_path)
|
||||
mk_swap(file_path)
|
||||
swap_on(file_path)
|
||||
end
|
||||
|
||||
def mk_swap(file_path)
|
||||
Puppet.debug "Running `mkswap #{file_path}`"
|
||||
output = mkswap([file_path])
|
||||
Puppet.debug "Returned value: #{output}`"
|
||||
end
|
||||
|
||||
def swap_on(file_path)
|
||||
Puppet.debug "Running `swapon #{file_path}`"
|
||||
output = swapon([file_path])
|
||||
Puppet.debug "Returned value: #{output}"
|
||||
end
|
||||
|
||||
def swap_off(file_path)
|
||||
Puppet.debug "Running `swapoff #{file_path}`"
|
||||
output = swapoff([file_path])
|
||||
Puppet.debug "Returned value: #{output}"
|
||||
end
|
||||
|
||||
def set_swapfile
|
||||
if @property_flush[:ensure] == :absent
|
||||
swap_off(resource[:name])
|
||||
return
|
||||
end
|
||||
|
||||
create_swap_file(resource[:name]) unless exists?
|
||||
end
|
||||
|
||||
def flush
|
||||
set_swapfile
|
||||
# Collect the resources again once they've been changed (that way `puppet
|
||||
# resource` will show the correct values after changes have been made).
|
||||
@property_hash = self.class.get_swapfile_properties(resource[:name])
|
||||
end
|
||||
|
||||
end
|
||||
40
modules/build/unix/swap_file/lib/puppet/type/swap_file.rb
Normal file
40
modules/build/unix/swap_file/lib/puppet/type/swap_file.rb
Normal file
@@ -0,0 +1,40 @@
|
||||
Puppet::Type.newtype(:swap_file) do
|
||||
|
||||
ensurable
|
||||
|
||||
desc <<-DOC
|
||||
Used to configure swap files
|
||||
=== Examples
|
||||
|
||||
swap_file { '/mnt/swap.1':
|
||||
ensure => 'present',
|
||||
size => '1068028',
|
||||
}
|
||||
DOC
|
||||
|
||||
@doc = 'Type representing swap files.'
|
||||
|
||||
newparam(:file, :namevar => true) do
|
||||
desc "The file path of the swapfile."
|
||||
validate do |value|
|
||||
fail "file parameter must be a valid absolute path" unless Puppet::Util.absolute_path?(value)
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:type) do
|
||||
desc "The type of the swapfile"
|
||||
end
|
||||
|
||||
newproperty(:size) do
|
||||
desc "The size of the swapfile in bytes"
|
||||
end
|
||||
|
||||
newproperty(:used) do
|
||||
desc "The amount of space used"
|
||||
end
|
||||
|
||||
newproperty(:priority) do
|
||||
desc "The priority of the swapfile"
|
||||
end
|
||||
|
||||
end
|
||||
143
modules/build/unix/swap_file/manifests/files.pp
Normal file
143
modules/build/unix/swap_file/manifests/files.pp
Normal file
@@ -0,0 +1,143 @@
|
||||
# Define: swap_file::files
|
||||
#
|
||||
# This is a defined type to create a swap_file
|
||||
#
|
||||
# == Parameters
|
||||
# [*ensure*]
|
||||
# Allows creation or removal of swapspace and the corresponding file.
|
||||
# [*swapfile*]
|
||||
# Location of swapfile, defaults to /mnt
|
||||
# [*swapfilesize*]
|
||||
# Size of the swapfile as a string (eg. 10 MB, 1.2 GB).
|
||||
# Defaults to $::memorysize fact on the node
|
||||
# [*add_mount*]
|
||||
# Add a mount to the swapfile so it persists on boot
|
||||
# [*options*]
|
||||
# Mount options for the swapfile
|
||||
# [*timeout*]
|
||||
# dd command exec timeout.
|
||||
# Defaults to 300
|
||||
# [*cmd*]
|
||||
# What command is used to create the file, dd or fallocate. dd is better tested and safer but fallocate is significantly faster.
|
||||
# Defaults to dd
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# swap_file::files { 'default':
|
||||
# ensure => present,
|
||||
# swapfile => '/mnt/swap.55',
|
||||
# }
|
||||
#
|
||||
# == Authors
|
||||
# @petems - Peter Souter
|
||||
#
|
||||
define swap_file::files (
|
||||
$ensure = 'present',
|
||||
$swapfile = '/mnt/swap.1',
|
||||
$swapfilesize = $::memorysize,
|
||||
$add_mount = true,
|
||||
$options = 'defaults',
|
||||
$timeout = 300,
|
||||
$cmd = 'dd',
|
||||
$resize_existing = false,
|
||||
$resize_margin = '50MB',
|
||||
$resize_verbose = false,
|
||||
)
|
||||
{
|
||||
# Parameter validation
|
||||
validate_legacy(String, 'validate_re', $ensure, ['^absent$', '^present$'])
|
||||
validate_legacy(String, 'validate_string', $swapfile)
|
||||
$swapfilesize_mb = to_bytes($swapfilesize) / 1048576
|
||||
validate_legacy(Boolean, 'validate_bool', $add_mount)
|
||||
|
||||
if $ensure == 'present' {
|
||||
|
||||
if ($resize_existing and $::swapfile_sizes) {
|
||||
|
||||
if (is_hash($::swapfile_sizes)) {
|
||||
|
||||
if (has_key($::swapfile_sizes,$swapfile)) {
|
||||
::swap_file::resize { $swapfile:
|
||||
swapfile_path => $swapfile,
|
||||
margin => $resize_margin,
|
||||
expected_swapfile_size => $swapfilesize,
|
||||
actual_swapfile_size => $::swapfile_sizes[$swapfile],
|
||||
verbose => $resize_verbose,
|
||||
before => Exec["Create swap file ${swapfile}"],
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$existing_swapfile_size = swap_file_size_from_csv($swapfile,$::swapfile_sizes_csv)
|
||||
if ($existing_swapfile_size) {
|
||||
::swap_file::resize { $swapfile:
|
||||
swapfile_path => $swapfile,
|
||||
margin => $resize_margin,
|
||||
expected_swapfile_size => $swapfilesize,
|
||||
actual_swapfile_size => $existing_swapfile_size,
|
||||
verbose => $resize_verbose,
|
||||
before => Exec["Create swap file ${swapfile}"],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exec { "Create swap file ${swapfile}":
|
||||
creates => $swapfile,
|
||||
timeout => $timeout,
|
||||
}
|
||||
case $cmd {
|
||||
'dd': {
|
||||
Exec["Create swap file ${swapfile}"] { command => "/bin/dd if=/dev/zero of=${swapfile} bs=1M count=${swapfilesize_mb}" }
|
||||
}
|
||||
'fallocate': {
|
||||
Exec["Create swap file ${swapfile}"] { command => "/usr/bin/fallocate -l ${swapfilesize_mb}M ${swapfile}" }
|
||||
}
|
||||
default: {
|
||||
fail("Invalid cmd: ${cmd} - (Must be 'dd' or 'fallocate')")
|
||||
}
|
||||
}
|
||||
file { $swapfile:
|
||||
owner => root,
|
||||
group => root,
|
||||
mode => '0600',
|
||||
require => Exec["Create swap file ${swapfile}"],
|
||||
}
|
||||
|
||||
if $::selinux {
|
||||
File[$swapfile] {
|
||||
seltype => 'swapfile_t',
|
||||
}
|
||||
}
|
||||
|
||||
swap_file { $swapfile:
|
||||
ensure => 'present',
|
||||
require => File[$swapfile],
|
||||
}
|
||||
if $add_mount {
|
||||
mount { $swapfile:
|
||||
ensure => present,
|
||||
fstype => swap,
|
||||
device => $swapfile,
|
||||
options => $options,
|
||||
dump => 0,
|
||||
pass => 0,
|
||||
require => Swap_file[$swapfile],
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif $ensure == 'absent' {
|
||||
swap_file { $swapfile:
|
||||
ensure => 'absent',
|
||||
}
|
||||
file { $swapfile:
|
||||
ensure => absent,
|
||||
backup => false,
|
||||
require => Swap_file[$swapfile],
|
||||
}
|
||||
mount { $swapfile:
|
||||
ensure => absent,
|
||||
device => $swapfile,
|
||||
}
|
||||
}
|
||||
}
|
||||
65
modules/build/unix/swap_file/manifests/init.pp
Normal file
65
modules/build/unix/swap_file/manifests/init.pp
Normal file
@@ -0,0 +1,65 @@
|
||||
# Main class to allow passing required swapfiles as hashes
|
||||
#
|
||||
# @example Will create one swapfile in /mnt/swap using the defaults.
|
||||
# class { '::swap_file':
|
||||
# 'files' => {
|
||||
# 'resource_name' => {
|
||||
# ensure => present,
|
||||
# swapfile => '/mnt/swap',
|
||||
# },
|
||||
# },
|
||||
# }
|
||||
#
|
||||
# @example Will create two swapfile with the given parameters
|
||||
# class { 'swap_file':
|
||||
# 'files' => {
|
||||
# 'swap1' => {
|
||||
# ensure => present,
|
||||
# swapfile => '/mnt/swap.1',
|
||||
# swapfilesize => '1 GB',
|
||||
# },
|
||||
# 'swap2' => {
|
||||
# ensure => present,
|
||||
# swapfile => '/mnt/swap.2',
|
||||
# swapfilesize => '2 GB',
|
||||
# cmd => 'fallocate',
|
||||
# },
|
||||
# },
|
||||
# }
|
||||
#
|
||||
# @example Will merge all found instances of swap_file::files found in hiera and create resources for these.
|
||||
# class { '::swap_file':
|
||||
# files_hiera_merge: true,
|
||||
# }
|
||||
#
|
||||
# @param [Hash] files Hash of swap files to ensure with swap_file::files
|
||||
# @param [Boolean] files_hiera_merge Boolean to merge all found instances of swap_file::files in Hiera.
|
||||
# This can be used to specify swap files at different levels an have
|
||||
# them all included in the catalog.
|
||||
#
|
||||
# @author - Peter Souter
|
||||
#
|
||||
class swap_file (
|
||||
$files = {},
|
||||
$files_hiera_merge = false,
|
||||
) {
|
||||
|
||||
# variable handling
|
||||
if $files_hiera_merge =~ Boolean {
|
||||
$files_hiera_merge_bool = $files_hiera_merge
|
||||
} else {
|
||||
$files_hiera_merge_bool = str2bool($files_hiera_merge)
|
||||
}
|
||||
validate_legacy(Boolean, 'validate_bool', $files_hiera_merge_bool)
|
||||
|
||||
# functionality
|
||||
if $files_hiera_merge_bool == true {
|
||||
$files_real = hiera_hash('swap_file::files', {})
|
||||
} else {
|
||||
$files_real = $files
|
||||
}
|
||||
if $files_real != undef {
|
||||
validate_legacy(Hash, 'validate_hash', $files_real)
|
||||
create_resources('swap_file::files', $files_real)
|
||||
}
|
||||
}
|
||||
49
modules/build/unix/swap_file/manifests/resize.pp
Normal file
49
modules/build/unix/swap_file/manifests/resize.pp
Normal file
@@ -0,0 +1,49 @@
|
||||
# A defined type to resize an existing swapfile
|
||||
#
|
||||
# @example
|
||||
# ::swap_file::resize { '/mnt/swap.1:
|
||||
# swapfile_path => '/mnt/swap.1',
|
||||
# margin => '500 MB',
|
||||
# expected_swapfile_size => '1 GB,
|
||||
# }
|
||||
#
|
||||
# @param [String] swapfile_path Path to the swapfile
|
||||
# @param [String] expected_swapfile_size Expected size of the swapfile
|
||||
# @param [String] actual_swapfile_size Actual size of the swapfile
|
||||
# @param [String] margin Margin that is checked before resizing the swapfile
|
||||
# @param [Boolean] verbose Adds a notify to explain why the change was made
|
||||
#
|
||||
# @author - Peter Souter
|
||||
#
|
||||
define swap_file::resize (
|
||||
$swapfile_path,
|
||||
$expected_swapfile_size,
|
||||
$actual_swapfile_size,
|
||||
$margin = '50MB',
|
||||
$verbose = false,
|
||||
)
|
||||
{
|
||||
$margin_bytes = to_bytes($margin)
|
||||
$existing_swapfile_bytes = to_bytes("${actual_swapfile_size}kb")
|
||||
$expected_swapfile_size_bytes = to_bytes($expected_swapfile_size)
|
||||
|
||||
if !($expected_swapfile_size_bytes == $existing_swapfile_bytes) {
|
||||
if !(difference_within_margin([$existing_swapfile_bytes, $expected_swapfile_size_bytes],$margin_bytes)) {
|
||||
if ($verbose) {
|
||||
$alert_message = "Existing : ${existing_swapfile_bytes}B\nExpected: ${expected_swapfile_size_bytes}B\nMargin: ${margin_bytes}B"
|
||||
notify{"Resizing Swapfile Alert ${swapfile_path}":
|
||||
name => $alert_message,
|
||||
}
|
||||
}
|
||||
exec { "Detach swap file ${swapfile_path} for resize":
|
||||
command => "/sbin/swapoff ${swapfile_path}",
|
||||
onlyif => "/sbin/swapon -s | grep ${swapfile_path}",
|
||||
} -> exec { "Purge ${swapfile_path} for resize":
|
||||
command => "/bin/rm -f ${swapfile_path}",
|
||||
onlyif => "test -f ${swapfile_path}",
|
||||
path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/' ],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
23
modules/build/unix/swap_file/manifests/swappiness.pp
Normal file
23
modules/build/unix/swap_file/manifests/swappiness.pp
Normal file
@@ -0,0 +1,23 @@
|
||||
# Allows setting the kernel swappiness setting
|
||||
#
|
||||
# @example Will set the sysctl setting for swappiness to 75
|
||||
# class { '::swap_file::swappiness':
|
||||
# swappiness => 75,
|
||||
# }
|
||||
#
|
||||
# @param [String] swapiness Swapiness level, integer from 0 - 100 inclusive
|
||||
#
|
||||
# @author - Peter Souter
|
||||
#
|
||||
class swap_file::swappiness (
|
||||
$swappiness = 60,
|
||||
) {
|
||||
|
||||
validate_legacy(Integer, 'validate_integer', $swappiness, [100, 0])
|
||||
|
||||
sysctl { 'vm.swappiness':
|
||||
ensure => 'present',
|
||||
value => $swappiness,
|
||||
}
|
||||
|
||||
}
|
||||
55
modules/build/unix/swap_file/metadata.json
Normal file
55
modules/build/unix/swap_file/metadata.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "petems-swap_file",
|
||||
"version": "4.0.2",
|
||||
"author": "Peter Souter",
|
||||
"summary": "Create swap files for Linux systems with Puppet",
|
||||
"license": "Apache-2.0",
|
||||
"source": "https://github.com/petems/petems-swap_file",
|
||||
"project_page": "https://github.com/petems/petems-swap_file",
|
||||
"issues_url": "https://github.com/petems/petems-swap_file/issues",
|
||||
"operatingsystem_support": [
|
||||
{
|
||||
"operatingsystem": "RedHat",
|
||||
"operatingsystemrelease": [
|
||||
"5",
|
||||
"6",
|
||||
"7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"operatingsystem": "CentOS",
|
||||
"operatingsystemrelease": [
|
||||
"5",
|
||||
"6",
|
||||
"7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"operatingsystem": "Debian",
|
||||
"operatingsystemrelease": [
|
||||
"6",
|
||||
"7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"operatingsystem": "Ubuntu",
|
||||
"operatingsystemrelease": [
|
||||
"10.04",
|
||||
"12.04",
|
||||
"14.04"
|
||||
]
|
||||
}
|
||||
],
|
||||
"requirements": [
|
||||
{
|
||||
"name": "puppet",
|
||||
"version_requirement": ">= 4.0.0"
|
||||
}
|
||||
],
|
||||
"dependencies": [
|
||||
{"name":"puppetlabs/stdlib","version_requirement":">= 4.23.0 < 6.0.0"},
|
||||
{"name":"puppetlabs/mount_core","version_requirement":">= 1.0.0 < 2.0.0"},
|
||||
{"name":"herculesteam/augeasproviders_sysctl","version_requirement":">=2.1.0 < 3.0.0"},
|
||||
{"name":"herculesteam/augeasproviders_core","version_requirement":">=2.1.0 < 3.0.0"}
|
||||
]
|
||||
}
|
||||
19
modules/build/unix/swap_file/secgen_metadata.xml
Normal file
19
modules/build/unix/swap_file/secgen_metadata.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0"?>
|
||||
<build xmlns="http://www.github/cliffe/SecGen/build"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/build">
|
||||
<name>Swap File Module</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>MIT</module_license>
|
||||
<description>TODO: </description>
|
||||
|
||||
<type>swap</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>size</read_fact>
|
||||
|
||||
<default_input into="size">
|
||||
<value>2 GB</value>
|
||||
</default_input>
|
||||
|
||||
</build>
|
||||
@@ -0,0 +1,11 @@
|
||||
Vagrant.configure("2") do |c|
|
||||
c.ssh.insert_key = false
|
||||
c.vm.define 'centos-7-x64' do |v|
|
||||
v.vm.hostname = 'centos-7-x64'
|
||||
v.vm.box = 'centos/7'
|
||||
v.vm.box_check_update = 'true'
|
||||
v.vm.provider :libvirt do |node|
|
||||
node.memory = 512
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
HOSTS:
|
||||
centos-6-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: el-6-x86_64
|
||||
box : puppetlabs/centos-6.6-64-nocm
|
||||
box_url : https://vagrantcloud.com/puppetlabs/boxes/centos-6.6-64-nocm
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
log_level: debug
|
||||
type: foss
|
||||
@@ -0,0 +1,11 @@
|
||||
HOSTS:
|
||||
centos-7-x64:
|
||||
roles:
|
||||
- default
|
||||
platform: el-7-x86_64
|
||||
box : centos/7
|
||||
hypervisor : vagrant_libvirt
|
||||
CONFIG:
|
||||
type: foss
|
||||
log_level: verbose
|
||||
network_mac: '5a:65:a9:97:e4:e4'
|
||||
@@ -0,0 +1,11 @@
|
||||
HOSTS:
|
||||
centos-7-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: el-7-x86_64
|
||||
box: puppetlabs/centos-7.0-64-nocm
|
||||
box_url: https://vagrantcloud.com/puppetlabs/boxes/centos-7.0-64-nocm
|
||||
hypervisor: vagrant
|
||||
CONFIG:
|
||||
log_level: verbose
|
||||
type: foss
|
||||
@@ -0,0 +1,11 @@
|
||||
HOSTS:
|
||||
ubuntu-server-1204-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: ubuntu-12.04-amd64
|
||||
box : puppetlabs/ubuntu-12.04-64-nocm
|
||||
box_url : https://vagrantcloud.com/puppetlabs/ubuntu-12.04-64-nocm
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
log_level: debug
|
||||
type: foss
|
||||
@@ -0,0 +1,11 @@
|
||||
HOSTS:
|
||||
ubuntu-server-1204-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: ubuntu-12.04-amd64
|
||||
box : puppetlabs/ubuntu-12.04-64-nocm
|
||||
box_url : https://vagrantcloud.com/puppetlabs/ubuntu-12.04-64-nocm
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
log_level: debug
|
||||
type: foss
|
||||
@@ -0,0 +1,45 @@
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'swap_file class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
|
||||
|
||||
context 'swap_file' do
|
||||
context 'ensure => present' do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
class { 'swap_file':
|
||||
files => {
|
||||
'swapfile' => {
|
||||
ensure => 'present',
|
||||
},
|
||||
'use fallocate' => {
|
||||
swapfile => '/tmp/swapfile.fallocate',
|
||||
cmd => 'fallocate',
|
||||
},
|
||||
'remove swap file' => {
|
||||
ensure => 'absent',
|
||||
swapfile => '/tmp/swapfile.old',
|
||||
},
|
||||
},
|
||||
}
|
||||
EOS
|
||||
|
||||
# Run it twice and test for idempotency
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the default swapfile' do
|
||||
shell('/sbin/swapon -s | grep /mnt/swap.1', :acceptable_exit_codes => [0])
|
||||
end
|
||||
it 'should contain the default fstab setting' do
|
||||
shell('cat /etc/fstab | grep /mnt/swap.1', :acceptable_exit_codes => [0])
|
||||
shell('cat /etc/fstab | grep defaults', :acceptable_exit_codes => [0])
|
||||
end
|
||||
it 'should contain the default swapfile' do
|
||||
shell('/sbin/swapon -s | grep /tmp/swapfile.fallocate', :acceptable_exit_codes => [0])
|
||||
end
|
||||
it 'should contain the default fstab setting' do
|
||||
shell('cat /etc/fstab | grep /tmp/swapfile.fallocate', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'swap_file::files defined type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
|
||||
|
||||
context 'fallocate command', :unless => ['FreeBSD'].include?(fact('osfamily')) do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
swap_file::files { 'default':
|
||||
ensure => present,
|
||||
cmd => 'fallocate',
|
||||
}
|
||||
EOS
|
||||
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the default swapfile' do
|
||||
shell('/sbin/swapon -s | grep /mnt/swap.1', :acceptable_exit_codes => [0])
|
||||
end
|
||||
it 'should contain the default fstab setting' do
|
||||
shell('cat /etc/fstab | grep /mnt/swap.1', :acceptable_exit_codes => [0])
|
||||
shell('cat /etc/fstab | grep defaults', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,31 @@
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'swap_file::files defined type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
|
||||
|
||||
context 'multiple swap_file::files', :unless => ['FreeBSD'].include?(fact('osfamily')) do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
swap_file::files { 'tmp file swap 1':
|
||||
ensure => present,
|
||||
swapfile => '/tmp/swapfile1',
|
||||
}
|
||||
|
||||
swap_file::files { 'tmp file swap 2':
|
||||
ensure => present,
|
||||
swapfile => '/tmp/swapfile2',
|
||||
}
|
||||
EOS
|
||||
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the given swapfile' do
|
||||
shell('/sbin/swapon -s | grep /tmp/swapfile1', :acceptable_exit_codes => [0])
|
||||
shell('/sbin/swapon -s | grep /tmp/swapfile2', :acceptable_exit_codes => [0])
|
||||
end
|
||||
it 'should contain the default fstab setting' do
|
||||
shell('cat /etc/fstab | grep /tmp/swapfile1', :acceptable_exit_codes => [0])
|
||||
shell('cat /etc/fstab | grep /tmp/swapfile2', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,35 @@
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'swap_file::files defined type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
|
||||
|
||||
context 'swap_file' do
|
||||
context 'custom parameters' do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
swap_file::files { 'tmp file swap':
|
||||
ensure => present,
|
||||
swapfile => '/tmp/swapfile',
|
||||
}
|
||||
EOS
|
||||
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the given swapfile' do
|
||||
if ["FreeBSD"].include?(fact('osfamily'))
|
||||
shell('/usr/sbin/swapinfo | grep /dev/md99', :acceptable_exit_codes => [0])
|
||||
else
|
||||
shell('/sbin/swapon -s | grep /tmp/swapfile', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
it 'should contain the given fstab setting' do
|
||||
shell('cat /etc/fstab | grep /tmp/swapfile', :acceptable_exit_codes => [0])
|
||||
if ["FreeBSD"].include?(fact('osfamily'))
|
||||
shell('cat /etc/fstab | grep md99', :acceptable_exit_codes => [0])
|
||||
else
|
||||
shell('cat /etc/fstab | grep defaults', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,73 @@
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'swap_file::files defined type', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
|
||||
|
||||
context 'swap_file' do
|
||||
context 'ensure => present' do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
swap_file::files { 'default':
|
||||
ensure => present,
|
||||
}
|
||||
EOS
|
||||
|
||||
# Run it twice and test for idempotency
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the default swapfile' do
|
||||
shell('/sbin/swapon -s | grep /mnt/swap.1', :acceptable_exit_codes => [0])
|
||||
end
|
||||
it 'should contain the default fstab setting' do
|
||||
shell('cat /etc/fstab | grep /mnt/swap.1', :acceptable_exit_codes => [0])
|
||||
shell('cat /etc/fstab | grep defaults', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
context 'custom parameters' do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
swap_file::files { 'tmp file swap':
|
||||
ensure => present,
|
||||
swapfile => '/tmp/swapfile',
|
||||
}
|
||||
EOS
|
||||
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the given swapfile' do
|
||||
shell('/sbin/swapon -s | grep /tmp/swapfile', :acceptable_exit_codes => [0])
|
||||
end
|
||||
it 'should contain the default fstab setting' do
|
||||
shell('cat /etc/fstab | grep /tmp/swapfile', :acceptable_exit_codes => [0])
|
||||
shell('cat /etc/fstab | grep defaults', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
context 'multiple swap_file::files' do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
swap_file::files { 'tmp file swap 1':
|
||||
ensure => present,
|
||||
swapfile => '/tmp/swapfile1',
|
||||
}
|
||||
|
||||
swap_file::files { 'tmp file swap 2':
|
||||
ensure => present,
|
||||
swapfile => '/tmp/swapfile2',
|
||||
}
|
||||
EOS
|
||||
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the given swapfiles' do
|
||||
shell('/sbin/swapon -s | grep /tmp/swapfile1', :acceptable_exit_codes => [0])
|
||||
shell('/sbin/swapon -s | grep /tmp/swapfile2', :acceptable_exit_codes => [0])
|
||||
end
|
||||
it 'should contain the default fstab setting' do
|
||||
shell('cat /etc/fstab | grep /tmp/swapfile1', :acceptable_exit_codes => [0])
|
||||
shell('cat /etc/fstab | grep /tmp/swapfile2', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,50 @@
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'swap_file class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
|
||||
|
||||
context 'disable stringify_facts' do
|
||||
shell('puppet config set stringify_facts false --section=agent', { :acceptable_exit_codes => [0,1] })
|
||||
shell('puppet config set stringify_facts false', { :acceptable_exit_codes => [0,1] })
|
||||
end
|
||||
|
||||
context 'swap_file' do
|
||||
context 'swapfilesize => 100' do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
swap_file::files { 'default':
|
||||
ensure => present,
|
||||
swapfilesize => '100MB',
|
||||
resize_existing => true,
|
||||
}
|
||||
EOS
|
||||
|
||||
# Run it twice and test for idempotency
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the given swapfile with the correct size (102396/100MB)' do
|
||||
shell('/sbin/swapon -s | grep /mnt/swap.1', :acceptable_exit_codes => [0])
|
||||
shell('/bin/cat /proc/swaps | grep 102396', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
context 'resize swap file' do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
swap_file::files { 'default':
|
||||
ensure => present,
|
||||
swapfilesize => '200MB',
|
||||
resize_existing => true,
|
||||
}
|
||||
EOS
|
||||
|
||||
# Run it twice and test for idempotency
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the given swapfile with the resized size (204796kb/200MB)' do
|
||||
shell('/sbin/swapon -s | grep /mnt/swap.1', :acceptable_exit_codes => [0])
|
||||
shell('/bin/cat /proc/swaps | grep 204796', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,51 @@
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'swap_file class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
|
||||
|
||||
context 'disable stringify_facts' do
|
||||
shell('puppet config set stringify_facts true --section=agent', { :acceptable_exit_codes => [0,1] })
|
||||
shell('puppet config set stringify_facts true', { :acceptable_exit_codes => [0,1] })
|
||||
end
|
||||
|
||||
context 'swap_file' do
|
||||
context 'swapfilesize => 100' do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
swap_file::files { 'default':
|
||||
ensure => present,
|
||||
swapfilesize => '100MB',
|
||||
resize_existing => true,
|
||||
}
|
||||
EOS
|
||||
|
||||
# Run it twice and test for idempotency
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the given swapfile with the correct size (102396/100MB)' do
|
||||
shell('/sbin/swapon -s | grep /mnt/swap.1', :acceptable_exit_codes => [0])
|
||||
shell('/bin/cat /proc/swaps | grep 102396', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
context 'resize swap file' do
|
||||
it 'errors out if stringify_facts is true and resize_existing is true' do
|
||||
pp = <<-EOS
|
||||
swap_file::files { 'default':
|
||||
ensure => present,
|
||||
swapfilesize => '200MB',
|
||||
resize_existing => true,
|
||||
}
|
||||
EOS
|
||||
|
||||
# Run it twice and test for idempotency
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should contain the given swapfile with the resized size (204796kb/200MB)' do
|
||||
shell('/sbin/swapon -s | grep /mnt/swap.1', :acceptable_exit_codes => [0])
|
||||
shell('/bin/cat /proc/swaps | grep 204796', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'swap_file::swappiness class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
|
||||
|
||||
context 'swap_file::swappiness' do
|
||||
context 'swappiness => 75, permanent => false' do
|
||||
it 'should work with no errors' do
|
||||
pp = <<-EOS
|
||||
class { 'swap_file::swappiness':
|
||||
swappiness => 75,
|
||||
}
|
||||
EOS
|
||||
|
||||
# Run it twice and test for idempotency
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
it 'should set the swappiness to 75 in a seperate sysctl file' do
|
||||
shell('/bin/cat /proc/sys/vm/swappiness | grep 75', :acceptable_exit_codes => [0])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
156
modules/build/unix/swap_file/spec/classes/init_spec.rb
Normal file
156
modules/build/unix/swap_file/spec/classes/init_spec.rb
Normal file
@@ -0,0 +1,156 @@
|
||||
require 'spec_helper'
|
||||
describe 'swap_file' do
|
||||
let(:facts) do
|
||||
{
|
||||
:memorysize => '1.00 GB',
|
||||
selinux: true,
|
||||
}
|
||||
end
|
||||
|
||||
context 'with defaults for all parameters' do
|
||||
it { is_expected.to compile.with_all_deps }
|
||||
it { is_expected.to contain_class('swap_file') }
|
||||
it { is_expected.to have_resource_count(0) }
|
||||
end
|
||||
|
||||
context 'with files set to valid hash' do
|
||||
let(:params) do
|
||||
{
|
||||
:files => {
|
||||
'swap' => {
|
||||
'ensure' => 'present',
|
||||
},
|
||||
'test' => {
|
||||
'swapfile' => '/mnt/test',
|
||||
},
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to compile.with_all_deps }
|
||||
it { is_expected.to contain_class('swap_file') }
|
||||
# subclass swap_file::files adds 4 resources for each given file
|
||||
it { is_expected.to have_resource_count(10) }
|
||||
|
||||
it do
|
||||
is_expected.to contain_swap_file__files('swap').with({
|
||||
'ensure' => 'present',
|
||||
})
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.to contain_swap_file__files('test').with({
|
||||
'swapfile' => '/mnt/test',
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with data for swap_file::files provided in multiple hiera levels' do
|
||||
let(:facts) do
|
||||
{
|
||||
:fqdn => 'files',
|
||||
:parameter_tests => 'files_hiera_merge',
|
||||
:memorysize => '1.00 GB',
|
||||
:selinux => true,
|
||||
}
|
||||
end
|
||||
|
||||
context 'when files_hiera_merge is set to the default value <false>' do
|
||||
let(:params) { { :files_hiera_merge => false } }
|
||||
it { is_expected.to compile.with_all_deps }
|
||||
it { is_expected.to contain_class('swap_file') }
|
||||
it { is_expected.to have_resource_count(5) }
|
||||
|
||||
it do
|
||||
is_expected.to contain_swap_file__files('resource_name').with({
|
||||
'ensure' => 'present',
|
||||
'swapfile' => '/mnt/swap',
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
context 'when files_hiera_merge is set to valid value <true>' do
|
||||
let(:params) { { :files_hiera_merge => true } }
|
||||
it { is_expected.to compile.with_all_deps }
|
||||
it { is_expected.to contain_class('swap_file') }
|
||||
it { is_expected.to have_resource_count(15) }
|
||||
|
||||
it do
|
||||
is_expected.to contain_swap_file__files('resource_name').with({
|
||||
'ensure' => 'present',
|
||||
'swapfile' => '/mnt/swap',
|
||||
})
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.to contain_swap_file__files('swap1').with({
|
||||
'ensure' => 'present',
|
||||
'swapfile' => '/mnt/swap.1',
|
||||
'swapfilesize' => '1 GB',
|
||||
})
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.to contain_swap_file__files('swap2').with({
|
||||
'ensure' => 'present',
|
||||
'swapfile' => '/mnt/swap.2',
|
||||
'swapfilesize' => '2 GB',
|
||||
'cmd' => 'fallocate',
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'variable type and content validations' do
|
||||
# set needed custom facts and variables
|
||||
let(:facts) do
|
||||
{
|
||||
:osfamily => 'RedHat',
|
||||
:memorysize => '1.00 GB',
|
||||
:selinux => true,
|
||||
}
|
||||
end
|
||||
let(:validation_params) do
|
||||
{
|
||||
#:param => 'value',
|
||||
}
|
||||
end
|
||||
|
||||
validations = {
|
||||
'bool_stringified' => {
|
||||
:name => %w(files_hiera_merge),
|
||||
:valid => [true, false, 'true', 'false'],
|
||||
:invalid => ['invalid', %w(array), { 'ha' => 'sh' }, 3, 2.42, nil],
|
||||
:message => '(Unknown type of boolean|str2bool\(\): (Requires either string to work with|Requires string to work with))',
|
||||
},
|
||||
'hash' => {
|
||||
:name => %w(files),
|
||||
:valid => [{ 'swap' => { 'ensure' => 'present' } }],
|
||||
:invalid => ['invalid', %w(array), 3, 2.42, true, false, nil],
|
||||
:message => '(is not a Hash|expects a Hash value, got)',
|
||||
},
|
||||
}
|
||||
|
||||
validations.sort.each do |type, var|
|
||||
var[:name].each do |var_name|
|
||||
var[:valid].each do |valid|
|
||||
context "with #{var_name} (#{type}) set to valid #{valid} (as #{valid.class})" do
|
||||
let(:params) { validation_params.merge({ :"#{var_name}" => valid, }) }
|
||||
it { is_expected.to compile }
|
||||
end
|
||||
end
|
||||
|
||||
var[:invalid].each do |invalid|
|
||||
context "with #{var_name} (#{type}) set to invalid #{invalid} (as #{invalid.class})" do
|
||||
let(:params) { validation_params.merge({ :"#{var_name}" => invalid, }) }
|
||||
it 'should fail' do
|
||||
expect do
|
||||
is_expected.to contain_class(subject)
|
||||
end.to raise_error(Puppet::Error, /#{var[:message]}/)
|
||||
end
|
||||
end
|
||||
end
|
||||
end # var[:name].each
|
||||
end # validations.sort.each
|
||||
end # describe 'variable type and content validations'
|
||||
end
|
||||
14
modules/build/unix/swap_file/spec/classes/swappiness_spec.rb
Normal file
14
modules/build/unix/swap_file/spec/classes/swappiness_spec.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'swap_file::swappiness' do
|
||||
let(:params) do
|
||||
{
|
||||
:swappiness => 65,
|
||||
}
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_sysctl('vm.swappiness').
|
||||
with({"ensure"=>"present",
|
||||
"value"=>"65"})
|
||||
end
|
||||
end
|
||||
360
modules/build/unix/swap_file/spec/defines/files_spec.rb
Normal file
360
modules/build/unix/swap_file/spec/defines/files_spec.rb
Normal file
@@ -0,0 +1,360 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'swap_file::files' do
|
||||
let(:title) { 'default' }
|
||||
|
||||
let(:facts) do
|
||||
{
|
||||
operatingsystem: 'RedHat',
|
||||
osfamily: 'RedHat',
|
||||
operatingsystemrelease: '7',
|
||||
concat_basedir: '/tmp',
|
||||
memorysize: '1.00 GB',
|
||||
selinux: true,
|
||||
}
|
||||
end
|
||||
|
||||
# Add these two lines in a single test block to enable puppet and hiera debug mode
|
||||
# Puppet::Util::Log.level = :debug
|
||||
# Puppet::Util::Log.newdestination(:console)
|
||||
|
||||
context 'default parameters' do
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Create swap file /mnt/swap.1')
|
||||
.with('command' => '/bin/dd if=/dev/zero of=/mnt/swap.1 bs=1M count=1024',
|
||||
'creates' => '/mnt/swap.1')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_file('/mnt/swap.1')
|
||||
.with('owner' => 'root',
|
||||
'group' => 'root',
|
||||
'mode' => '0600',
|
||||
'require' => 'Exec[Create swap file /mnt/swap.1]')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_swap_file('/mnt/swap.1')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_mount('/mnt/swap.1')
|
||||
.with('require' => 'Swap_file[/mnt/swap.1]')
|
||||
end
|
||||
end
|
||||
|
||||
context 'custom swapfilesize parameter' do
|
||||
let(:params) do
|
||||
{
|
||||
swapfilesize: '4.1 GB'
|
||||
}
|
||||
end
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Create swap file /mnt/swap.1')
|
||||
.with('command' => '/bin/dd if=/dev/zero of=/mnt/swap.1 bs=1M count=4198',
|
||||
'creates' => '/mnt/swap.1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'custom swapfilesize parameter with timeout' do
|
||||
let(:params) do
|
||||
{
|
||||
swapfile: '/mnt/swap.2',
|
||||
swapfilesize: '4.1 GB',
|
||||
timeout: 900
|
||||
}
|
||||
end
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Create swap file /mnt/swap.2')
|
||||
.with('command' => '/bin/dd if=/dev/zero of=/mnt/swap.2 bs=1M count=4198',
|
||||
'timeout' => 900, 'creates' => '/mnt/swap.2')
|
||||
end
|
||||
end
|
||||
|
||||
context 'custom swapfilesize parameter with timeout' do
|
||||
let(:params) do
|
||||
{
|
||||
swapfile: '/mnt/swap.2',
|
||||
swapfilesize: '4.1 GB',
|
||||
timeout: 900
|
||||
}
|
||||
end
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Create swap file /mnt/swap.2')
|
||||
.with('command' => '/bin/dd if=/dev/zero of=/mnt/swap.2 bs=1M count=4198',
|
||||
'timeout' => 900, 'creates' => '/mnt/swap.2')
|
||||
end
|
||||
end
|
||||
|
||||
context 'custom swapfilesize parameter with fallocate' do
|
||||
let(:params) do
|
||||
{
|
||||
swapfile: '/mnt/swap.3',
|
||||
swapfilesize: '4.1 GB',
|
||||
cmd: 'fallocate'
|
||||
}
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
is_expected.to contain_exec('Create swap file /mnt/swap.3')
|
||||
.with(
|
||||
'command' => '/usr/bin/fallocate -l 4198M /mnt/swap.3',
|
||||
'creates' => '/mnt/swap.3'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with cmd set to invalid value' do
|
||||
let(:params) do
|
||||
{
|
||||
cmd: 'invalid'
|
||||
}
|
||||
end
|
||||
it 'should fail' do
|
||||
expect { should contain_class(subject) }.to raise_error(Puppet::Error, /Invalid cmd: invalid - \(Must be \'dd\' or \'fallocate\'\)/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'resize_existing => true' do
|
||||
|
||||
let(:existing_swap_kb) { '204796' } # 200MB
|
||||
|
||||
context 'when swapfile_sizes fact exists and matches path' do
|
||||
let(:params) do
|
||||
{
|
||||
swapfile: '/mnt/swap.resizeme',
|
||||
resize_existing: true
|
||||
}
|
||||
end
|
||||
|
||||
let(:facts) do
|
||||
{
|
||||
operatingsystem: 'RedHat',
|
||||
osfamily: 'RedHat',
|
||||
operatingsystemrelease: '7',
|
||||
concat_basedir: '/tmp',
|
||||
memorysize: '1.00 GB',
|
||||
swapfile_sizes: {
|
||||
'/mnt/swap.resizeme' => existing_swap_kb,
|
||||
},
|
||||
swapfile_sizes_csv: "/mnt/swap.resizeme||#{existing_swap_kb}",
|
||||
selinux: true,
|
||||
}
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
should contain_swap_file__resize('/mnt/swap.resizeme').with('swapfile_path' => '/mnt/swap.resizeme',
|
||||
'margin' => '50MB',
|
||||
'expected_swapfile_size' => '1.00 GB',
|
||||
'actual_swapfile_size' => existing_swap_kb,
|
||||
'before' => 'Exec[Create swap file /mnt/swap.resizeme]')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Create swap file /mnt/swap.resizeme')
|
||||
.with('command' => '/bin/dd if=/dev/zero of=/mnt/swap.resizeme bs=1M count=1024',
|
||||
'creates' => '/mnt/swap.resizeme')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_file('/mnt/swap.resizeme')
|
||||
.with('owner' => 'root',
|
||||
'group' => 'root',
|
||||
'mode' => '0600',
|
||||
'require' => 'Exec[Create swap file /mnt/swap.resizeme]')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_swap_file('/mnt/swap.resizeme')
|
||||
.with('ensure' => 'present')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_mount('/mnt/swap.resizeme')
|
||||
.with('require' => 'Swap_file[/mnt/swap.resizeme]')
|
||||
end
|
||||
end
|
||||
context 'when swapfile_sizes fact does not exist' do
|
||||
let(:params) do
|
||||
{
|
||||
swapfile: '/mnt/swap.nofact',
|
||||
resize_existing: true
|
||||
}
|
||||
end
|
||||
let(:facts) do
|
||||
{
|
||||
operatingsystem: 'RedHat',
|
||||
osfamily: 'RedHat',
|
||||
operatingsystemrelease: '7',
|
||||
concat_basedir: '/tmp',
|
||||
memorysize: '1.00 GB',
|
||||
swapfile_sizes: nil,
|
||||
selinux: true,
|
||||
}
|
||||
end
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
should_not contain_swap_file__resize('/mnt/swap.nofact')
|
||||
end
|
||||
end
|
||||
context 'when swapfile_sizes fact exits but file does not match' do
|
||||
let(:params) do
|
||||
{
|
||||
swapfile: '/mnt/swap.factbutnomatch',
|
||||
resize_existing: true
|
||||
}
|
||||
end
|
||||
let(:facts) do
|
||||
{
|
||||
operatingsystem: 'RedHat',
|
||||
osfamily: 'RedHat',
|
||||
operatingsystemrelease: '7',
|
||||
concat_basedir: '/tmp',
|
||||
memorysize: '1.00 GB',
|
||||
swapfile_sizes: {
|
||||
'/mnt/swap.differentname' => '204796', # 200MB
|
||||
},
|
||||
swapfile_sizes_csv: "/mnt/swap.differentname||#{existing_swap_kb}",
|
||||
selinux: true,
|
||||
}
|
||||
end
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Create swap file /mnt/swap.factbutnomatch')
|
||||
.with(
|
||||
'command' => '/bin/dd if=/dev/zero of=/mnt/swap.factbutnomatch bs=1M count=1024',
|
||||
'creates' => '/mnt/swap.factbutnomatch'
|
||||
)
|
||||
end
|
||||
it do
|
||||
should_not contain_swap_file__resize('/mnt/swap.factbutnomatch')
|
||||
end
|
||||
end
|
||||
context 'when swapfile_sizes fact exists and matches path, but not hash' do
|
||||
let(:params) do
|
||||
{
|
||||
swapfile: '/mnt/swap.resizeme',
|
||||
resize_existing: true
|
||||
}
|
||||
end
|
||||
|
||||
let(:existing_swap_kb) { '204796' } # 200MB
|
||||
|
||||
let(:facts) do
|
||||
{
|
||||
operatingsystem: 'RedHat',
|
||||
osfamily: 'RedHat',
|
||||
operatingsystemrelease: '7',
|
||||
concat_basedir: '/tmp',
|
||||
memorysize: '1.00 GB',
|
||||
swapfile_sizes: "/mnt/swap.resizeme#{existing_swap_kb}",
|
||||
swapfile_sizes_csv: "/mnt/swap.resizeme||#{existing_swap_kb}",
|
||||
selinux: true,
|
||||
}
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
should contain_swap_file__resize('/mnt/swap.resizeme').with('swapfile_path' => '/mnt/swap.resizeme',
|
||||
'margin' => '50MB',
|
||||
'expected_swapfile_size' => '1.00 GB',
|
||||
'actual_swapfile_size' => existing_swap_kb,
|
||||
'before' => 'Exec[Create swap file /mnt/swap.resizeme]')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Create swap file /mnt/swap.resizeme')
|
||||
.with('command' => '/bin/dd if=/dev/zero of=/mnt/swap.resizeme bs=1M count=1024',
|
||||
'creates' => '/mnt/swap.resizeme')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_file('/mnt/swap.resizeme')
|
||||
.with('owner' => 'root',
|
||||
'group' => 'root',
|
||||
'mode' => '0600',
|
||||
'require' => 'Exec[Create swap file /mnt/swap.resizeme]')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_swap_file('/mnt/swap.resizeme')
|
||||
.with('ensure' => 'present')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_mount('/mnt/swap.resizeme')
|
||||
.with('require' => 'Swap_file[/mnt/swap.resizeme]')
|
||||
end
|
||||
end
|
||||
context 'when swapfile_sizes fact does not exist' do
|
||||
let(:params) do
|
||||
{
|
||||
swapfile: '/mnt/swap.nofact',
|
||||
resize_existing: true
|
||||
}
|
||||
end
|
||||
let(:facts) do
|
||||
{
|
||||
operatingsystem: 'RedHat',
|
||||
osfamily: 'RedHat',
|
||||
operatingsystemrelease: '7',
|
||||
concat_basedir: '/tmp',
|
||||
memorysize: '1.00 GB',
|
||||
swapfile_sizes: nil,
|
||||
swapfile_sizes_csv: nil,
|
||||
selinux: true,
|
||||
}
|
||||
end
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
should_not contain_swap_file__resize('/mnt/swap.nofact')
|
||||
end
|
||||
end
|
||||
context 'when swapfile_sizes fact exits but file does not match' do
|
||||
let(:params) do
|
||||
{
|
||||
swapfile: '/mnt/swap.factbutnomatch',
|
||||
resize_existing: true
|
||||
}
|
||||
end
|
||||
let(:facts) do
|
||||
{
|
||||
operatingsystem: 'RedHat',
|
||||
osfamily: 'RedHat',
|
||||
operatingsystemrelease: '7',
|
||||
concat_basedir: '/tmp',
|
||||
memorysize: '1.00 GB',
|
||||
swapfile_sizes: "/mnt/swap.differentname#{existing_swap_kb}",
|
||||
swapfile_sizes_csv: "/mnt/swap.differentname||#{existing_swap_kb}",
|
||||
selinux: true,
|
||||
}
|
||||
end
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Create swap file /mnt/swap.factbutnomatch')
|
||||
.with(
|
||||
'command' => '/bin/dd if=/dev/zero of=/mnt/swap.factbutnomatch bs=1M count=1024',
|
||||
'creates' => '/mnt/swap.factbutnomatch'
|
||||
)
|
||||
end
|
||||
it do
|
||||
should_not contain_swap_file__resize('/mnt/swap.factbutnomatch')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
98
modules/build/unix/swap_file/spec/defines/resize_spec.rb
Normal file
98
modules/build/unix/swap_file/spec/defines/resize_spec.rb
Normal file
@@ -0,0 +1,98 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'swap_file::resize' do
|
||||
let(:title) { 'default' }
|
||||
|
||||
|
||||
let(:default_facts) do
|
||||
{
|
||||
:operatingsystem => 'RedHat',
|
||||
:osfamily => 'RedHat',
|
||||
:operatingsystemrelease => '7',
|
||||
:concat_basedir => '/tmp',
|
||||
:memorysize => '1.00 GB',
|
||||
}
|
||||
end
|
||||
|
||||
# Add these two lines in a single test block to enable puppet and hiera debug mode
|
||||
# Puppet::Util::Log.level = :debug
|
||||
# Puppet::Util::Log.newdestination(:console)
|
||||
|
||||
context 'has resize execs if swapfile outside of margin range' do
|
||||
let(:params) do
|
||||
{
|
||||
:swapfile_path => '/mnt/swap.1',
|
||||
:expected_swapfile_size => '1 GB',
|
||||
:actual_swapfile_size => '512 GB',
|
||||
}
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Detach swap file /mnt/swap.1 for resize').
|
||||
with(
|
||||
{
|
||||
"command"=>"/sbin/swapoff /mnt/swap.1",
|
||||
"onlyif"=>"/sbin/swapon -s | grep /mnt/swap.1"
|
||||
}
|
||||
)
|
||||
|
||||
is_expected.to contain_exec('Purge /mnt/swap.1 for resize').
|
||||
with(
|
||||
{
|
||||
"command"=>"/bin/rm -f /mnt/swap.1",
|
||||
"onlyif"=>"test -f /mnt/swap.1"
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'wont have resize execs if swapfile inside of margin range' do
|
||||
let(:params) do
|
||||
{
|
||||
:swapfile_path => '/mnt/swap.1',
|
||||
:expected_swapfile_size => '4 GB',
|
||||
:actual_swapfile_size => '3.9 GB',
|
||||
:margin => '150MB',
|
||||
}
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
is_expected.to_not contain_exec('Detach swap file /mnt/swap.1 for resize')
|
||||
end
|
||||
it do
|
||||
is_expected.to_not contain_exec('Purge /mnt/swap.1 for resize')
|
||||
end
|
||||
end
|
||||
|
||||
context 'can get verboseness message' do
|
||||
let(:params) do
|
||||
{
|
||||
:swapfile_path => '/mnt/swap.1',
|
||||
:expected_swapfile_size => '4 GB',
|
||||
:actual_swapfile_size => '5 GB',
|
||||
:margin => '5MB',
|
||||
:verbose => true,
|
||||
}
|
||||
end
|
||||
|
||||
it do
|
||||
is_expected.to compile.with_all_deps
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Detach swap file /mnt/swap.1 for resize')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_exec('Purge /mnt/swap.1 for resize')
|
||||
end
|
||||
it do
|
||||
is_expected.to contain_notify('Resizing Swapfile Alert /mnt/swap.1').with_name("Existing : 5368709120B\nExpected: 4294967296B\nMargin: 5242880B")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
5
modules/build/unix/swap_file/spec/fixtures/hiera/fqdn/files.yaml
vendored
Normal file
5
modules/build/unix/swap_file/spec/fixtures/hiera/fqdn/files.yaml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
swap_file::files:
|
||||
'resource_name':
|
||||
ensure: 'present'
|
||||
swapfile: '/mnt/swap'
|
||||
8
modules/build/unix/swap_file/spec/fixtures/hiera/hiera.yaml
vendored
Normal file
8
modules/build/unix/swap_file/spec/fixtures/hiera/hiera.yaml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
:backends:
|
||||
- yaml
|
||||
:yaml:
|
||||
:datadir: 'spec/fixtures/hiera'
|
||||
:hierarchy:
|
||||
- fqdn/%{fqdn}
|
||||
- parameter_tests/%{parameter_tests}
|
||||
11
modules/build/unix/swap_file/spec/fixtures/hiera/parameter_tests/files_hiera_merge.yaml
vendored
Normal file
11
modules/build/unix/swap_file/spec/fixtures/hiera/parameter_tests/files_hiera_merge.yaml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
swap_file::files:
|
||||
'swap1':
|
||||
ensure: 'present'
|
||||
swapfile: '/mnt/swap.1'
|
||||
swapfilesize: '1 GB'
|
||||
'swap2':
|
||||
ensure: 'present'
|
||||
swapfile: '/mnt/swap.2'
|
||||
swapfilesize: '2 GB'
|
||||
cmd: 'fallocate'
|
||||
@@ -0,0 +1,20 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'difference_within_margin' do
|
||||
it { is_expected.not_to eq(nil) }
|
||||
it { is_expected.to run.with_params([]).and_raise_error(Puppet::ParseError, /Wrong number of arguments given \(1 for 2\)/i) }
|
||||
it { is_expected.to run.with_params(['1','2']).and_raise_error(Puppet::ParseError, /Wrong number of arguments given \(1 for 2\)/i) }
|
||||
it { is_expected.to run.with_params([],'2').and_raise_error(Puppet::ParseError, /arg\[0\] array cannot be empty/i) }
|
||||
|
||||
it { is_expected.to run.with_params([100,150],60).and_return(true) }
|
||||
it { is_expected.to run.with_params([100,150],40).and_return(false) }
|
||||
it { is_expected.to run.with_params([213909504, 209711104], 5242880).and_return(true) }
|
||||
it { is_expected.to run.with_params([104853504,209715200],5242880).and_return(false) }
|
||||
|
||||
it { is_expected.to run.with_params(['100','150'],'60').and_return(true) }
|
||||
it { is_expected.to run.with_params(['100','150'],'40').and_return(false) }
|
||||
it { is_expected.to run.with_params(['213909504','209711104'],'5242880').and_return(true) }
|
||||
it { is_expected.to run.with_params(['104853504','209715200'],'5242880').and_return(false) }
|
||||
|
||||
|
||||
end
|
||||
@@ -0,0 +1,12 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'swap_file_size_from_csv' do
|
||||
it { is_expected.not_to eq(nil) }
|
||||
it { is_expected.to run.with_params([]).and_raise_error(Puppet::ParseError, /Wrong number of arguments given \(1 for 2\)/i) }
|
||||
it { is_expected.to run.with_params(['1','2']).and_raise_error(Puppet::ParseError, /Wrong number of arguments given \(1 for 2\)/i) }
|
||||
it { is_expected.to run.with_params([],'2').and_raise_error(Puppet::ParseError, /swapfile name but be a string/i) }
|
||||
|
||||
it { is_expected.to run.with_params('/mnt/swap.1','/mnt/swap.1||1019900,/mnt/swap.1||1019900').and_return('1019900') }
|
||||
it { is_expected.to run.with_params('/mnt/swap.2','/mnt/swap.1||1019900,/mnt/swap.1||1019900').and_return(false) }
|
||||
|
||||
end
|
||||
6
modules/build/unix/swap_file/spec/spec.opts
Normal file
6
modules/build/unix/swap_file/spec/spec.opts
Normal file
@@ -0,0 +1,6 @@
|
||||
--format
|
||||
s
|
||||
--colour
|
||||
--loadby
|
||||
mtime
|
||||
--backtrace
|
||||
24
modules/build/unix/swap_file/spec/spec_helper.rb
Normal file
24
modules/build/unix/swap_file/spec/spec_helper.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
require 'puppetlabs_spec_helper/module_spec_helper'
|
||||
|
||||
# SimpleCov does not run on Ruby 1.8.7
|
||||
unless RUBY_VERSION.to_f < 1.9
|
||||
require 'simplecov'
|
||||
require 'simplecov-console'
|
||||
SimpleCov.formatters = [
|
||||
SimpleCov::Formatter::HTMLFormatter,
|
||||
SimpleCov::Formatter::Console,
|
||||
]
|
||||
SimpleCov.start do
|
||||
coverage_dir('coverage/')
|
||||
add_filter('/spec/')
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.hiera_config = 'spec/fixtures/hiera/hiera.yaml'
|
||||
config.expect_with :rspec do |c|
|
||||
c.max_formatted_output_length = 999
|
||||
end
|
||||
end
|
||||
|
||||
at_exit { RSpec::Puppet::Coverage.report! }
|
||||
33
modules/build/unix/swap_file/spec/spec_helper_acceptance.rb
Normal file
33
modules/build/unix/swap_file/spec/spec_helper_acceptance.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
require 'beaker-rspec'
|
||||
|
||||
unless ENV['RS_PROVISION'] == 'no'
|
||||
hosts.each do |host|
|
||||
if host.is_pe?
|
||||
install_pe
|
||||
else
|
||||
install_puppet
|
||||
on host, "mkdir -p #{host['distmoduledir']}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
UNSUPPORTED_PLATFORMS = ['windows']
|
||||
|
||||
RSpec.configure do |c|
|
||||
# Project root
|
||||
proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
||||
|
||||
# Readable test descriptions
|
||||
c.formatter = :documentation
|
||||
|
||||
# Configure all nodes in nodeset
|
||||
c.before :suite do
|
||||
# Install module and dependencies
|
||||
puppet_module_install(:source => proj_root, :module_name => 'swap_file')
|
||||
hosts.each do |host|
|
||||
shell('puppet module install puppetlabs-stdlib --version 4.7.0', { :acceptable_exit_codes => [0] })
|
||||
shell('puppet module install herculesteam/augeasproviders_core --version 2.1.0', { :acceptable_exit_codes => [0] })
|
||||
shell('puppet module install herculesteam/augeasproviders_sysctl --version 2.1.0', { :acceptable_exit_codes => [0] })
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,46 @@
|
||||
require "spec_helper"
|
||||
|
||||
describe Facter::Util::Fact do
|
||||
before {
|
||||
Facter.clear
|
||||
}
|
||||
|
||||
describe 'swapfile_sizes_csv' do
|
||||
context 'returns swapfile_sizes when present' do
|
||||
before do
|
||||
Facter.fact(:kernel).stubs(:value).returns("Linux")
|
||||
File.stubs(:exists?)
|
||||
File.expects(:exists?).with('/proc/swaps').returns(true)
|
||||
Facter::Util::Resolution.stubs(:exec)
|
||||
end
|
||||
it do
|
||||
proc_swap_output = <<-EOS
|
||||
Filename Type Size Used Priority
|
||||
/dev/dm-1 partition 524284 0 -1
|
||||
/mnt/swap.1 file 204796 0 -2
|
||||
/tmp/swapfile.fallocate file 204796 0 -3
|
||||
EOS
|
||||
Facter::Util::Resolution.expects(:exec).with('cat /proc/swaps').returns(proc_swap_output)
|
||||
expect(Facter.value(:swapfile_sizes_csv)).to eq('/mnt/swap.1||204796,/tmp/swapfile.fallocate||204796')
|
||||
end
|
||||
end
|
||||
|
||||
context 'returns nil when no swapfiles' do
|
||||
before do
|
||||
Facter.fact(:kernel).stubs(:value).returns("Linux")
|
||||
File.stubs(:exists?)
|
||||
File.expects(:exists?).with('/proc/swaps').returns(true)
|
||||
Facter::Util::Resolution.stubs(:exec)
|
||||
end
|
||||
it do
|
||||
proc_swap_output = <<-EOS
|
||||
Filename Type Size Used Priority
|
||||
/dev/dm-2 partition 16612860 0 -1
|
||||
EOS
|
||||
Facter::Util::Resolution.expects(:exec).with('cat /proc/swaps').returns(proc_swap_output)
|
||||
expect(Facter.value(:swapfile_sizes_csv)).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,34 @@
|
||||
require "spec_helper"
|
||||
|
||||
describe Facter::Util::Fact do
|
||||
before {
|
||||
Facter.clear
|
||||
}
|
||||
|
||||
describe 'swapfile_sizes' do
|
||||
context 'returns swapfile_sizes when present' do
|
||||
before do
|
||||
Facter.fact(:kernel).stubs(:value).returns("Linux")
|
||||
File.stubs(:exists?)
|
||||
File.expects(:exists?).with('/proc/swaps').returns(true)
|
||||
Facter::Util::Resolution.stubs(:exec)
|
||||
end
|
||||
it do
|
||||
proc_swap_output = <<-EOS
|
||||
Filename Type Size Used Priority
|
||||
/dev/dm-1 partition 524284 0 -1
|
||||
/mnt/swap.1 file 204796 0 -2
|
||||
/tmp/swapfile.fallocate file 204796 0 -3
|
||||
EOS
|
||||
Facter::Util::Resolution.expects(:exec).with('cat /proc/swaps').returns(proc_swap_output)
|
||||
expect(Facter.value(:swapfile_sizes)).to eq(
|
||||
{
|
||||
"/mnt/swap.1"=>"204796",
|
||||
"/tmp/swapfile.fallocate"=>"204796"
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,93 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Puppet::Type.type(:swap_file).provider(:linux) do
|
||||
|
||||
let(:resource) { Puppet::Type.type(:swap_file).new(
|
||||
{
|
||||
:name => '/tmp/swap',
|
||||
:size => '1024',
|
||||
:provider => described_class.name
|
||||
}
|
||||
)}
|
||||
|
||||
let(:provider) { resource.provider }
|
||||
|
||||
let(:instance) { provider.class.instances.first }
|
||||
|
||||
swapon_s_output = <<-EOS
|
||||
Filename Type Size Used Priority
|
||||
/dev/sda2 partition 4192956 0 -1
|
||||
/dev/sda1 partition 4454542 0 -2
|
||||
EOS
|
||||
|
||||
swapon_line = <<-EOS
|
||||
/dev/sda2 partition 4192956 0 -1
|
||||
EOS
|
||||
|
||||
mkswap_return = <<-EOS
|
||||
Setting up swapspace version 1, size = 524284 KiB
|
||||
no label, UUID=0e5e7c60-bbba-4089-a76c-2bb29c0f0839
|
||||
EOS
|
||||
|
||||
swapon_line_to_hash = {
|
||||
:ensure => :present,
|
||||
:file => "/dev/sda2",
|
||||
:name => "/dev/sda2",
|
||||
:priority => "-1",
|
||||
:provider => :swap_file,
|
||||
:size => "4192956",
|
||||
:type => "partition",
|
||||
:used => "0",
|
||||
}
|
||||
|
||||
before :each do
|
||||
Facter.stubs(:value).with(:kernel).returns('Linux')
|
||||
provider.class.stubs(:swapon).with(['-s']).returns(swapon_s_output)
|
||||
end
|
||||
|
||||
describe 'self.prefetch' do
|
||||
it 'exists' do
|
||||
provider.class.instances
|
||||
provider.class.prefetch({})
|
||||
end
|
||||
end
|
||||
|
||||
describe 'exists?' do
|
||||
it 'checks if swap file exists' do
|
||||
expect(instance.exists?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe 'self.instances' do
|
||||
it 'returns an array of swapfiles' do
|
||||
swapfiles = provider.class.instances.collect {|x| x.name }
|
||||
swapfile_sizes = provider.class.instances.collect {|x| x.size }
|
||||
|
||||
expect(swapfiles).to include('/dev/sda1','/dev/sda2')
|
||||
expect(swapfile_sizes).to include('4192956','4454542')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'self.get_swapfile_properties' do
|
||||
it 'turns results from swapon -s line to hash' do
|
||||
swapon_line_to_hash_provider = provider.class.get_swapfile_properties(swapon_line)
|
||||
expect(swapon_line_to_hash_provider).to eql swapon_line_to_hash
|
||||
end
|
||||
end
|
||||
|
||||
describe 'create_swap_file' do
|
||||
it 'runs mkswap and swapon' do
|
||||
provider.stubs(:mkswap).returns(mkswap_return)
|
||||
provider.stubs(:swapon).returns('')
|
||||
provider.create_swap_file('/tmp/swap')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'swap_off' do
|
||||
it 'runs swapoff and returns the log of the command' do
|
||||
provider.stubs(:swapoff).returns('')
|
||||
provider.swap_off('/tmp/swap')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Puppet::Type.type(:swap_file) do
|
||||
|
||||
before do
|
||||
@class = described_class
|
||||
@provider_class = @class.provide(:fake) { mk_resource_methods }
|
||||
@provider = @provider_class.new
|
||||
@resource = stub 'resource', :resource => nil, :provider => @provider
|
||||
|
||||
@class.stubs(:defaultprovider).returns @provider_class
|
||||
@class.any_instance.stubs(:provider).returns @provider
|
||||
end
|
||||
|
||||
it "should have :name as its keyattribute" do
|
||||
expect(@class.key_attributes).to eq([:file])
|
||||
end
|
||||
|
||||
describe "when validating attributes" do
|
||||
|
||||
params = [
|
||||
:file,
|
||||
]
|
||||
|
||||
properties = [
|
||||
:type,
|
||||
:size,
|
||||
:used,
|
||||
:priority,
|
||||
]
|
||||
|
||||
params.each do |param|
|
||||
it "should have a #{param} parameter" do
|
||||
expect(@class.attrtype(param)).to eq(:param)
|
||||
end
|
||||
end
|
||||
|
||||
properties.each do |prop|
|
||||
it "should have a #{prop} property" do
|
||||
expect(@class.attrtype(prop)).to eq(:property)
|
||||
end
|
||||
end
|
||||
|
||||
%w[. ./foo \foo C:/foo \\Server\Foo\Bar \\?\C:\foo\bar \/?/foo\bar \/Server/foo foo//bar/baz].each do |invalid_path|
|
||||
context "path => #{invalid_path}" do
|
||||
it 'should require a valid path for file' do
|
||||
expect {
|
||||
@class.new({:file => invalid_path})
|
||||
}.to raise_error(Puppet::ResourceError, /file parameter must be a valid absolute path/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%w[/ /foo /foo/../bar //foo //Server/Foo/Bar //?/C:/foo/bar /\Server/Foo /foo//bar/baz].each do |valid_path|
|
||||
context "path => #{valid_path}" do
|
||||
it 'should allow a valid path for file' do
|
||||
expect {
|
||||
@class.new({:file => valid_path})
|
||||
}.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
11
modules/build/unix/swap_file/swap_file.pp
Normal file
11
modules/build/unix/swap_file/swap_file.pp
Normal file
@@ -0,0 +1,11 @@
|
||||
$secgen_params = secgen_functions::get_parameters($::base64_inputs_file)
|
||||
$swapfile_size = $secgen_params['size'][0]
|
||||
class { 'swap_file':
|
||||
files => {
|
||||
'swap1' => {
|
||||
ensure => present,
|
||||
swapfile => '/mnt/swap.1',
|
||||
swapfilesize => $swapfile_size,
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -31,7 +31,7 @@ class FilenameGenerator < StringEncoder
|
||||
extension = ''
|
||||
end
|
||||
|
||||
15.times { leaked_filenames << Faker::File.file_name('', file_name, extension, '').chomp('.') }
|
||||
15.times { leaked_filenames << Faker::File.file_name(dir:'', name:file_name, ext:extension, directory_separator: '').chomp('.') }
|
||||
|
||||
output = leaked_filenames.sample
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ class RandomDifficulty < StringGenerator
|
||||
end
|
||||
|
||||
def generate
|
||||
outputs << %w(easy medium high).sample.chomp
|
||||
outputs << %w(easy medium hard).sample.chomp
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/ruby
|
||||
require_relative '../../../../../lib/objects/local_string_encoder.rb'
|
||||
|
||||
class AccountGenerator < StringEncoder
|
||||
attr_accessor :username
|
||||
attr_accessor :password
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/ruby
|
||||
require 'json'
|
||||
require_relative '../../../../../../lib/objects/local_string_generator.rb'
|
||||
|
||||
class GoalFlagHacktivity < StringGenerator
|
||||
attr_accessor :target
|
||||
attr_accessor :mapping
|
||||
attr_accessor :mapping_type
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Goal-Flag to Hacktivity AlertActioner Config Generator'
|
||||
self.target = '' # Address for Hacktivity / external web application
|
||||
self.mapping = [] # TODO: Implement granular mappings
|
||||
self.mapping_type = ''
|
||||
end
|
||||
|
||||
def generate
|
||||
# TODO: Create an enum-like hash/class to validate the mapping_types
|
||||
self.outputs << {:target => self.target, :mapping => self.mapping, :mapping_type => self.mapping_type}.to_json
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
super + [['--target', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--mapping', GetoptLong::OPTIONAL_ARGUMENT],
|
||||
['--mapping_type', GetoptLong::OPTIONAL_ARGUMENT]]
|
||||
end
|
||||
|
||||
def process_options(opt, arg)
|
||||
super
|
||||
case opt
|
||||
when '--target'
|
||||
self.target = arg
|
||||
when '--mapping'
|
||||
self.mapping << arg
|
||||
when '--mapping_type'
|
||||
self.mapping_type << arg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
GoalFlagHacktivity.new.run
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>AlertActioner goal-flag-hacktivity config generator</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>TODO</description>
|
||||
|
||||
<type>alert_actioner_config</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>target</read_fact>
|
||||
|
||||
<!-- Either provide a mapping (i.e. [system1vuln1goal1 to system1vuln1goal_flag1, ... ] OR a broader mapping_type -->
|
||||
<read_fact>mapping</read_fact>
|
||||
<read_fact>mapping_type</read_fact>
|
||||
|
||||
<default_input into="target">
|
||||
<value>https://hacktivity.aet.leedsbeckett.ac.uk/submit_flag</value>
|
||||
</default_input>
|
||||
|
||||
<!-- Mapping types tell the project_file_creator what to do.-->
|
||||
<default_input into="mapping_type">
|
||||
<value>all_goal_flags_to_hacktivity</value>
|
||||
</default_input>
|
||||
|
||||
<output_type>json</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/ruby
|
||||
require 'json'
|
||||
require_relative '../../../../../../lib/objects/local_string_generator.rb'
|
||||
|
||||
# Generate a config hash for the XmlAlertActionConfigGenerator
|
||||
class GoalMessageHost < StringGenerator
|
||||
attr_accessor :host
|
||||
attr_accessor :sender
|
||||
attr_accessor :password
|
||||
attr_accessor :recipient
|
||||
attr_accessor :message_header
|
||||
attr_accessor :message_subtext
|
||||
attr_accessor :mapping
|
||||
attr_accessor :mapping_type
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Goal-Message-Host AlertActioner Config Generator'
|
||||
self.host = '' # Host IP
|
||||
self.sender = '' # Host username
|
||||
self.password = '' # Host password
|
||||
self.recipient = '' # Host password
|
||||
self.message_header = '' # Message to send to host
|
||||
self.message_subtext = '' # Message to send to host
|
||||
self.mapping = [] # TODO: Implement granular mappings
|
||||
self.mapping_type = ''
|
||||
end
|
||||
|
||||
def generate
|
||||
self.outputs << {:host => self.host, :sender => self.sender, :password => self.password, :recipient => self.recipient, :message_header => self.message_header, :message_subtext => self.message_subtext, :mapping => self.mapping, :mapping_type => self.mapping_type}.to_json
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
super + [['--host', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--sender', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--password', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--recipient', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--message_header', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--message_subtext', GetoptLong::OPTIONAL_ARGUMENT],
|
||||
['--mapping', GetoptLong::OPTIONAL_ARGUMENT],
|
||||
['--mapping_type', GetoptLong::OPTIONAL_ARGUMENT]]
|
||||
end
|
||||
|
||||
def process_options(opt, arg)
|
||||
super
|
||||
case opt
|
||||
when '--host'
|
||||
self.host = arg
|
||||
when '--sender'
|
||||
self.sender = arg
|
||||
when '--password'
|
||||
self.password = arg
|
||||
when '--recipient'
|
||||
self.recipient = arg
|
||||
when '--message_header'
|
||||
self.message_header = arg
|
||||
when '--message_subtext'
|
||||
self.message_subtext = arg
|
||||
when '--mapping'
|
||||
self.mapping << arg
|
||||
when '--mapping_type'
|
||||
self.mapping_type = arg
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
GoalMessageHost.new.run
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>AlertActioner goal-message-host config generator</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>Generates a json config string for use by the XmlAlertActionConfigGenerator.</description>
|
||||
|
||||
<type>alert_actioner_config</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>host</read_fact>
|
||||
<read_fact>sender</read_fact>
|
||||
<read_fact>password</read_fact>
|
||||
<read_fact>recipient</read_fact>
|
||||
<read_fact>message_header</read_fact>
|
||||
<read_fact>message_subtext</read_fact>
|
||||
|
||||
<!-- Either provide a mapping (i.e. [system1vuln1goal1 to system1vuln1goal_flag1, ... ] OR a broader mapping_type -->
|
||||
<read_fact>mapping</read_fact>
|
||||
<read_fact>mapping_type</read_fact>
|
||||
|
||||
<default_input into="message_header">
|
||||
<generator type="message_generator"/>
|
||||
<value>Message header from the module</value>
|
||||
</default_input>
|
||||
|
||||
<default_input into="message_subtext">
|
||||
<!--<generator type="message_generator"/>-->
|
||||
<value>Subtext from the module</value>
|
||||
</default_input>
|
||||
|
||||
<default_input into="host">
|
||||
<value>127.0.0.1</value>
|
||||
</default_input>
|
||||
|
||||
<!-- Mapping types tell the project_file_creator what to do.-->
|
||||
<default_input into="mapping_type">
|
||||
<value>all_goal_messages_to_host</value>
|
||||
</default_input>
|
||||
|
||||
<output_type>json</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/ruby
|
||||
require 'json'
|
||||
require_relative '../../../../../lib/objects/local_string_generator.rb'
|
||||
|
||||
class AAAConfigGenerator < StringGenerator
|
||||
attr_accessor :server_ip
|
||||
attr_accessor :client_ips
|
||||
attr_accessor :elasticsearch_port
|
||||
attr_accessor :logstash_port
|
||||
attr_accessor :kibana_port
|
||||
attr_accessor :aa_configs
|
||||
|
||||
def initialize
|
||||
super
|
||||
self.module_name = 'Analysis Alert Action Config Generator'
|
||||
self.client_ips = []
|
||||
self.aa_configs = []
|
||||
end
|
||||
|
||||
def generate
|
||||
|
||||
# Validate the inputs + crash out if we don't receive all inputs.
|
||||
self.outputs << {
|
||||
:server_ip => self.server_ip,
|
||||
:client_ips => self.client_ips,
|
||||
:elasticsearch_port => self.elasticsearch_port,
|
||||
:logstash_port => self.logstash_port,
|
||||
:kibana_port => self.kibana_port,
|
||||
:aa_configs => self.aa_configs
|
||||
}.to_json
|
||||
end
|
||||
|
||||
def get_options_array
|
||||
super + [['--server_ip', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--client_ips', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--elasticsearch_port', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--logstash_port', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--kibana_port', GetoptLong::REQUIRED_ARGUMENT],
|
||||
['--aa_configs', GetoptLong::REQUIRED_ARGUMENT]]
|
||||
end
|
||||
|
||||
def process_options(opt, arg)
|
||||
super
|
||||
case opt
|
||||
when '--server_ip'
|
||||
self.server_ip = arg
|
||||
when '--client_ips'
|
||||
self.client_ips << arg
|
||||
when '--elasticsearch_port'
|
||||
self.elasticsearch_port = arg
|
||||
when '--logstash_port'
|
||||
self.logstash_port = arg
|
||||
when '--kibana_port'
|
||||
self.kibana_port = arg
|
||||
when '--aa_configs'
|
||||
self.aa_configs << JSON.parse(arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
AAAConfigGenerator.new.run
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<generator xmlns="http://www.github/cliffe/SecGen/generator"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
|
||||
<name>AAA config generator</name>
|
||||
<author>Thomas Shaw</author>
|
||||
<module_license>GPLv3</module_license>
|
||||
<description>TODO</description>
|
||||
|
||||
<type>aaa_config</type>
|
||||
<platform>linux</platform>
|
||||
|
||||
<read_fact>server_ip</read_fact>
|
||||
<read_fact>client_ips</read_fact>
|
||||
<read_fact>elasticsearch_port</read_fact>
|
||||
<read_fact>logstash_port</read_fact>
|
||||
<read_fact>kibana_port</read_fact>
|
||||
<read_fact>aa_configs</read_fact>
|
||||
|
||||
<output_type>json</output_type>
|
||||
|
||||
</generator>
|
||||
@@ -0,0 +1,27 @@
|
||||
$secgen_parameters = secgen_functions::get_parameters($::base64_inputs_file)
|
||||
$aaa_config = parsejson($secgen_parameters['aaa_config'][0])
|
||||
$elasticsearch_ip = $aaa_config['server_ip']
|
||||
$elasticsearch_port = 0 + $aaa_config['elasticsearch_port']
|
||||
$logstash_port = 0 + $aaa_config['logstash_port']
|
||||
$kibana_ip = $aaa_config['server_ip']
|
||||
$kibana_port = 0 + $aaa_config['kibana_port']
|
||||
|
||||
class { 'elasticsearch_7':
|
||||
api_host => $elasticsearch_ip,
|
||||
api_port => $elasticsearch_port,
|
||||
}~>
|
||||
class { 'logstash_7':
|
||||
elasticsearch_ip => $elasticsearch_ip,
|
||||
elasticsearch_port => $elasticsearch_port,
|
||||
logstash_port => $logstash_port
|
||||
}
|
||||
class { 'kibana_7':
|
||||
elasticsearch_ip => $elasticsearch_ip,
|
||||
elasticsearch_port => $elasticsearch_port,
|
||||
kibana_port => $kibana_port
|
||||
}~>
|
||||
class { 'elastalert':
|
||||
elasticsearch_ip => $elasticsearch_ip,
|
||||
elasticsearch_port => $elasticsearch_port,
|
||||
}~>
|
||||
class { 'analysis_alert_action_server': }
|
||||
@@ -0,0 +1,46 @@
|
||||
require 'fileutils'
|
||||
require 'erb'
|
||||
require_relative '../lib/logging'
|
||||
require_relative '../lib/print'
|
||||
require_relative '../lib/aa_constants'
|
||||
|
||||
class AlertActioner
|
||||
include Logging
|
||||
|
||||
attr_accessor :alertactioner_name # AlertActioner name - ID for this particular action
|
||||
attr_accessor :alert_name # Alert / Rule name - ID for elastalert rule that was triggered
|
||||
|
||||
def initialize(config_filename, alertaction_index, alert_name)
|
||||
self.alertactioner_name = config_filename[0..-5] + '-' + alertaction_index.to_s + '-' + alertaction_index.to_s # Remove .xml extension
|
||||
self.alert_name = alert_name
|
||||
end
|
||||
|
||||
def perform_action
|
||||
# override me
|
||||
end
|
||||
|
||||
def action_alert
|
||||
Print.info("Running #{self.class}: #{self.alertactioner_name}", logger)
|
||||
Print.info("Actioning alert: #{self.alert_name}", logger)
|
||||
perform_action
|
||||
|
||||
end
|
||||
|
||||
def template_based_file_write(template, filename)
|
||||
template_out = ERB.new(File.read(template), 0, '<>-')
|
||||
|
||||
begin
|
||||
File.open(filename, 'wb+') do |file|
|
||||
file.write(template_out.result(self.get_binding))
|
||||
end
|
||||
rescue StandardError => e
|
||||
Print.err "Error writing file: #{e.message}"
|
||||
Print.err e.backtrace.inspect
|
||||
end
|
||||
end
|
||||
|
||||
def get_binding
|
||||
binding
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,57 @@
|
||||
require 'net/http'
|
||||
require 'uri'
|
||||
require 'open3'
|
||||
require_relative 'alert_actioner'
|
||||
|
||||
class CommandActioner < AlertActioner
|
||||
|
||||
attr_accessor :host
|
||||
attr_accessor :username
|
||||
attr_accessor :password
|
||||
attr_accessor :commands
|
||||
|
||||
|
||||
def initialize(config_filename, alertaction_index, alert_name, host, username, password, commands=[])
|
||||
super(config_filename, alertaction_index, alert_name)
|
||||
self.host = host
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.commands = commands
|
||||
end
|
||||
|
||||
def perform_action
|
||||
# Create config/commands directory
|
||||
FileUtils.mkdir_p COMMANDS_DIRECTORY
|
||||
commands_sh_path = COMMANDS_DIRECTORY + "#{self.alertactioner_name}.sh"
|
||||
template_path = TEMPLATES_DIRECTORY + 'command.sh.erb'
|
||||
|
||||
# We need to populate an array of commands + their parameters
|
||||
@shell_commands = command_strings
|
||||
template_based_file_write(template_path, commands_sh_path)
|
||||
|
||||
ssh_command = "sshpass -p #{self.password} ssh -oStrictHostKeyChecking=no #{self.username}@#{self.host} /bin/bash -s < #{commands_sh_path}"
|
||||
|
||||
Print.info " Command strings:\n #{@shell_commands.join("\n ")}"
|
||||
|
||||
stdout, stderr, status = Open3.capture3(ssh_command)
|
||||
Print.info " stdout: #{stdout}", logger
|
||||
Print.info " stderr: #{stderr}", logger if stderr != ''
|
||||
Print.info " STATUS: #{status}", logger
|
||||
|
||||
unless status.exitstatus == 0
|
||||
Print.info " ERROR: non-zero exit code.", logger
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
def command_strings
|
||||
self.commands
|
||||
# For more specific command-actioners, override me.
|
||||
end
|
||||
|
||||
# TODO: Override me in superclass to print actioner type + all parameters??
|
||||
def to_s
|
||||
"#{self.class}:\n Host: #{self.host}\n Command: #{self.command}\n Parameters: #{self.parameters.join(',')}"
|
||||
end
|
||||
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user