dust-deploy 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/dust CHANGED
@@ -4,6 +4,7 @@ require 'rubygems'
4
4
  require 'thor/runner'
5
5
  require 'thor/util'
6
6
  require 'yaml'
7
+ require 'erb'
7
8
  require 'fileutils'
8
9
  require 'ipaddress'
9
10
  require 'dust'
@@ -186,7 +187,7 @@ module Dust
186
187
  end
187
188
 
188
189
  yaml_files.to_array.each do |file|
189
- node = YAML.load_file(file)
190
+ node = YAML.load ERB.new( File.read(file), nil, '%<>').result
190
191
 
191
192
  # if the file is empty, just skip it
192
193
  next unless node
@@ -200,7 +201,7 @@ module Dust
200
201
  if node['inherits']
201
202
  inherited = {}
202
203
  node.delete('inherits').each do |file|
203
- template = YAML.load_file "./nodes/#{file}.yaml"
204
+ template = YAML.load ERB.new( File.read("./nodes/#{file}.yaml"), nil, '%<>').result
204
205
  inherited.deep_merge! template
205
206
  end
206
207
  node = inherited.deep_merge node
data/changelog.md CHANGED
@@ -1,6 +1,42 @@
1
1
  Changelog
2
2
  =============
3
3
 
4
+ 0.10.0
5
+ ------------
6
+
7
+ - it is now possible to use ERB codes in your yaml configuration files.
8
+
9
+ <% user = john %>
10
+
11
+ hostname: <%= user %>-notebook
12
+
13
+ recipes:
14
+ ssh_authorized_keys:
15
+ <%= user %>: admin
16
+
17
+ - unattended upgrade recipe was removed in favor of the new apt recipe
18
+ - postgres recipe: now adds a log_line_prefix as default
19
+ also accepts empty postgresql.conf in yaml configuration
20
+ - apt recipe now looks for present proxy configurations and comments them out before applying new config
21
+ - adds apt recipe to configure apt systems (unattended upgrades, proxy configuration, etc)
22
+ you have to migrate your existing unattended_upgrade recipe from:
23
+
24
+ recipes:
25
+ unattended_upgrades: true
26
+
27
+ to:
28
+
29
+ recipes:
30
+ apt:
31
+ unattended_upgrades:
32
+ enabled: 1
33
+
34
+ or simply, in case you do not need other apt options (as enabling unattended_upgrades is the default):
35
+
36
+ recipes:
37
+ apt: enabled
38
+
39
+
4
40
  0.9.2
5
41
  ------------
6
42
 
data/dust.gemspec CHANGED
@@ -18,9 +18,8 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- # specify any dependencies here; for example:
22
- # s.add_development_dependency "rspec"
23
- # s.add_runtime_dependency "rest-client"
21
+ # specify any dependencies here
22
+ s.add_runtime_dependency 'json'
24
23
  s.add_runtime_dependency 'net-ssh'
25
24
  s.add_runtime_dependency 'net-scp'
26
25
  s.add_runtime_dependency 'net-sftp'
@@ -13,7 +13,7 @@ module Dust
13
13
  $stdout.sync = true # autoflush
14
14
 
15
15
  def self.print_result ret, options={:quiet => false, :indent => 1}
16
- if ret == 0 or ret == true
16
+ if ret == 0 or ret.is_a? TrueClass
17
17
  print_ok '', options
18
18
  return true
19
19
  else
@@ -0,0 +1,74 @@
1
+ class Apt < Recipe
2
+ desc 'apt:deploy', 'configures apt/aptitude'
3
+ def deploy
4
+ return unless @node.uses_apt?
5
+
6
+ @config = default_config.merge @config
7
+
8
+ unattended_upgrades @config.delete('unattended_upgrades')
9
+ proxy @config.delete('proxy')
10
+
11
+ @config.each do |name, settings|
12
+ ::Dust.print_msg "deploying apt settings #{name}\n"
13
+ conf = ''
14
+ settings.to_array.each do |setting|
15
+ conf << "#{setting}\n"
16
+ end
17
+
18
+ @node.write "/etc/apt/apt.conf.d/#{name}", conf, :indent => 2
19
+ end
20
+ end
21
+
22
+
23
+ private
24
+ def default_config
25
+ {
26
+ 'unattended_upgrades' => {
27
+ 'enable' => 1,
28
+ 'update-package-lists' => 1,
29
+ 'unattended-upgrade' => 1,
30
+ 'autocleaninterval' => 1,
31
+ 'verbose' => 0
32
+ },
33
+
34
+ 'proxy' => 'disabled'
35
+ }
36
+ end
37
+
38
+ def unattended_upgrades config
39
+ return if config.is_a? FalseClass or config == 'disabled'
40
+
41
+ @node.install_package 'unattended-upgrades'
42
+
43
+ ::Dust.print_msg "deploying unattended upgrades configuration\n"
44
+ periodic = ''
45
+ periodic << "APT::Periodic::Enable \"#{config['enable']}\";\n"
46
+ periodic << "APT::Periodic::Update-Package-Lists \"#{config['update-package-lists']}\";\n"
47
+ periodic << "APT::Periodic::Unattended-Upgrade \"#{config['unattended-upgrade']}\";\n"
48
+ periodic << "APT::Periodic::AutocleanInterval \"#{config['autocleaninterval']}\";\n"
49
+ periodic << "APT::Periodic::Verbose \"#{config['verbose']}\";\n"
50
+
51
+ @node.write '/etc/apt/apt.conf.d/02periodic', periodic, :indent => 2
52
+ end
53
+
54
+ def proxy config
55
+ # look for already configured proxy and delete
56
+ files = @node.exec("grep -v '^#' /etc/apt/ -R |grep -i 'acquire::http::proxy' |cut -d: -f1")[:stdout]
57
+ files.each_line do |file|
58
+ file.chomp!
59
+
60
+ # skip 02proxy, because we're going to overwrite it anyways
61
+ next if file == '/etc/apt/apt.conf.d/02proxy'
62
+
63
+ ::Dust.print_warning "found proxy configuration in file #{file}, commenting out"
64
+ @node.exec "sed -i 's/^\\(acquire::http::proxy.*\\)/#\\1/i' #{file}"
65
+ end
66
+
67
+ return if config.is_a? FalseClass or config == 'disabled'
68
+
69
+ ::Dust.print_msg "deploying proxy configuration\n"
70
+ proxy = "Acquire::http::Proxy \"#{config}\";\n"
71
+
72
+ @node.write '/etc/apt/apt.conf.d/02proxy', proxy, :indent => 2
73
+ end
74
+ end
@@ -19,20 +19,20 @@ class Debsecan < Recipe
19
19
  config_file = ''
20
20
 
21
21
  # configures whether daily reports are sent
22
- config_file += "# If true, enable daily reports, sent by email.\n" +
22
+ config_file << "# If true, enable daily reports, sent by email.\n" +
23
23
  "REPORT=#{config['report'].to_s}\n\n"
24
24
 
25
25
  # configures the suite
26
- config_file += "# For better reporting, specify the correct suite here, using the code\n" +
26
+ config_file << "# For better reporting, specify the correct suite here, using the code\n" +
27
27
  "# name (that is, \"sid\" instead of \"unstable\").\n" +
28
28
  "SUITE=#{@node['lsbdistcodename']}\n\n"
29
29
 
30
30
  # which user gets the reports?
31
- config_file += "# Mail address to which reports are sent.\n" +
31
+ config_file << "# Mail address to which reports are sent.\n" +
32
32
  "MAILTO=#{config['mailto']}\n\n"
33
33
 
34
34
  # set vulnerability source
35
- config_file += "# The URL from which vulnerability data is downloaded. Empty for the\n" +
35
+ config_file << "# The URL from which vulnerability data is downloaded. Empty for the\n" +
36
36
  "# built-in default.\n" +
37
37
  "SOURCE=#{config['source']}\n\n"
38
38
 
@@ -77,7 +77,7 @@ class Duplicity < Recipe
77
77
  "--archive-dir #{config['archive']} " +
78
78
  "#{File.join(config['backend'], config['directory'])}"
79
79
 
80
- cmd += " |tail -n3 |head -n1" unless options.long?
80
+ cmd << " |tail -n3 |head -n1" unless options.long?
81
81
 
82
82
  ret = @node.exec cmd
83
83
 
@@ -61,10 +61,10 @@ class Iptables < Recipe
61
61
 
62
62
  @tables['ipv' + @ip_version.to_s].keys.each do |table|
63
63
  # clear all rules
64
- @script.concat "--flush --table #{table}\n"
64
+ @script << "--flush --table #{table}\n"
65
65
 
66
66
  # delete all custom chains
67
- @script.concat "--delete-chain --table #{table}\n" unless @node.uses_rpm?
67
+ @script << "--delete-chain --table #{table}\n" unless @node.uses_rpm?
68
68
  end
69
69
  end
70
70
 
@@ -87,7 +87,7 @@ class Iptables < Recipe
87
87
  # generates all iptables rules
88
88
  def generate_all_rules
89
89
  @tables['ipv' + @ip_version.to_s].each do |table, chains|
90
- @script.concat "*#{table}\n" if @node.uses_rpm?
90
+ @script << "*#{table}\n" if @node.uses_rpm?
91
91
  set_chain_policies table
92
92
  generate_rules_for_table table
93
93
  end
@@ -103,9 +103,9 @@ class Iptables < Recipe
103
103
  policy = get_chain_policy table, chain
104
104
 
105
105
  if @node.uses_rpm?
106
- @script.concat ":#{chain.upcase} #{policy} [0:0]\n"
106
+ @script << ":#{chain.upcase} #{policy} [0:0]\n"
107
107
  else
108
- @script.concat "--table #{table} --policy #{chain.upcase} #{policy}\n"
108
+ @script << "--table #{table} --policy #{chain.upcase} #{policy}\n"
109
109
  end
110
110
  end
111
111
 
@@ -125,9 +125,9 @@ class Iptables < Recipe
125
125
  next unless chain_used_in_table
126
126
 
127
127
  if @node.uses_rpm?
128
- @script.concat ":#{chain.upcase} - [0:0]\n"
128
+ @script << ":#{chain.upcase} - [0:0]\n"
129
129
  else
130
- @script.concat "--table #{table} --new-chain #{chain.upcase}\n"
130
+ @script << "--table #{table} --new-chain #{chain.upcase}\n"
131
131
  end
132
132
  end
133
133
  end
@@ -162,7 +162,7 @@ class Iptables < Recipe
162
162
  ::Dust.print_ok
163
163
  end
164
164
  end
165
- @script.concat "COMMIT\n" if @node.uses_rpm?
165
+ @script << "COMMIT\n" if @node.uses_rpm?
166
166
  end
167
167
 
168
168
  def get_rules_for_table rules, table
@@ -188,7 +188,7 @@ class Iptables < Recipe
188
188
  def generate_iptables_string chain, rule
189
189
  parse_rule(rule).each do |r|
190
190
  #::Dust.print_msg "#{::Dust.grey}#{r.join ' '}#{::Dust.none}\n", :indent => 5
191
- @script.concat "--append #{chain.upcase} #{r.join ' '}\n"
191
+ @script << "--append #{chain.upcase} #{r.join ' '}\n"
192
192
  end
193
193
  end
194
194
 
@@ -14,15 +14,15 @@ class Logrotate < Recipe
14
14
  file = "#{rule['path']} {\n"
15
15
 
16
16
  rule['args'] ||= default_args
17
- rule['args'].each { |arg| file.concat " #{arg}\n" }
17
+ rule['args'].each { |arg| file << " #{arg}\n" }
18
18
 
19
19
  rule['scripts'] ||= {}
20
20
  rule['scripts'].each do |script, commands|
21
- file.concat " #{script}\n"
22
- commands.each { |cmd| file.concat " #{cmd}\n" }
21
+ file << " #{script}\n"
22
+ commands.each { |cmd| file << " #{cmd}\n" }
23
23
  end
24
24
 
25
- file.concat "}\n"
25
+ file << "}\n"
26
26
  deploy_rule name, file
27
27
  end
28
28
 
@@ -46,7 +46,6 @@ class Logrotate < Recipe
46
46
 
47
47
  def deploy_rule name, file
48
48
  @node.write "/etc/logrotate.d/#{name}", file, :indent => 2
49
- @node.chmod '0644', "/etc/logrotate.d/#{name}", :indent => 2
50
49
  @node.chown 'root:root', "/etc/logrotate.d/#{name}", :indent => 2
51
50
  end
52
51
 
@@ -13,7 +13,6 @@ class Mysql < Recipe
13
13
  ::Dust.print_ok "set innodb buffer pool to '#{@config['mysqld']['innodb_buffer_pool_size']}'", :indent => 2
14
14
 
15
15
  @node.write '/etc/mysql/my.cnf', generate_my_cnf
16
- @node.chmod '644', '/etc/mysql/my.cnf'
17
16
 
18
17
  @node.restart_service 'mysql' if options.restart?
19
18
  @node.reload_service 'mysql' if options.reload?
@@ -96,13 +95,13 @@ class Mysql < Recipe
96
95
  def generate_my_cnf
97
96
  my_cnf = ''
98
97
  @config.each do |category, config|
99
- my_cnf.concat "[#{category}]\n"
100
- config.each { |key, value| my_cnf.concat "#{key} = #{value}\n" }
101
- my_cnf.concat "\n"
98
+ my_cnf << "[#{category}]\n"
99
+ config.each { |key, value| my_cnf << "#{key} = #{value}\n" }
100
+ my_cnf << "\n"
102
101
  end
103
102
 
104
103
  # add includedir
105
- my_cnf.concat "!includedir /etc/mysql/conf.d/\n"
104
+ my_cnf << "!includedir /etc/mysql/conf.d/\n"
106
105
  my_cnf
107
106
  end
108
107
  end
@@ -4,6 +4,8 @@ class Postgres < Recipe
4
4
  return ::Dust.print_failed 'no version specified' unless @config['version']
5
5
  return unless install_postgres
6
6
 
7
+ @config['postgresql.conf'] ||= {}
8
+
7
9
  # default cluster on debian-like systems is 'main'
8
10
  @config['cluster'] ||= 'main' if @node.uses_apt?
9
11
 
@@ -71,9 +73,6 @@ class Postgres < Recipe
71
73
  @node.write "#{@config['conf_directory']}/postgresql.conf", generate_postgresql_conf
72
74
  @node.write "#{@config['conf_directory']}/pg_hba.conf", generate_pg_hba_conf
73
75
  @node.write "#{@config['conf_directory']}/pg_ident.conf", generate_pg_ident_conf
74
- @node.chmod '644', "#{@config['conf_directory']}/postgresql.conf"
75
- @node.chmod '644', "#{@config['conf_directory']}/pg_hba.conf"
76
- @node.chmod '644', "#{@config['conf_directory']}/pg_ident.conf"
77
76
  end
78
77
 
79
78
  # copy recovery.conf to either recovery.conf or recovery.done
@@ -94,16 +93,20 @@ class Postgres < Recipe
94
93
 
95
94
  # default settings for postgresql.conf
96
95
  def default_postgres_conf
97
- { 'max_connections' => 100,
96
+ {
97
+ 'max_connections' => 100,
98
98
  'datestyle' => 'iso, mdy',
99
99
  'lc_messages' => 'en_US.UTF-8',
100
100
  'lc_monetary' => 'en_US.UTF-8',
101
101
  'lc_numeric' => 'en_US.UTF-8',
102
102
  'lc_time' => 'en_US.UTF-8',
103
- 'default_text_search_config' => 'pg_catalog.english' }
103
+ 'default_text_search_config' => 'pg_catalog.english',
104
+ 'log_line_prefix' => '%t [%p] %u@%d '
105
+ }
104
106
  end
105
107
 
106
108
  def generate_postgresql_conf
109
+ @config['postgresql.conf'] ||= {}
107
110
  @config['postgresql.conf'] = default_postgres_conf.merge @config['postgresql.conf']
108
111
 
109
112
  calculate_values
@@ -111,7 +114,7 @@ class Postgres < Recipe
111
114
  postgresql_conf = ''
112
115
  @config['postgresql.conf'].each do |key, value|
113
116
  value = "'#{value}'" if value.is_a? String # enclose strings in ''
114
- postgresql_conf.concat "#{key} = #{value}\n"
117
+ postgresql_conf << "#{key} = #{value}\n"
115
118
  end
116
119
 
117
120
  postgresql_conf
@@ -123,7 +126,7 @@ class Postgres < Recipe
123
126
  recovery_conf = ''
124
127
  @config['recovery.conf'].each do |key, value|
125
128
  value = "'#{value}'" if value.is_a? String # enclose strings in ''
126
- recovery_conf.concat "#{key} = #{value}\n"
129
+ recovery_conf << "#{key} = #{value}\n"
127
130
  end
128
131
 
129
132
  recovery_conf
@@ -8,10 +8,10 @@ class RcLocal < Recipe
8
8
  rc = ''
9
9
  @config.to_array.each do |cmd|
10
10
  ::Dust.print_msg "adding command: #{cmd}", :indent => 2
11
- rc += "#{cmd}\n"
11
+ rc << "#{cmd}\n"
12
12
  ::Dust.print_ok
13
13
  end
14
- rc += "\nexit 0\n"
14
+ rc << "\nexit 0\n"
15
15
 
16
16
  @node.write '/etc/rc.local', rc
17
17
  @node.chown 'root:root', '/etc/rc.local'
@@ -63,9 +63,9 @@ class Redis < Recipe
63
63
  redis_conf = ''
64
64
  @config.each do |key, value|
65
65
  if value.is_a? Array
66
- value.each { |v| redis_conf.concat "#{key} #{v}\n" }
66
+ value.each { |v| redis_conf << "#{key} #{v}\n" }
67
67
  else
68
- redis_conf.concat "#{key} #{value}\n"
68
+ redis_conf << "#{key} #{value}\n"
69
69
  end
70
70
  end
71
71
 
@@ -83,8 +83,8 @@ class Redis < Recipe
83
83
  ::Dust.print_result @node.exec('sysctl -w vm.swappiness=0')[:exit_code]
84
84
 
85
85
  file = ''
86
- file += "vm.overcommit_memory=1\n"
87
- file += "vm.swappiness=0\n"
86
+ file << "vm.overcommit_memory=1\n"
87
+ file << "vm.swappiness=0\n"
88
88
 
89
89
  @node.write "/etc/sysctl.d/30-redis.conf", file
90
90
 
@@ -1,7 +1,7 @@
1
1
  class Repositories < Recipe
2
2
  desc 'repositories:deploy', 'configures package management repositories (aptitude, yum)'
3
3
  def deploy
4
- @node.collect_facts
4
+ return unless @node.collect_facts
5
5
 
6
6
  delete_old_repositories
7
7
  deploy_repositories
@@ -59,32 +59,32 @@ class Repositories < Recipe
59
59
 
60
60
  def generate_default_repo repo
61
61
  sources = ''
62
- sources.concat "deb #{repo['url']} #{repo['release']} #{repo['components']}\n"
63
- sources.concat "deb-src #{repo['url']} #{repo['release']} #{repo['components']}\n\n"
62
+ sources << "deb #{repo['url']} #{repo['release']} #{repo['components']}\n"
63
+ sources << "deb-src #{repo['url']} #{repo['release']} #{repo['components']}\n\n"
64
64
 
65
65
  # security
66
66
  if @node.is_debian?
67
- sources.concat "deb http://security.debian.org/ #{repo['release']}/updates #{repo['components']}\n"
68
- sources.concat "deb-src http://security.debian.org/ #{repo['release']}/updates #{repo['components']}\n\n"
67
+ sources << "deb http://security.debian.org/ #{repo['release']}/updates #{repo['components']}\n"
68
+ sources << "deb-src http://security.debian.org/ #{repo['release']}/updates #{repo['components']}\n\n"
69
69
  elsif @node.is_ubuntu?
70
- sources.concat "deb http://security.ubuntu.com/ubuntu/ #{repo['release']}-security #{repo['components']}\n"
71
- sources.concat "deb-src http://security.ubuntu.com/ubuntu/ #{repo['release']}-security #{repo['components']}\n\n"
70
+ sources << "deb http://security.ubuntu.com/ubuntu/ #{repo['release']}-security #{repo['components']}\n"
71
+ sources << "deb-src http://security.ubuntu.com/ubuntu/ #{repo['release']}-security #{repo['components']}\n\n"
72
72
  end
73
73
 
74
74
  # updates
75
- sources.concat "deb #{repo['url']} #{repo['release']}-updates #{repo['components']}\n"
76
- sources.concat "deb-src #{repo['url']} #{repo['release']}-updates #{repo['components']}\n\n"
75
+ sources << "deb #{repo['url']} #{repo['release']}-updates #{repo['components']}\n"
76
+ sources << "deb-src #{repo['url']} #{repo['release']}-updates #{repo['components']}\n\n"
77
77
 
78
78
  # proposed
79
79
  if @node.is_ubuntu?
80
- sources.concat "deb #{repo['url']} #{repo['release']}-proposed #{repo['components']}\n"
81
- sources.concat "deb-src #{repo['url']} #{repo['release']}-proposed #{repo['components']}\n\n"
80
+ sources << "deb #{repo['url']} #{repo['release']}-proposed #{repo['components']}\n"
81
+ sources << "deb-src #{repo['url']} #{repo['release']}-proposed #{repo['components']}\n\n"
82
82
  end
83
83
 
84
84
  # backports is enabled per default in ubuntu oneiric
85
85
  if @node.is_ubuntu?
86
- sources.concat "deb #{repo['url']} #{repo['release']}-backports #{repo['components']}\n"
87
- sources.concat "deb-src #{repo['url']} #{repo['release']}-backports #{repo['components']}\n\n"
86
+ sources << "deb #{repo['url']} #{repo['release']}-backports #{repo['components']}\n"
87
+ sources << "deb-src #{repo['url']} #{repo['release']}-backports #{repo['components']}\n\n"
88
88
  end
89
89
 
90
90
  sources
@@ -93,8 +93,8 @@ class Repositories < Recipe
93
93
  def generate_repo repo
94
94
  # add url to sources.list
95
95
  sources = ''
96
- sources.concat "deb #{repo['url']} #{repo['release']} #{repo['components']}\n" if repo['binary']
97
- sources.concat "deb-src #{repo['url']} #{repo['release']} #{repo['components']}\n" if repo['source']
96
+ sources << "deb #{repo['url']} #{repo['release']} #{repo['components']}\n" if repo['binary']
97
+ sources << "deb-src #{repo['url']} #{repo['release']} #{repo['components']}\n" if repo['source']
98
98
  sources
99
99
  end
100
100
 
@@ -14,25 +14,25 @@ class ResolvConf < Recipe
14
14
  # configures whether daily reports are sent
15
15
  if @config['search']
16
16
  ::Dust.print_msg "adding search #{@config['search']}", :indent => 2
17
- config_file += "search #{@config['search']}\n"
17
+ config_file << "search #{@config['search']}\n"
18
18
  ::Dust.print_ok
19
19
  end
20
20
 
21
21
  if @config['domain']
22
22
  ::Dust.print_msg "adding domain #{@config['domain']}", :indent => 2
23
- config_file += "domain #{@config['domain']}\n"
23
+ config_file << "domain #{@config['domain']}\n"
24
24
  ::Dust.print_ok
25
25
  end
26
26
 
27
27
  if @config['options']
28
28
  ::Dust.print_msg "adding options #{@config['options']}", :indent => 2
29
- config_file += "options #{@config['options']}\n"
29
+ config_file << "options #{@config['options']}\n"
30
30
  ::Dust.print_ok
31
31
  end
32
32
 
33
33
  @config['nameservers'].each do |nameserver|
34
34
  ::Dust.print_msg "adding nameserver #{nameserver}", :indent => 2
35
- config_file += "nameserver #{nameserver}\n"
35
+ config_file << "nameserver #{nameserver}\n"
36
36
  ::Dust.print_ok
37
37
  end
38
38
 
@@ -34,6 +34,8 @@ class RubyRvm < Recipe
34
34
  next
35
35
  end
36
36
 
37
+ return unless change_shell user
38
+ return unless create_homedir user
37
39
  return unless install_rvm user
38
40
  return unless install_ruby user, version
39
41
  return unless set_default user, version
@@ -84,4 +86,22 @@ class RubyRvm < Recipe
84
86
  end
85
87
  false
86
88
  end
89
+
90
+ # rvm only supports bash and zsh
91
+ def change_shell user
92
+ shell = @node.get_shell user
93
+ return true if shell == '/bin/zsh' or shell == '/bin/bash'
94
+
95
+ ::Dust.print_msg "changing shell for #{user} to /bin/bash"
96
+ ::Dust.print_result@node.exec("chsh -s /bin/bash #{user}")[:exit_code]
97
+ end
98
+
99
+ def create_homedir user
100
+ dir = @node.get_home user
101
+ unless @node.dir_exists? dir, :quiet => true
102
+ return false unless @node.mkdir dir
103
+ return false unless @node.chown user, dir
104
+ end
105
+ true
106
+ end
87
107
  end
@@ -25,10 +25,10 @@ class SshAuthorizedKeys < Recipe
25
25
  users[ssh_user]['name'] ||= ssh_user
26
26
  ::Dust.print_msg "adding user #{users[ssh_user]['name']}", :indent => 2
27
27
  users[ssh_user]['keys'].each do |key|
28
- authorized_keys.concat"#{key}"
29
- authorized_keys.concat " #{users[ssh_user]['name']}" if users[ssh_user]['name']
30
- authorized_keys.concat " <#{users[ssh_user]['email']}>" if users[ssh_user]['email']
31
- authorized_keys.concat "\n"
28
+ authorized_keys << "#{key}"
29
+ authorized_keys << " #{users[ssh_user]['name']}" if users[ssh_user]['name']
30
+ authorized_keys << " <#{users[ssh_user]['email']}>" if users[ssh_user]['email']
31
+ authorized_keys << "\n"
32
32
  end
33
33
  ::Dust.print_ok
34
34
  end
@@ -51,7 +51,6 @@ class SshAuthorizedKeys < Recipe
51
51
 
52
52
  # check permissions
53
53
  @node.chown "#{user}:#{user}", "#{home}/.ssh"
54
- @node.chmod '0644', "#{home}/.ssh/authorized_keys"
55
54
  end
56
55
 
57
56
  # remove authorized_keys files for all other users
@@ -55,7 +55,7 @@ class Sshd < Recipe
55
55
  def apply_configuration
56
56
  @sshd_config = ''
57
57
  @config.each do |key, values|
58
- values.each { |value| @sshd_config.concat "#{key} #{value}\n" }
58
+ values.each { |value| @sshd_config << "#{key} #{value}\n" }
59
59
  end
60
60
  end
61
61
 
@@ -21,7 +21,7 @@ class Sudoers < Recipe
21
21
 
22
22
  file = ''
23
23
  rule['user'].each do |u|
24
- rule['command'].each { |c| file.concat "#{u} #{c}\n" }
24
+ rule['command'].each { |c| file << "#{u} #{c}\n" }
25
25
  end
26
26
  end
27
27
 
@@ -30,7 +30,7 @@ class Sysctl < Recipe
30
30
  sysctl.each do |key, value|
31
31
  ::Dust.print_msg "setting #{key} = #{value}", :indent => 2
32
32
  ::Dust.print_result @node.exec("sysctl -w #{key}=#{value}")[:exit_code]
33
- sysctl_conf.concat "#{key} = #{value}\n"
33
+ sysctl_conf << "#{key} = #{value}\n"
34
34
  end
35
35
 
36
36
  ::Dust.print_msg "saving settings to /etc/sysctl.d/10-#{name}.conf", :indent => 2
@@ -50,7 +50,9 @@ class ZabbixAgent < Recipe
50
50
  # generate zabbix_agentd.conf
51
51
  def generate_zabbix_agentd_conf
52
52
  @config = default_config.merge @config
53
-
53
+
54
+ @config['UserParameter'] = Array @config['UserParameter']
55
+
54
56
  # system updates
55
57
  @config['UserParameter'] |= enable_apt if @node.uses_apt?
56
58
  @config['UserParameter'] |= enable_rpm if @node.uses_rpm?
@@ -65,12 +67,12 @@ class ZabbixAgent < Recipe
65
67
  # add normal configuration variables
66
68
  @config.each do |key, value|
67
69
  next if key == 'UserParameter'
68
- zabbix_agentd_conf.concat "#{key}=#{value}\n"
70
+ zabbix_agentd_conf << "#{key}=#{value}\n"
69
71
  end
70
72
 
71
73
  # add user parameters
72
74
  @config['UserParameter'].each do |user_parameter|
73
- zabbix_agentd_conf.concat "UserParameter=#{user_parameter}\n"
75
+ zabbix_agentd_conf << "UserParameter=#{user_parameter}\n"
74
76
  end
75
77
 
76
78
  zabbix_agentd_conf
data/lib/dust/server.rb CHANGED
@@ -108,16 +108,20 @@ module Dust
108
108
 
109
109
  def write destination, content, options = {}
110
110
  options = default_options.merge options
111
-
111
+
112
112
  Dust.print_msg "deploying #{File.basename destination}", options
113
-
113
+
114
114
  f = Tempfile.new 'dust-write'
115
115
  f.print content
116
116
  f.close
117
-
117
+
118
+ file_existed = file_exists? destination, :quiet => true
119
+
118
120
  ret = Dust.print_result scp(f.path, destination, :quiet => true), options
119
121
  f.unlink
120
-
122
+
123
+ # default to 644 unless file existed before
124
+ chmod '0644', destination, options unless file_existed
121
125
  ret
122
126
  end
123
127
 
@@ -575,9 +579,22 @@ module Dust
575
579
  def get_home user, options = {}
576
580
  options = default_options(:quiet => true).merge options
577
581
 
578
- Dust.print_msg "getting home directory of #{user}"
582
+ Dust.print_msg "getting home directory of #{user}", options
579
583
  ret = exec "getent passwd |cut -d':' -f1,6 |grep '^#{user}' |head -n1 |cut -d: -f2"
580
- if Dust.print_result ret[:exit_code]
584
+ if Dust.print_result ret[:exit_code], options
585
+ return ret[:stdout].chomp
586
+ else
587
+ return false
588
+ end
589
+ end
590
+
591
+ # returns shell of this user
592
+ def get_shell user, options = {}
593
+ options = default_options(:quiet => true).merge options
594
+
595
+ Dust.print_msg "getting shell of #{user}", options
596
+ ret = exec "getent passwd |cut -d':' -f1,7 |grep '^#{user}' |head -n1 |cut -d: -f2"
597
+ if Dust.print_result ret[:exit_code], options
581
598
  return ret[:stdout].chomp
582
599
  else
583
600
  return false
data/lib/dust/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dust
2
- VERSION = "0.9.2"
2
+ VERSION = "0.10.0"
3
3
  end
metadata CHANGED
@@ -1,80 +1,104 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: dust-deploy
3
- version: !ruby/object:Gem::Version
4
- version: 0.9.2
5
- prerelease:
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 10
8
+ - 0
9
+ version: 0.10.0
6
10
  platform: ruby
7
- authors:
11
+ authors:
8
12
  - kris kechagia
9
13
  autorequire:
10
14
  bindir: bin
11
15
  cert_chain: []
12
- date: 2012-03-27 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: net-ssh
16
- requirement: &70357952436820 !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
16
+
17
+ date: 2012-04-03 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: json
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
22
30
  type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: net-ssh
23
34
  prerelease: false
24
- version_requirements: *70357952436820
25
- - !ruby/object:Gem::Dependency
26
- name: net-scp
27
- requirement: &70357952436280 !ruby/object:Gem::Requirement
28
- none: false
29
- requirements:
30
- - - ! '>='
31
- - !ruby/object:Gem::Version
32
- version: '0'
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
33
42
  type: :runtime
43
+ version_requirements: *id002
44
+ - !ruby/object:Gem::Dependency
45
+ name: net-scp
34
46
  prerelease: false
35
- version_requirements: *70357952436280
36
- - !ruby/object:Gem::Dependency
37
- name: net-sftp
38
- requirement: &70357952435600 !ruby/object:Gem::Requirement
39
- none: false
40
- requirements:
41
- - - ! '>='
42
- - !ruby/object:Gem::Version
43
- version: '0'
47
+ requirement: &id003 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ version: "0"
44
54
  type: :runtime
55
+ version_requirements: *id003
56
+ - !ruby/object:Gem::Dependency
57
+ name: net-sftp
45
58
  prerelease: false
46
- version_requirements: *70357952435600
47
- - !ruby/object:Gem::Dependency
48
- name: thor
49
- requirement: &70357952434660 !ruby/object:Gem::Requirement
50
- none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
59
+ requirement: &id004 !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
55
66
  type: :runtime
67
+ version_requirements: *id004
68
+ - !ruby/object:Gem::Dependency
69
+ name: thor
56
70
  prerelease: false
57
- version_requirements: *70357952434660
58
- - !ruby/object:Gem::Dependency
59
- name: ipaddress
60
- requirement: &70357952434240 !ruby/object:Gem::Requirement
61
- none: false
62
- requirements:
63
- - - ! '>='
64
- - !ruby/object:Gem::Version
65
- version: '0'
71
+ requirement: &id005 !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
66
78
  type: :runtime
79
+ version_requirements: *id005
80
+ - !ruby/object:Gem::Dependency
81
+ name: ipaddress
67
82
  prerelease: false
68
- version_requirements: *70357952434240
69
- description: when puppet and chef suck because you want to be in control and sprinkle
70
- just cannot do enough for you
71
- email:
83
+ requirement: &id006 !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ type: :runtime
91
+ version_requirements: *id006
92
+ description: when puppet and chef suck because you want to be in control and sprinkle just cannot do enough for you
93
+ email:
72
94
  - kk@rndsec.net
73
- executables:
95
+ executables:
74
96
  - dust
75
97
  extensions: []
98
+
76
99
  extra_rdoc_files: []
77
- files:
100
+
101
+ files:
78
102
  - .gitignore
79
103
  - Gemfile
80
104
  - LICENSE
@@ -110,6 +134,7 @@ files:
110
134
  - lib/dust/print_status.rb
111
135
  - lib/dust/recipe.rb
112
136
  - lib/dust/recipes/aliases.rb
137
+ - lib/dust/recipes/apt.rb
113
138
  - lib/dust/recipes/basic_setup.rb
114
139
  - lib/dust/recipes/cjdroute.rb
115
140
  - lib/dust/recipes/cups_client.rb
@@ -138,32 +163,38 @@ files:
138
163
  - lib/dust/recipes/sshd.rb
139
164
  - lib/dust/recipes/sudoers.rb
140
165
  - lib/dust/recipes/sysctl.rb
141
- - lib/dust/recipes/unattended_upgrades.rb
142
166
  - lib/dust/recipes/zabbix_agent.rb
143
167
  - lib/dust/server.rb
144
168
  - lib/dust/version.rb
145
- homepage: ''
169
+ has_rdoc: true
170
+ homepage: ""
146
171
  licenses: []
172
+
147
173
  post_install_message:
148
174
  rdoc_options: []
149
- require_paths:
175
+
176
+ require_paths:
150
177
  - lib
151
- required_ruby_version: !ruby/object:Gem::Requirement
152
- none: false
153
- requirements:
154
- - - ! '>='
155
- - !ruby/object:Gem::Version
156
- version: '0'
157
- required_rubygems_version: !ruby/object:Gem::Requirement
158
- none: false
159
- requirements:
160
- - - ! '>='
161
- - !ruby/object:Gem::Version
162
- version: '0'
178
+ required_ruby_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ segments:
183
+ - 0
184
+ version: "0"
185
+ required_rubygems_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ segments:
190
+ - 0
191
+ version: "0"
163
192
  requirements: []
193
+
164
194
  rubyforge_project: dust-deploy
165
- rubygems_version: 1.8.11
195
+ rubygems_version: 1.3.6
166
196
  signing_key:
167
197
  specification_version: 3
168
198
  summary: small server deployment tool for complex environments
169
199
  test_files: []
200
+
@@ -1,27 +0,0 @@
1
- class UnattendedUpgrades < Recipe
2
- desc 'unattended_upgrades:deploy', 'installs and configures automatic system updates for debian and ubuntu'
3
- def deploy
4
- return unless @node.uses_apt?
5
- @node.install_package 'unattended-upgrades'
6
-
7
- @config = {} unless @config.is_a? Hash
8
-
9
- # set defaults for non-set config
10
- @config['enable'] ||= 1
11
- @config['update-package-lists'] ||= 1
12
- @config['unattended-upgrade'] ||= 1
13
- @config['autocleaninterval'] ||= 1
14
- @config['verbose'] ||= 0
15
-
16
- # generate configuration file
17
- periodic = ''
18
- periodic += "APT::Periodic::Enable \"#{@config['enable']}\";\n"
19
- periodic += "APT::Periodic::Update-Package-Lists \"#{@config['update-package-lists']}\";\n"
20
- periodic += "APT::Periodic::Unattended-Upgrade \"#{@config['unattended-upgrade']}\";\n"
21
- periodic += "APT::Periodic::AutocleanInterval \"#{@config['autocleaninterval']}\";\n"
22
- periodic += "APT::Periodic::Verbose \"#{@config['verbose']}\";\n"
23
-
24
- @node.write '/etc/apt/apt.conf.d/02periodic', periodic
25
- @node.chmod '644', '/etc/apt/apt.conf.d/02periodic'
26
- end
27
- end