dust-deploy 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/changelog.md +7 -0
- data/lib/dust.rb +0 -1
- data/lib/dust/examples/templates/hash_check/weak_passwords +26 -0
- data/lib/dust/helper.rb +21 -0
- data/lib/dust/recipes/aliases.rb +2 -1
- data/lib/dust/recipes/basic_setup.rb +1 -1
- data/lib/dust/recipes/duplicity.rb +4 -6
- data/lib/dust/recipes/etc_hosts.rb +1 -1
- data/lib/dust/recipes/hash_check.rb +44 -0
- data/lib/dust/recipes/motd.rb +2 -6
- data/lib/dust/recipes/mysql.rb +1 -4
- data/lib/dust/recipes/newrelic.rb +4 -2
- data/lib/dust/recipes/nginx.rb +4 -20
- data/lib/dust/recipes/postgres.rb +8 -28
- data/lib/dust/recipes/zabbix_agent.rb +13 -20
- data/lib/dust/server.rb +157 -61
- data/lib/dust/version.rb +1 -1
- metadata +5 -4
- data/lib/dust/convert_size.rb +0 -21
data/changelog.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
Changelog
|
2
2
|
=============
|
3
3
|
|
4
|
+
0.4.2
|
5
|
+
------------
|
6
|
+
|
7
|
+
adds hash_check recipe, which can check for weak hashes (according to provided list) in your /etc/shadow files.
|
8
|
+
can be used e.g. for making sure that none of your servers still has the template password.
|
9
|
+
|
10
|
+
|
4
11
|
0.4.1
|
5
12
|
------------
|
6
13
|
|
data/lib/dust.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
root
|
2
|
+
toor
|
3
|
+
user
|
4
|
+
123456
|
5
|
+
12345
|
6
|
+
password
|
7
|
+
password1
|
8
|
+
123456789
|
9
|
+
12345678
|
10
|
+
1234567890
|
11
|
+
abc123
|
12
|
+
computer
|
13
|
+
tigger
|
14
|
+
1234
|
15
|
+
qwerty
|
16
|
+
money
|
17
|
+
carmen
|
18
|
+
mickey
|
19
|
+
secret
|
20
|
+
summer
|
21
|
+
internet
|
22
|
+
a1b2c3
|
23
|
+
123
|
24
|
+
service
|
25
|
+
hello
|
26
|
+
123abc
|
data/lib/dust/helper.rb
CHANGED
@@ -49,3 +49,24 @@ class String
|
|
49
49
|
false
|
50
50
|
end
|
51
51
|
end
|
52
|
+
|
53
|
+
|
54
|
+
module Dust
|
55
|
+
# converts string to kilobytes (rounded)
|
56
|
+
def self.convert_size s
|
57
|
+
i, unit = s.split(' ')
|
58
|
+
|
59
|
+
case unit.downcase
|
60
|
+
when 'kb'
|
61
|
+
return i.to_i
|
62
|
+
when 'mb'
|
63
|
+
return (i.to_f * 1024).to_i
|
64
|
+
when 'gb'
|
65
|
+
return (i.to_f * 1024 * 1024).to_i
|
66
|
+
when 'tb'
|
67
|
+
return (i.to_f * 1024 * 1024 * 1024).to_i
|
68
|
+
else
|
69
|
+
return false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/dust/recipes/aliases.rb
CHANGED
@@ -2,7 +2,8 @@ class Aliases < Recipe
|
|
2
2
|
desc 'aliases:deploy', 'installs email aliases'
|
3
3
|
def deploy
|
4
4
|
return unless @node.package_installed? 'postfix'
|
5
|
-
|
5
|
+
|
6
|
+
@node.deploy_file "#{@template_path}/aliases", '/etc/aliases', :binding => binding
|
6
7
|
|
7
8
|
::Dust.print_msg 'running newaliases'
|
8
9
|
::Dust.print_result @node.exec('newaliases')[:exit_code]
|
@@ -25,7 +25,7 @@ class BasicSetup < Recipe
|
|
25
25
|
::Dust.print_msg "deploying configuration files for root\n"
|
26
26
|
Dir["#{@template_path}/.*"].each do |file|
|
27
27
|
next unless File.file? file
|
28
|
-
@node.
|
28
|
+
@node.deploy_file file, "/root/#{File.basename file}", { :binding => binding, :indent => 2 }
|
29
29
|
end
|
30
30
|
|
31
31
|
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'erb'
|
2
|
-
|
3
1
|
class Duplicity < Recipe
|
4
2
|
desc 'duplicity:deploy', 'installs and configures duplicity backups'
|
5
3
|
def deploy
|
@@ -46,11 +44,11 @@ class Duplicity < Recipe
|
|
46
44
|
cronjob_path = "/etc/cron.#{config['interval']}/duplicity-#{scenario}"
|
47
45
|
|
48
46
|
# adjust and upload cronjob
|
49
|
-
|
50
|
-
::Dust.print_msg "adjusting and deploying cronjob (scenario: #{scenario}, interval: #{config['interval']})\n"
|
47
|
+
::Dust.print_msg "adjusting and deploying cronjob (scenario: #{scenario}, interval: #{config['interval']})\n"
|
51
48
|
config['options'].each { |option| ::Dust.print_ok "adding option: #{option}", :indent => 2 }
|
52
|
-
|
53
|
-
|
49
|
+
|
50
|
+
@node.deploy_file "#{@template_path}/cronjob", cronjob_path, :binding => binding
|
51
|
+
|
54
52
|
# making cronjob executeable
|
55
53
|
@node.chmod '0700', cronjob_path
|
56
54
|
puts
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class EtcHosts < Recipe
|
2
2
|
desc 'etc_hosts:deploy', 'deploys /etc/hosts'
|
3
3
|
def deploy
|
4
|
-
@node.
|
4
|
+
@node.deploy_file "#{@template_path}/hosts", '/etc/hosts', :binding => binding
|
5
5
|
|
6
6
|
# restart dns service
|
7
7
|
if @options.restart? and @config.is_a? String
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class HashCheck < Recipe
|
2
|
+
|
3
|
+
desc 'hash_check:deploy', 'checks /etc/shadow for weak hashes'
|
4
|
+
def deploy
|
5
|
+
# mkpasswd is in the package 'whois' resp. 'expect'
|
6
|
+
@node.install_package 'whois' if @node.uses_apt?
|
7
|
+
@node.install_package 'expect' if @node.uses_rpm?
|
8
|
+
|
9
|
+
# those keys indicate that no password is set, or login is disabled
|
10
|
+
keys = [ '*', '!', '!!', '', 'LK', 'NP' ]
|
11
|
+
|
12
|
+
# mapping the magic numbers to the actual hash algorithms
|
13
|
+
algorithms = { '1' => 'md5', '2' => 'blowfish', '5' => 'sha-256', '6' => 'sha-512' }
|
14
|
+
|
15
|
+
weak_passwords = File.open "#{@template_path}/weak_passwords", 'r'
|
16
|
+
shadow = @node.exec('cat /etc/shadow')[:stdout]
|
17
|
+
|
18
|
+
::Dust.print_msg "checking for weak password hashes\n"
|
19
|
+
|
20
|
+
found_weak = false
|
21
|
+
|
22
|
+
shadow.each do |line|
|
23
|
+
user, hash = line.split(':')[0..1]
|
24
|
+
next if keys.include? hash
|
25
|
+
method, salt = hash.split('$')[1..2]
|
26
|
+
|
27
|
+
weak_passwords.each_line do |password|
|
28
|
+
password.chomp!
|
29
|
+
|
30
|
+
# generate the hash for this password, according to salt and method
|
31
|
+
weak_hash = @node.exec("mkpasswd -m #{algorithms[method.to_s]} -S '#{salt}' '#{password}'")[:stdout]
|
32
|
+
weak_hash.chomp!
|
33
|
+
|
34
|
+
if weak_hash == hash
|
35
|
+
::Dust.print_failed "user #{user} has a weak password! (#{password})", :indent => 2
|
36
|
+
found_weak= true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
weak_passwords.close
|
42
|
+
::Dust.print_ok 'none found.', :indent => 2 unless found_weak
|
43
|
+
end
|
44
|
+
end
|
data/lib/dust/recipes/motd.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
|
-
require 'erb'
|
2
|
-
|
3
1
|
class Motd < Recipe
|
4
2
|
desc 'motd:deploy', 'creates message of the day'
|
5
|
-
def deploy
|
6
|
-
#
|
7
|
-
template = ERB.new File.read("#{@template_path}/motd.erb"), nil, '%<>'
|
8
|
-
@node.write '/etc/motd', template.result(binding)
|
3
|
+
def deploy
|
4
|
+
@node.deploy_file "#{@template_path}/motd", '/etc/motd', :binding => binding
|
9
5
|
end
|
10
6
|
end
|
data/lib/dust/recipes/mysql.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'erb'
|
2
|
-
|
3
1
|
class Mysql < Recipe
|
4
2
|
desc 'mysql:deploy', 'installs and configures mysql database'
|
5
3
|
def deploy
|
@@ -36,8 +34,7 @@ class Mysql < Recipe
|
|
36
34
|
|
37
35
|
::Dust.print_ok "setting innodb buffer pool to '#{@config['innodb_buffer_pool_size']}'", :indent => 2
|
38
36
|
|
39
|
-
|
40
|
-
@node.write '/etc/mysql/my.cnf', template.result(binding)
|
37
|
+
@node.deploy_file "#{@template_path}/my.cnf", '/etc/mysql/my.cnf', :binding => binding
|
41
38
|
@node.chmod '644', '/etc/mysql/my.cnf'
|
42
39
|
|
43
40
|
@node.restart_service 'mysql-server' if options.restart?
|
@@ -4,8 +4,10 @@ class Newrelic < Recipe
|
|
4
4
|
return Dust.print_failed 'no key specified' unless @config
|
5
5
|
return unless @node.uses_apt? :quiet=>false
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
if @options.restart? or @options.reload?
|
8
|
+
::Dust.print_msg 'updating repositories'
|
9
|
+
::Dust.print_result @node.exec('aptitude update')[:exit_code]
|
10
|
+
end
|
9
11
|
|
10
12
|
unless @node.install_package 'newrelic-sysmond'
|
11
13
|
::Dust.print_failed 'installing newrelic monitoring daemon failed, did you setup the newrelic repositories?'
|
data/lib/dust/recipes/nginx.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'erb'
|
2
|
-
|
3
1
|
class Nginx < Recipe
|
4
2
|
desc 'nginx:deploy', 'installs and configures nginx web server'
|
5
3
|
def deploy
|
@@ -14,27 +12,13 @@ class Nginx < Recipe
|
|
14
12
|
::Dust.print_ok
|
15
13
|
|
16
14
|
@config.each do |state, site|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
if File.exists? file
|
21
|
-
@node.scp file, "/etc/nginx/sites-available/#{site}"
|
22
|
-
|
23
|
-
# if this site is an erb template, render it and deploy
|
24
|
-
elsif File.exists? "#{file}.erb"
|
25
|
-
template = ERB.new( File.read("#{file}.erb"), nil, '%<>')
|
26
|
-
@node.write "/etc/nginx/sites-available/#{site}", template.result(binding)
|
27
|
-
|
28
|
-
# skip to next site if template wasn't found
|
29
|
-
else
|
30
|
-
::Dust.print_failed "couldn't find template for #{site}", :indent => 2
|
31
|
-
next
|
32
|
-
end
|
33
|
-
|
15
|
+
|
16
|
+
@node.deploy_file "#{@template_path}/sites/#{site}", "/etc/nginx/sites-available/#{site}", :binding => binding
|
17
|
+
|
34
18
|
# symlink to sites-enabled if this is listed as an enabled site
|
35
19
|
if state == 'sites-enabled'
|
36
20
|
::Dust.print_msg "enabling #{site}", :indent => 2
|
37
|
-
::Dust.print_result
|
21
|
+
::Dust.print_result @node.exec("cd /etc/nginx/sites-enabled && ln -s ../sites-available/#{site} #{site}")[:exit_code]
|
38
22
|
end
|
39
23
|
end
|
40
24
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'erb'
|
2
|
-
|
3
1
|
class Postgres < Recipe
|
4
2
|
desc 'postgres:deploy', 'installs and configures postgresql database'
|
5
3
|
def deploy
|
@@ -24,9 +22,9 @@ class Postgres < Recipe
|
|
24
22
|
end
|
25
23
|
|
26
24
|
|
27
|
-
deploy_file
|
28
|
-
deploy_file
|
29
|
-
deploy_file
|
25
|
+
@node.deploy_file "#{@template_path}/postgresql.conf", "#{@config['conf-dir']}/postgresql.conf", :binding => binding
|
26
|
+
@node.deploy_file "#{@template_path}/pg_hba.conf", "#{@config['conf-dir']}/pg_hba.conf", :binding => binding
|
27
|
+
@node.deploy_file "#{@template_path}/pg_ident.conf", "#{@config['conf-dir']}/pg_ident.conf", :binding => binding
|
30
28
|
|
31
29
|
@node.chmod '644', "#{@config['conf-dir']}/postgresql.conf"
|
32
30
|
@node.chmod '644', "#{@config['conf-dir']}/pg_hba.conf"
|
@@ -34,21 +32,21 @@ class Postgres < Recipe
|
|
34
32
|
|
35
33
|
# deploy pacemaker script
|
36
34
|
if @node.package_installed? 'pacemaker'
|
37
|
-
deploy_file
|
35
|
+
@node.deploy_file "#{@template_path}/pacemaker.sh", "#{@config['conf-dir']}/pacemaker.sh", :binding => binding
|
38
36
|
@node.chmod '755', "#{@config['conf-dir']}/pacemaker.sh"
|
39
37
|
end
|
40
38
|
|
41
39
|
# copy recovery.conf to either recovery.conf or recovery.done
|
42
40
|
# depending on which file already exists.
|
43
41
|
if @node.file_exists? "#{@config['data-dir']}/recovery.conf", :quiet => true
|
44
|
-
deploy_file
|
42
|
+
@node.deploy_file "#{@template_path}/recovery.conf", "#{@config['data-dir']}/recovery.conf", :binding => binding
|
45
43
|
else
|
46
|
-
deploy_file
|
44
|
+
@node.deploy_file "#{@template_path}/recovery.conf", "#{@config['data-dir']}/recovery.done", :binding => binding
|
47
45
|
end
|
48
46
|
|
49
47
|
# deploy certificates to data-dir
|
50
|
-
deploy_file
|
51
|
-
deploy_file
|
48
|
+
@node.deploy_file "#{@template_path}/server.crt", "#{@config['data-dir']}/server.crt", :binding => binding
|
49
|
+
@node.deploy_file "#{@template_path}/server.key", "#{@config['data-dir']}/server.key", :binding => binding
|
52
50
|
|
53
51
|
@node.chown @config['dbuser'], @config['data-dir'] if @config['dbuser']
|
54
52
|
@node.chmod 'u+Xrw,g-rwx,o-rwx', @config['data-dir']
|
@@ -91,23 +89,5 @@ class Postgres < Recipe
|
|
91
89
|
@node.reload_service @config['service-name'] if options.reload?
|
92
90
|
end
|
93
91
|
|
94
|
-
private
|
95
|
-
def deploy_file file, target
|
96
|
-
# if file is just a regular file, copy it to sites-available
|
97
|
-
if File.exists? "#{@template_path}/#{file}"
|
98
|
-
@node.scp "#{@template_path}/#{file}", target
|
99
|
-
|
100
|
-
# if file is an erb template, render it and deploy
|
101
|
-
elsif File.exists? "#{@template_path}/#{file}.erb"
|
102
|
-
::Dust.print_msg "adjusting and deploying #{file}"
|
103
|
-
template = ERB.new( File.read("#{@template_path}/#{file}.erb"), nil, '%<>')
|
104
|
-
::Dust.print_result @node.write(target, template.result(binding), :quiet => true)
|
105
|
-
|
106
|
-
# file was not found, return
|
107
|
-
else
|
108
|
-
return ::Dust.print_failed "file '#{@template_path}/#{file}' not found."
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
92
|
end
|
113
93
|
|
@@ -1,24 +1,16 @@
|
|
1
|
-
require 'erb'
|
2
|
-
|
3
1
|
class ZabbixAgent < Recipe
|
4
2
|
desc 'zabbix_agent:deploy', 'installs and configures zabbix agent'
|
5
3
|
def deploy
|
6
4
|
return unless install_zabbix
|
7
5
|
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
@node.
|
12
|
-
|
13
|
-
|
6
|
+
@node.deploy_file "#{@template_path}/zabbix_agentd.conf", '/etc/zabbix/zabbix_agentd.conf', :binding => binding
|
7
|
+
|
8
|
+
# set daemon name, according zu distribution
|
9
|
+
daemon = @node.uses_emerge? ? 'zabbix-agentd' : 'zabbix-agent'
|
10
|
+
|
14
11
|
# restart using new configuration
|
15
|
-
|
16
|
-
|
17
|
-
@node.restart_service 'zabbix-agentd' if options.restart?
|
18
|
-
else
|
19
|
-
@node.autostart_service 'zabbix-agent'
|
20
|
-
@node.restart_service 'zabbix-agent' if options.restart?
|
21
|
-
end
|
12
|
+
@node.autostart_service daemon
|
13
|
+
@node.restart_service daemon if options.restart?
|
22
14
|
end
|
23
15
|
|
24
16
|
private
|
@@ -26,15 +18,13 @@ class ZabbixAgent < Recipe
|
|
26
18
|
def install_zabbix
|
27
19
|
|
28
20
|
if @node.uses_apt?
|
21
|
+
# debsecan is needed for zabbix checks (security updates)
|
29
22
|
return false unless @node.install_package 'zabbix-agent'
|
30
|
-
|
31
|
-
# debsecan is needed for zabbix checks (security updates)
|
32
23
|
return false unless @node.install_package 'debsecan'
|
33
24
|
|
34
25
|
elsif @node.uses_emerge?
|
26
|
+
# glsa-check (part of gentoolkit) is needed for zabbix checks (security updates)
|
35
27
|
return false unless @node.install_package 'zabbix', :env => 'USE=agent'
|
36
|
-
|
37
|
-
# glsa-check (part of gentoolkit) is needed for zabbix checks (security updates)
|
38
28
|
return false unless @node.install_package 'gentoolkit'
|
39
29
|
|
40
30
|
elsif @node.uses_rpm?
|
@@ -49,6 +39,9 @@ class ZabbixAgent < Recipe
|
|
49
39
|
true
|
50
40
|
end
|
51
41
|
|
42
|
+
|
43
|
+
# below this line is unfinished code, not in use yet
|
44
|
+
|
52
45
|
# TODO (not yet finished)
|
53
46
|
desc 'zabbix_agent:postgres', 'configure postgres database for zabbix monitoring'
|
54
47
|
def postgres
|
@@ -69,7 +62,7 @@ class ZabbixAgent < Recipe
|
|
69
62
|
::Dust.print_result( @node.exec('createuser -U postgres zabbix -RSD')[:exit_code] )
|
70
63
|
end
|
71
64
|
|
72
|
-
# TODO: only GRANT is this is a master
|
65
|
+
# TODO: only GRANT is this is a master
|
73
66
|
::Dust.print_msg 'GRANT zabbix user access to postgres database'
|
74
67
|
::Dust.print_result( @node.exec('psql -U postgres -c "GRANT SELECT ON pg_stat_database TO zabbix" postgres')[:exit_code] )
|
75
68
|
|
data/lib/dust/server.rb
CHANGED
@@ -2,37 +2,41 @@ require 'rubygems'
|
|
2
2
|
require 'net/ssh'
|
3
3
|
require 'net/scp'
|
4
4
|
require 'net/ssh/proxy/socks5'
|
5
|
+
require 'erb'
|
5
6
|
|
6
7
|
module Dust
|
7
8
|
class Server
|
8
9
|
attr_reader :ssh
|
9
10
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@
|
11
|
+
def default_options options = {}
|
12
|
+
{ :quiet => false, :indent => 1 }.merge options
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize node
|
16
|
+
@node = node
|
17
|
+
@node['user'] ||= 'root'
|
18
|
+
@node['port'] ||= 22
|
19
|
+
@node['password'] ||= ''
|
16
20
|
end
|
17
21
|
|
18
22
|
def connect
|
19
|
-
Dust.print_hostname @
|
23
|
+
Dust.print_hostname @node['hostname']
|
20
24
|
begin
|
21
25
|
# connect to proxy if given
|
22
|
-
if @
|
23
|
-
host, port = @
|
26
|
+
if @node['proxy']
|
27
|
+
host, port = @node['proxy'].split ':'
|
24
28
|
proxy = Net::SSH::Proxy::SOCKS5.new host, port
|
25
29
|
else
|
26
30
|
proxy = nil
|
27
31
|
end
|
28
32
|
|
29
|
-
@ssh = Net::SSH.start @
|
30
|
-
{ :password => @
|
31
|
-
:port => @
|
33
|
+
@ssh = Net::SSH.start @node['fqdn'], @node['user'],
|
34
|
+
{ :password => @node['password'],
|
35
|
+
:port => @node['port'],
|
32
36
|
:proxy => proxy }
|
33
37
|
rescue Exception
|
34
|
-
error_message = "coudln't connect to #{@
|
35
|
-
error_message += " (via socks5 proxy #{@
|
38
|
+
error_message = "coudln't connect to #{@node['fqdn']}"
|
39
|
+
error_message += " (via socks5 proxy #{@node['proxy']})" if proxy
|
36
40
|
Dust.print_failed error_message
|
37
41
|
return false
|
38
42
|
end
|
@@ -66,7 +70,9 @@ module Dust
|
|
66
70
|
end
|
67
71
|
|
68
72
|
|
69
|
-
def write target, text, options={
|
73
|
+
def write target, text, options = {}
|
74
|
+
options = default_options.merge options
|
75
|
+
|
70
76
|
Dust.print_msg "deploying #{File.basename target}", options
|
71
77
|
|
72
78
|
# escape $ signs and \ at the end of line
|
@@ -84,40 +90,54 @@ module Dust
|
|
84
90
|
restorecon target, options # restore SELinux labels
|
85
91
|
end
|
86
92
|
|
87
|
-
def append target, text, options={
|
93
|
+
def append target, text, options = {}
|
94
|
+
options = default_options.merge options
|
95
|
+
|
88
96
|
Dust.print_msg "appending to #{File.basename target}", options
|
89
97
|
Dust.print_result exec("cat << EOF >> #{target}\n#{text}\nEOF")[:exit_code], options
|
90
98
|
end
|
91
99
|
|
92
|
-
def scp source, destination, options={
|
100
|
+
def scp source, destination, options = {}
|
101
|
+
options = default_options.merge options
|
102
|
+
|
93
103
|
Dust.print_msg "deploying #{File.basename(source)}", options
|
94
104
|
@ssh.scp.upload! source, destination
|
95
105
|
Dust.print_ok '', options
|
96
106
|
restorecon destination, options # restore SELinux labels
|
97
107
|
end
|
98
108
|
|
99
|
-
def symlink source, destination, options={
|
109
|
+
def symlink source, destination, options = {}
|
110
|
+
options = default_options.merge options
|
111
|
+
|
100
112
|
Dust.print_msg "symlinking #{File.basename(source)} to '#{destination}'", options
|
101
113
|
Dust.print_result exec("ln -s #{source} #{destination}")[:exit_code], options
|
102
114
|
restorecon destination, options # restore SELinux labels
|
103
115
|
end
|
104
116
|
|
105
|
-
def chmod mode, file, options={
|
117
|
+
def chmod mode, file, options = {}
|
118
|
+
options = default_options.merge options
|
119
|
+
|
106
120
|
Dust.print_msg "setting mode of #{File.basename(file)} to #{mode}", options
|
107
121
|
Dust.print_result exec("chmod -R #{mode} #{file}")[:exit_code], options
|
108
122
|
end
|
109
123
|
|
110
|
-
def chown user, file, options={
|
124
|
+
def chown user, file, options = {}
|
125
|
+
options = default_options.merge options
|
126
|
+
|
111
127
|
Dust.print_msg "setting owner of #{File.basename(file)} to #{user}", options
|
112
128
|
Dust.print_result exec("chown -R #{user} #{file}")[:exit_code], options
|
113
129
|
end
|
114
130
|
|
115
|
-
def rm file, options={
|
131
|
+
def rm file, options = {}
|
132
|
+
options = default_options.merge options
|
133
|
+
|
116
134
|
Dust.print_msg "deleting #{file}", options
|
117
135
|
Dust.print_result exec("rm -rf #{file}")[:exit_code], options
|
118
136
|
end
|
119
137
|
|
120
|
-
def mkdir dir, options={
|
138
|
+
def mkdir dir, options = {}
|
139
|
+
options = default_options.merge options
|
140
|
+
|
121
141
|
return true if dir_exists? dir, :quiet => true
|
122
142
|
|
123
143
|
Dust.print_msg "creating directory #{dir}", options
|
@@ -127,7 +147,9 @@ module Dust
|
|
127
147
|
|
128
148
|
# check if restorecon (selinux) is available
|
129
149
|
# if so, run it on "path" recursively
|
130
|
-
def restorecon path, options={
|
150
|
+
def restorecon path, options = {}
|
151
|
+
options = default_options.merge options
|
152
|
+
|
131
153
|
|
132
154
|
# if restorecon is not installed, just return true
|
133
155
|
ret = exec 'which restorecon'
|
@@ -137,7 +159,9 @@ module Dust
|
|
137
159
|
Dust.print_result exec("#{ret[:stdout].chomp} -R #{path}")[:exit_code], options
|
138
160
|
end
|
139
161
|
|
140
|
-
def get_system_users options={
|
162
|
+
def get_system_users options = {}
|
163
|
+
options = default_options.merge options
|
164
|
+
|
141
165
|
Dust.print_msg "getting all system users", options
|
142
166
|
ret = exec 'getent passwd |cut -d: -f1'
|
143
167
|
Dust.print_result ret[:exit_code], options
|
@@ -150,7 +174,9 @@ module Dust
|
|
150
174
|
end
|
151
175
|
|
152
176
|
# checks if one of the packages is installed
|
153
|
-
def package_installed? packages, options={
|
177
|
+
def package_installed? packages, options = {}
|
178
|
+
options = default_options.merge options
|
179
|
+
|
154
180
|
packages = [ packages ] if packages.is_a? String
|
155
181
|
|
156
182
|
Dust.print_msg "checking if #{packages.join(' or ')} is installed", options
|
@@ -168,10 +194,16 @@ module Dust
|
|
168
194
|
Dust.print_failed '', options
|
169
195
|
end
|
170
196
|
|
171
|
-
def install_package package, options={
|
172
|
-
|
197
|
+
def install_package package, options = {}
|
198
|
+
options = default_options.merge options
|
199
|
+
options[:env] ||= ''
|
200
|
+
|
201
|
+
if package_installed? package, :quiet=>true
|
202
|
+
return Dust.print_ok "package #{package} already installed"
|
203
|
+
end
|
204
|
+
|
205
|
+
Dust.print_msg "installing #{package}", :indent => options[:indent] + 1
|
173
206
|
|
174
|
-
Dust.print_msg "installing #{package}", {:quiet => options[:quiet], :indent => options[:indent] + 1}
|
175
207
|
if uses_apt?
|
176
208
|
exec "DEBIAN_FRONTEND=noninteractive aptitude install -y #{package}"
|
177
209
|
elsif uses_emerge?
|
@@ -186,7 +218,9 @@ module Dust
|
|
186
218
|
Dust.print_result package_installed? package, :quiet => true
|
187
219
|
end
|
188
220
|
|
189
|
-
def remove_package package, options={
|
221
|
+
def remove_package package, options = {}
|
222
|
+
options = default_options.merge options
|
223
|
+
|
190
224
|
unless package_installed? package, :quiet => true
|
191
225
|
return Dust.print_ok "package #{package} not installed", options
|
192
226
|
end
|
@@ -203,7 +237,9 @@ module Dust
|
|
203
237
|
end
|
204
238
|
end
|
205
239
|
|
206
|
-
def update_repos options={
|
240
|
+
def update_repos options = {}
|
241
|
+
options = default_options.merge options
|
242
|
+
|
207
243
|
Dust.print_msg 'updating system repositories', options
|
208
244
|
|
209
245
|
if uses_apt?
|
@@ -217,7 +253,9 @@ module Dust
|
|
217
253
|
end
|
218
254
|
end
|
219
255
|
|
220
|
-
def system_update options={
|
256
|
+
def system_update options = {}
|
257
|
+
options = default_options.merge options
|
258
|
+
|
221
259
|
Dust.print_msg 'installing system updates', options
|
222
260
|
|
223
261
|
if uses_apt?
|
@@ -241,27 +279,35 @@ module Dust
|
|
241
279
|
|
242
280
|
# determining the system packet manager has to be done without facter
|
243
281
|
# because it's used to find out whether facter is installed / install facter
|
244
|
-
def uses_apt? options={
|
282
|
+
def uses_apt? options = {}
|
283
|
+
options = default_options(:quiet => true).merge options
|
284
|
+
|
245
285
|
Dust.print_msg 'determining whether node uses apt', options
|
246
286
|
Dust.print_result exec('test -e /etc/debian_version')[:exit_code], options
|
247
287
|
end
|
248
288
|
|
249
|
-
def uses_rpm? options={
|
289
|
+
def uses_rpm? options = {}
|
290
|
+
options = default_options(:quiet => true).merge options
|
291
|
+
|
250
292
|
Dust.print_msg 'determining whether node uses rpm', options
|
251
293
|
Dust.print_result exec('test -e /etc/redhat-release')[:exit_code], options
|
252
294
|
end
|
253
295
|
|
254
|
-
def uses_emerge? options={
|
296
|
+
def uses_emerge? options = {}
|
297
|
+
options = default_options(:quiet => true).merge options
|
298
|
+
|
255
299
|
Dust.print_msg 'determining whether node uses emerge', options
|
256
300
|
Dust.print_result exec('test -e /etc/gentoo-release')[:exit_code], options
|
257
301
|
end
|
258
302
|
|
259
|
-
def is_os? os_list, options={
|
303
|
+
def is_os? os_list, options = {}
|
304
|
+
options = default_options(:quiet => true).merge options
|
305
|
+
|
260
306
|
Dust.print_msg "checking if this machine runs #{os_list.join(' or ')}", options
|
261
|
-
collect_facts options unless @
|
307
|
+
collect_facts options unless @node['operatingsystem']
|
262
308
|
|
263
309
|
os_list.each do |os|
|
264
|
-
if @
|
310
|
+
if @node['operatingsystem'].downcase == os.downcase
|
265
311
|
return Dust.print_ok '', options
|
266
312
|
end
|
267
313
|
end
|
@@ -270,46 +316,66 @@ module Dust
|
|
270
316
|
false
|
271
317
|
end
|
272
318
|
|
273
|
-
def is_debian? options={
|
319
|
+
def is_debian? options = {}
|
320
|
+
options = default_options(:quiet => true).merge options
|
321
|
+
|
274
322
|
is_os? ['debian'], options
|
275
323
|
end
|
276
324
|
|
277
|
-
def is_ubuntu? options={
|
325
|
+
def is_ubuntu? options = {}
|
326
|
+
options = default_options(:quiet => true).merge options
|
327
|
+
|
278
328
|
is_os? ['ubuntu'], options
|
279
329
|
end
|
280
330
|
|
281
|
-
def is_gentoo? options={
|
331
|
+
def is_gentoo? options = {}
|
332
|
+
options = default_options(:quiet => true).merge options
|
333
|
+
|
282
334
|
is_os? ['gentoo'], options
|
283
335
|
end
|
284
336
|
|
285
|
-
def is_centos? options={
|
337
|
+
def is_centos? options = {}
|
338
|
+
options = default_options(:quiet => true).merge options
|
339
|
+
|
286
340
|
is_os? ['centos'], options
|
287
341
|
end
|
288
342
|
|
289
|
-
def is_scientific? options={
|
343
|
+
def is_scientific? options = {}
|
344
|
+
options = default_options(:quiet => true).merge options
|
345
|
+
|
290
346
|
is_os? ['scientific'], options
|
291
347
|
end
|
292
348
|
|
293
|
-
def is_fedora? options={
|
349
|
+
def is_fedora? options = {}
|
350
|
+
options = default_options(:quiet => true).merge options
|
351
|
+
|
294
352
|
is_os? ['fedora'], options
|
295
353
|
end
|
296
354
|
|
297
|
-
def is_executable? file, options={
|
355
|
+
def is_executable? file, options = {}
|
356
|
+
options = default_options.merge options
|
357
|
+
|
298
358
|
Dust.print_msg "checking if file #{file} exists and is executeable", options
|
299
359
|
Dust.print_result exec("test -x $(which #{file})")[:exit_code], options
|
300
360
|
end
|
301
361
|
|
302
|
-
def file_exists? file, options={
|
362
|
+
def file_exists? file, options = {}
|
363
|
+
options = default_options.merge options
|
364
|
+
|
303
365
|
Dust.print_msg "checking if file #{file} exists", options
|
304
366
|
Dust.print_result exec("test -e #{file}")[:exit_code], options
|
305
367
|
end
|
306
368
|
|
307
|
-
def dir_exists? dir, options={
|
369
|
+
def dir_exists? dir, options = {}
|
370
|
+
options = default_options.merge options
|
371
|
+
|
308
372
|
Dust.print_msg "checking if directory #{dir} exists", options
|
309
373
|
Dust.print_result exec("test -d #{dir}")[:exit_code], options
|
310
374
|
end
|
311
375
|
|
312
|
-
def autostart_service service, options={
|
376
|
+
def autostart_service service, options = {}
|
377
|
+
options = default_options.merge options
|
378
|
+
|
313
379
|
Dust.print_msg "autostart #{service} on boot", options
|
314
380
|
if uses_rpm?
|
315
381
|
Dust.print_result exec("chkconfig #{service} on")[:exit_code], options
|
@@ -320,27 +386,37 @@ module Dust
|
|
320
386
|
end
|
321
387
|
end
|
322
388
|
|
323
|
-
def restart_service service, options={
|
389
|
+
def restart_service service, options = {}
|
390
|
+
options = default_options.merge options
|
391
|
+
|
324
392
|
Dust.print_msg "restarting #{service}", options
|
325
393
|
Dust.print_result exec("/etc/init.d/#{service} restart")[:exit_code], options
|
326
394
|
end
|
327
395
|
|
328
|
-
def reload_service service, options={
|
396
|
+
def reload_service service, options = {}
|
397
|
+
options = default_options.merge options
|
398
|
+
|
329
399
|
Dust.print_msg "reloading #{service}", options
|
330
400
|
Dust.print_result exec("/etc/init.d/#{service} reload")[:exit_code], options
|
331
401
|
end
|
332
402
|
|
333
403
|
# check whether a user exists on this node
|
334
|
-
def user_exists? user, options={
|
404
|
+
def user_exists? user, options = {}
|
405
|
+
options = default_options.merge options
|
406
|
+
|
335
407
|
Dust.print_msg "checking if user #{user} exists", options
|
336
408
|
Dust.print_result exec("id #{user}")[:exit_code], options
|
337
409
|
end
|
338
410
|
|
339
411
|
# create a user
|
340
|
-
def create_user user, options={
|
412
|
+
def create_user user, options = {}
|
413
|
+
options = default_options.merge options
|
414
|
+
options[:home] ||= nil
|
415
|
+
options[:shell] ||= nil
|
416
|
+
|
341
417
|
return true if user_exists? user, options
|
342
418
|
|
343
|
-
Dust.print_msg "creating user #{user}",
|
419
|
+
Dust.print_msg "creating user #{user}", :indent => options[:indent]
|
344
420
|
cmd = "useradd #{user} -m"
|
345
421
|
cmd += " -d #{options[:home]}" if options[:home]
|
346
422
|
cmd += " -s #{options[:shell]}" if options[:shell]
|
@@ -348,7 +424,9 @@ module Dust
|
|
348
424
|
end
|
349
425
|
|
350
426
|
# collect additional system facts using puppets facter
|
351
|
-
def collect_facts options={
|
427
|
+
def collect_facts options = {}
|
428
|
+
options = default_options.merge options
|
429
|
+
|
352
430
|
|
353
431
|
# check if lsb-release (on apt systems) and facter are installed
|
354
432
|
# and install them if not
|
@@ -362,23 +440,41 @@ module Dust
|
|
362
440
|
|
363
441
|
Dust.print_msg "collecting additional system facts (using facter)", options
|
364
442
|
|
365
|
-
# run facter with -y for yaml output, and merge results into @
|
443
|
+
# run facter with -y for yaml output, and merge results into @node
|
366
444
|
ret = exec 'facter -y'
|
367
|
-
@
|
445
|
+
@node.merge! YAML.load ret[:stdout]
|
368
446
|
|
369
447
|
Dust.print_result ret[:exit_code], options
|
370
448
|
end
|
371
449
|
|
450
|
+
# if file is a regular file, copy it using scp
|
451
|
+
# if it's an file.erb exists, render template and push to server
|
452
|
+
def deploy_file file, destination, options = {}
|
453
|
+
options = default_options(:binding => binding).merge options
|
454
|
+
|
455
|
+
if File.exists? file
|
456
|
+
scp file, destination, options
|
457
|
+
|
458
|
+
elsif File.exists? "#{file}.erb"
|
459
|
+
template = ERB.new( File.read("#{file}.erb"), nil, '%<>')
|
460
|
+
write destination, template.result(options[:binding]), options
|
461
|
+
|
462
|
+
else
|
463
|
+
::Dust.print_failed "'#{file}' was not found."
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
|
372
468
|
private
|
373
469
|
|
374
470
|
def method_missing method, *args, &block
|
375
|
-
# make server
|
376
|
-
if @
|
377
|
-
@
|
471
|
+
# make server nodeibutes accessible via server.nodeibute
|
472
|
+
if @node[method.to_s]
|
473
|
+
@node[method.to_s]
|
378
474
|
|
379
|
-
# and as server['
|
380
|
-
elsif @
|
381
|
-
@
|
475
|
+
# and as server['nodeibute']
|
476
|
+
elsif @node[args.first]
|
477
|
+
@node[args.first]
|
382
478
|
|
383
479
|
# default to super
|
384
480
|
else
|
data/lib/dust/version.rb
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 4
|
8
|
-
-
|
9
|
-
version: 0.4.
|
8
|
+
- 2
|
9
|
+
version: 0.4.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- kris kechagia
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2012-01-
|
17
|
+
date: 2012-01-17 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -96,7 +96,6 @@ files:
|
|
96
96
|
- changelog.md
|
97
97
|
- dust.gemspec
|
98
98
|
- lib/dust.rb
|
99
|
-
- lib/dust/convert_size.rb
|
100
99
|
- lib/dust/examples/nodes/_debian.yaml
|
101
100
|
- lib/dust/examples/nodes/_default.yaml
|
102
101
|
- lib/dust/examples/nodes/_newrelic.yaml
|
@@ -111,6 +110,7 @@ files:
|
|
111
110
|
- lib/dust/examples/templates/basic_setup/.your-vimrc
|
112
111
|
- lib/dust/examples/templates/duplicity/cronjob.erb
|
113
112
|
- lib/dust/examples/templates/etc_hosts/hosts
|
113
|
+
- lib/dust/examples/templates/hash_check/weak_passwords
|
114
114
|
- lib/dust/examples/templates/motd/motd.erb
|
115
115
|
- lib/dust/examples/templates/nginx/nginx.conf
|
116
116
|
- lib/dust/examples/templates/nginx/sites/othersite.erb
|
@@ -130,6 +130,7 @@ files:
|
|
130
130
|
- lib/dust/recipes/debsecan.rb
|
131
131
|
- lib/dust/recipes/duplicity.rb
|
132
132
|
- lib/dust/recipes/etc_hosts.rb
|
133
|
+
- lib/dust/recipes/hash_check.rb
|
133
134
|
- lib/dust/recipes/iptables.rb
|
134
135
|
- lib/dust/recipes/locale.rb
|
135
136
|
- lib/dust/recipes/memory_limit.rb
|
data/lib/dust/convert_size.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module Dust
|
2
|
-
|
3
|
-
# converts string to kilobytes (rounded)
|
4
|
-
def self.convert_size s
|
5
|
-
i, unit = s.split(' ')
|
6
|
-
|
7
|
-
case unit.downcase
|
8
|
-
when 'kb'
|
9
|
-
return i.to_i
|
10
|
-
when 'mb'
|
11
|
-
return (i.to_f * 1024).to_i
|
12
|
-
when 'gb'
|
13
|
-
return (i.to_f * 1024 * 1024).to_i
|
14
|
-
when 'tb'
|
15
|
-
return (i.to_f * 1024 * 1024 * 1024).to_i
|
16
|
-
else
|
17
|
-
return false
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|