dust-deploy 0.4.4 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,16 @@
1
1
  Changelog
2
2
  =============
3
3
 
4
+ 0.4.5
5
+ ------------
6
+
7
+ - node.write and node.append now not using echo for writing files on the server anymore.
8
+ this solves problems with binary files and files including backticks (`)
9
+ - adds pacemaker recipe, for basic setup and configuration of corosync/pacemaker
10
+ - adds sudoers recipe for maintaining your sudoers rules
11
+ - postgres recipe now checks if zabbix is installed, and if so configures the node for monitoring
12
+
13
+
4
14
  0.4.4
5
15
  ------------
6
16
 
@@ -34,9 +34,9 @@ class Duplicity < Recipe
34
34
  # add hostkey to known_hosts
35
35
  if config['hostkey']
36
36
  ::Dust.print_msg 'checking if ssh key is in known_hosts'
37
- unless ::Dust.print_result @node.exec("grep -q '#{config['hostkey']}' ~/.ssh/known_hosts")[:exit_code] == 0
38
- @node.mkdir '~/.ssh', :indent => 2
39
- @node.append '~/.ssh/known_hosts', config['hostkey'], :indent => 2
37
+ unless ::Dust.print_result @node.exec("grep -q '#{config['hostkey']}' /root/.ssh/known_hosts")[:exit_code] == 0
38
+ @node.mkdir '/root/.ssh', :indent => 2
39
+ @node.append '/root/.ssh/known_hosts', config['hostkey'], :indent => 2
40
40
  end
41
41
  end
42
42
 
@@ -0,0 +1,35 @@
1
+ require 'base64'
2
+
3
+ class Pacemaker < Recipe
4
+
5
+ desc 'pacemaker:deploy', 'installs and configures corosync/pacemaker'
6
+ def deploy
7
+ # this recipe is only tested with ubuntu
8
+ return unless @node.uses_apt?
9
+ return unless @node.install_package 'pacemaker'
10
+
11
+ # return if no authkey is given
12
+ unless @config['authkey']
13
+ return ::Dust.print_failed 'no authkey given. generate it using "corosync-keygen" ' +
14
+ 'and convert it to base64 using "base64 -w0 /etc/corosync/authkey"'
15
+ end
16
+
17
+ @node.collect_facts
18
+
19
+ # set defaults
20
+ @config['interface'] ||= 'eth0'
21
+ @config['mcastaddr'] ||= '226.13.37.1'
22
+ @config['mcastport'] ||= 5405
23
+
24
+ # set bindnetaddr to the ip address of @config['interface']
25
+ # unless it is specified manually in node config
26
+ @config['bindnetaddr'] ||= @node["ipaddress_#{@config['interface']}"]
27
+
28
+ # decode base64 authkey
29
+ @node.write '/etc/corosync/authkey', Base64.decode64(@config['authkey'])
30
+ @node.deploy_file "#{@template_path}/corosync.conf", '/etc/corosync/corosync.conf', :binding => binding
31
+
32
+ # not restarting automatically, because it provokes switching of ha services
33
+ #@node.restart_service 'corosync' if @options.restart
34
+ end
35
+ end
@@ -2,7 +2,26 @@ class Postgres < Recipe
2
2
  desc 'postgres:deploy', 'installs and configures postgresql database'
3
3
  def deploy
4
4
  return ::Dust.print_failed 'no version specified' unless @config['version']
5
-
5
+ return ::Dust.print_failed 'os not supported' unless default_config
6
+
7
+ deploy_config
8
+ deploy_recovery
9
+ deploy_certificates
10
+ configure_sysctl
11
+
12
+ deploy_pacemaker_script if @node.package_installed? 'pacemaker'
13
+ configure_for_zabbix if zabbix_installed?
14
+
15
+ # reload/restart postgres if command line option is given
16
+ @node.restart_service @config['service-name'] if options.restart?
17
+ @node.reload_service @config['service-name'] if options.reload?
18
+ end
19
+
20
+
21
+ private
22
+
23
+ # set default variables and make sure postgres is installed
24
+ def default_config
6
25
  if @node.uses_emerge?
7
26
  return unless @node.package_installed? 'postgresql-server'
8
27
  @config['data-dir'] ||= "/var/lib/postgresql/#{@config['version']}/data"
@@ -18,10 +37,12 @@ class Postgres < Recipe
18
37
  @config['service-name'] ||= 'postgresql'
19
38
 
20
39
  else
21
- return 'os not supported'
40
+ return ::Dust.print_failed 'os not supported yet'
22
41
  end
42
+ end
23
43
 
24
-
44
+ # deploy standard postgres config
45
+ def deploy_config
25
46
  @node.deploy_file "#{@template_path}/postgresql.conf", "#{@config['conf-dir']}/postgresql.conf", :binding => binding
26
47
  @node.deploy_file "#{@template_path}/pg_hba.conf", "#{@config['conf-dir']}/pg_hba.conf", :binding => binding
27
48
  @node.deploy_file "#{@template_path}/pg_ident.conf", "#{@config['conf-dir']}/pg_ident.conf", :binding => binding
@@ -29,22 +50,20 @@ class Postgres < Recipe
29
50
  @node.chmod '644', "#{@config['conf-dir']}/postgresql.conf"
30
51
  @node.chmod '644', "#{@config['conf-dir']}/pg_hba.conf"
31
52
  @node.chmod '644', "#{@config['conf-dir']}/pg_ident.conf"
32
-
33
- # deploy pacemaker script
34
- if @node.package_installed? 'pacemaker'
35
- @node.deploy_file "#{@template_path}/pacemaker.sh", "#{@config['conf-dir']}/pacemaker.sh", :binding => binding
36
- @node.chmod '755', "#{@config['conf-dir']}/pacemaker.sh"
37
- end
38
-
39
- # copy recovery.conf to either recovery.conf or recovery.done
40
- # depending on which file already exists.
53
+ end
54
+
55
+ # copy recovery.conf to either recovery.conf or recovery.done
56
+ # depending on which file already exists.
57
+ def deploy_recovery
41
58
  if @node.file_exists? "#{@config['data-dir']}/recovery.conf", :quiet => true
42
59
  @node.deploy_file "#{@template_path}/recovery.conf", "#{@config['data-dir']}/recovery.conf", :binding => binding
43
60
  else
44
61
  @node.deploy_file "#{@template_path}/recovery.conf", "#{@config['data-dir']}/recovery.done", :binding => binding
45
62
  end
46
-
47
- # deploy certificates to data-dir
63
+ end
64
+
65
+ # deploy certificates to data-dir
66
+ def deploy_certificates
48
67
  @node.deploy_file "#{@template_path}/server.crt", "#{@config['data-dir']}/server.crt", :binding => binding
49
68
  @node.deploy_file "#{@template_path}/server.key", "#{@config['data-dir']}/server.key", :binding => binding
50
69
 
@@ -55,9 +74,11 @@ class Postgres < Recipe
55
74
  @node.mkdir @config['archive-dir']
56
75
  @node.chown @config['dbuser'], @config['archive-dir'] if @config['dbuser']
57
76
  @node.chmod 'u+Xrw,g-rwx,o-rwx', @config['archive-dir']
77
+ end
58
78
 
59
-
60
- # increase shm memory
79
+ # increase shm memory
80
+ def configure_sysctl
81
+
61
82
  if @node.uses_apt?
62
83
  ::Dust.print_msg "setting postgres sysctl keys\n"
63
84
  @node.collect_facts :quiet => true
@@ -83,11 +104,56 @@ class Postgres < Recipe
83
104
 
84
105
  @node.write "/etc/sysctl.d/30-postgresql-shm.conf", file
85
106
  end
86
-
87
- # reload/restart postgres if command line option is given
88
- @node.restart_service @config['service-name'] if options.restart?
89
- @node.reload_service @config['service-name'] if options.reload?
90
107
  end
91
108
 
109
+ def deploy_pacemaker_script
110
+ @node.deploy_file "#{@template_path}/pacemaker.sh", "#{@config['conf-dir']}/pacemaker.sh", :binding => binding
111
+ @node.chmod '755', "#{@config['conf-dir']}/pacemaker.sh"
112
+ end
113
+
114
+ # below this line is unfinished code, not in use yet
115
+ def zabbix_installed?
116
+ if @node.uses_emerge?
117
+ return @node.package_installed? 'zabbix', :quiet => true
118
+ else
119
+ return @node.package_installed? 'zabbix-agent', :quiet => true
120
+ end
121
+ end
122
+
123
+ # adds zabbix user to postgres group
124
+ # creates zabbix user in postgres and grant access to postgres database
125
+ def configure_for_zabbix
126
+ ::Dust.print_msg "configuring postgres for zabbix monitoring\n"
127
+ ::Dust.print_msg 'adding zabbix user to postgres group', :indent => 2
128
+ ::Dust.print_result @node.exec('usermod -a -G postgres zabbix')[:exit_code]
129
+
130
+ if is_master? :indent => 2
131
+ ::Dust.print_msg 'checking if zabbix user exists in postgres', :indent => 3
132
+ ret = ::Dust.print_result @node.exec('psql -U postgres -c ' +
133
+ ' "SELECT usename FROM pg_user WHERE usename = \'zabbix\'"' +
134
+ ' postgres |grep -q zabbix')[:exit_code]
135
+
136
+ # if user was not found, create him
137
+ unless ret
138
+ ::Dust.print_msg 'create zabbix user in postgres', :indent => 4
139
+ ::Dust.print_result @node.exec('createuser -U postgres zabbix -RSD')[:exit_code]
140
+ end
141
+
142
+ ::Dust.print_msg 'GRANT zabbix user access to postgres database', :indent => 3
143
+ ::Dust.print_result( @node.exec('psql -U postgres -c "GRANT SELECT ON pg_stat_database TO zabbix" postgres')[:exit_code] )
144
+ end
145
+ end
146
+
147
+ # checks if this server is a postgres master
148
+ def is_master? options = {}
149
+ ::Dust.print_msg 'checking if this host is the postgres master: ', options
150
+ if @node.file_exists? "#{@config['data-dir']}/recovery.done", :quiet => true
151
+ ::Dust.print_ok 'yes', :indent => 0
152
+ return true
153
+ else
154
+ ::Dust.print_ok 'no', :indent => 0
155
+ return false
156
+ end
157
+ end
92
158
  end
93
159
 
@@ -0,0 +1,46 @@
1
+ class Sudoers < Recipe
2
+ desc 'sudoers:deploy', 'installs email aliases'
3
+ def deploy
4
+ return unless @node.install_package 'sudo'
5
+
6
+ remove_rules
7
+
8
+ @config.each do |name, rule|
9
+ ::Dust.print_msg "deploying sudo rules '#{name}'\n"
10
+
11
+ # rulename: 'myrule'
12
+ if rule.is_a? String
13
+ file = "#{rule}\n"
14
+
15
+ # rulename: { user: [ user1, user2 ], command: [ cmd1, cmd2 ] }
16
+ else
17
+ unless rule['user'] and rule['command']
18
+ ::Dust.print_failed 'user or command missing', :indent => 2
19
+ next
20
+ end
21
+
22
+ file = ''
23
+ rule['user'].each do |u|
24
+ rule['command'].each { |c| file.concat "#{u} #{c}\n" }
25
+ end
26
+ end
27
+
28
+ deploy_rule name, file
29
+ end
30
+
31
+ end
32
+
33
+
34
+ private
35
+
36
+ def remove_rules
37
+ @node.rm '/etc/sudoers.d/*'
38
+ end
39
+
40
+ def deploy_rule name, file
41
+ @node.write "/etc/sudoers.d/#{name}", file, :indent => 2
42
+ @node.chmod '0440', "/etc/sudoers.d/#{name}", :indent => 2
43
+ @node.chown 'root:root', "/etc/sudoers.d/#{name}", :indent => 2
44
+ end
45
+ end
46
+
@@ -38,38 +38,4 @@ class ZabbixAgent < Recipe
38
38
 
39
39
  true
40
40
  end
41
-
42
-
43
- # below this line is unfinished code, not in use yet
44
-
45
- # TODO (not yet finished)
46
- desc 'zabbix_agent:postgres', 'configure postgres database for zabbix monitoring'
47
- def postgres
48
- next unless @node.uses_emerge? :quiet=>false
49
- next unless @node.package_installed?('postgresql-@node')
50
-
51
- ::Dust.print_msg 'add zabbix system user to postgres group'
52
- ::Dust.print_result( @node.exec('usermod -a -G postgres zabbix')[:exit_code] )
53
-
54
- ::Dust.print_msg 'checking if zabbix user exists in postgres'
55
- ret = ::Dust.print_result( @node.exec('psql -U postgres -c ' +
56
- ' "SELECT usename FROM pg_user WHERE usename = \'zabbix\'"' +
57
- ' postgres |grep -q zabbix')[:exit_code] )
58
-
59
- # if user was not found, create him
60
- unless ret
61
- ::Dust.print_msg 'create zabbix user in postgres', :indent => 2
62
- ::Dust.print_result( @node.exec('createuser -U postgres zabbix -RSD')[:exit_code] )
63
- end
64
-
65
- # TODO: only GRANT is this is a master
66
- ::Dust.print_msg 'GRANT zabbix user access to postgres database'
67
- ::Dust.print_result( @node.exec('psql -U postgres -c "GRANT SELECT ON pg_stat_database TO zabbix" postgres')[:exit_code] )
68
-
69
- # reload postgresql
70
- @node.reload_service('postgresql-9.0')
71
-
72
- @node.disconnect
73
- puts
74
- end
75
41
  end
@@ -3,7 +3,8 @@ require 'net/ssh'
3
3
  require 'net/scp'
4
4
  require 'net/ssh/proxy/socks5'
5
5
  require 'erb'
6
-
6
+ require 'tempfile'
7
+
7
8
  module Dust
8
9
  class Server
9
10
  attr_reader :ssh
@@ -70,37 +71,34 @@ module Dust
70
71
  end
71
72
 
72
73
 
73
- def write target, text, options = {}
74
+ def write destination, content, options = {}
74
75
  options = default_options.merge options
75
-
76
- Dust.print_msg "deploying #{File.basename target}", options
77
-
78
- # escape $ signs and \ at the end of line
79
- text.gsub! '$','\$'
80
- text.gsub! /\\$/, '\\\\\\'
81
-
82
- # note: ` (backticks) somehow cannot be escaped.. don't use them
83
- # in bash, use $(cmd) instead of `cmd` as a workaround
84
- if exec("cat << EOF > #{target}\n#{text}\nEOF")[:exit_code] != 0
85
- Dust.print_failed '', options
86
- return false
87
- end
88
-
89
- Dust.print_ok '', options
90
- restorecon target, options # restore SELinux labels
76
+
77
+ Dust.print_msg "deploying #{File.basename destination}", options
78
+
79
+ f = Tempfile.new 'dust-write'
80
+ f.print content
81
+ f.close
82
+
83
+ Dust.print_result scp(f.path, destination, :quiet => true), options
84
+ f.unlink
91
85
  end
92
86
 
93
- def append target, text, options = {}
87
+ def append destination, newcontent, options = {}
94
88
  options = default_options.merge options
95
-
96
- Dust.print_msg "appending to #{File.basename target}", options
97
- Dust.print_result exec("cat << EOF >> #{target}\n#{text}\nEOF")[:exit_code], options
89
+
90
+ Dust.print_msg "appending to #{File.basename destination}", options
91
+
92
+ content = exec("cat #{destination}")[:stdout]
93
+ content.concat newcontent
94
+
95
+ Dust.print_result write(destination, content, :quiet => true), options
98
96
  end
99
97
 
100
98
  def scp source, destination, options = {}
101
99
  options = default_options.merge options
102
100
 
103
- Dust.print_msg "deploying #{File.basename(source)}", options
101
+ Dust.print_msg "deploying #{File.basename source}", options
104
102
  @ssh.scp.upload! source, destination
105
103
  Dust.print_ok '', options
106
104
  restorecon destination, options # restore SELinux labels
@@ -109,7 +107,7 @@ module Dust
109
107
  def symlink source, destination, options = {}
110
108
  options = default_options.merge options
111
109
 
112
- Dust.print_msg "symlinking #{File.basename(source)} to '#{destination}'", options
110
+ Dust.print_msg "symlinking #{File.basename source} to '#{destination}'", options
113
111
  Dust.print_result exec("ln -s #{source} #{destination}")[:exit_code], options
114
112
  restorecon destination, options # restore SELinux labels
115
113
  end
@@ -117,14 +115,14 @@ module Dust
117
115
  def chmod mode, file, options = {}
118
116
  options = default_options.merge options
119
117
 
120
- Dust.print_msg "setting mode of #{File.basename(file)} to #{mode}", options
118
+ Dust.print_msg "setting mode of #{File.basename file} to #{mode}", options
121
119
  Dust.print_result exec("chmod -R #{mode} #{file}")[:exit_code], options
122
120
  end
123
121
 
124
122
  def chown user, file, options = {}
125
123
  options = default_options.merge options
126
124
 
127
- Dust.print_msg "setting owner of #{File.basename(file)} to #{user}", options
125
+ Dust.print_msg "setting owner of #{File.basename file} to #{user}", options
128
126
  Dust.print_result exec("chown -R #{user} #{file}")[:exit_code], options
129
127
  end
130
128
 
@@ -150,7 +148,6 @@ module Dust
150
148
  def restorecon path, options = {}
151
149
  options = default_options.merge options
152
150
 
153
-
154
151
  # if restorecon is not installed, just return true
155
152
  ret = exec 'which restorecon'
156
153
  return true unless ret[:exit_code] == 0
@@ -1,3 +1,3 @@
1
1
  module Dust
2
- VERSION = "0.4.4"
2
+ VERSION = "0.4.5"
3
3
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 4
8
- - 4
9
- version: 0.4.4
8
+ - 5
9
+ version: 0.4.5
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-20 00:00:00 +01:00
17
+ date: 2012-01-23 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -138,6 +138,7 @@ files:
138
138
  - lib/dust/recipes/mysql.rb
139
139
  - lib/dust/recipes/newrelic.rb
140
140
  - lib/dust/recipes/nginx.rb
141
+ - lib/dust/recipes/pacemaker.rb
141
142
  - lib/dust/recipes/packages.rb
142
143
  - lib/dust/recipes/postgres.rb
143
144
  - lib/dust/recipes/rc_local.rb
@@ -146,6 +147,7 @@ files:
146
147
  - lib/dust/recipes/resolv_conf.rb
147
148
  - lib/dust/recipes/ssh_authorized_keys.rb
148
149
  - lib/dust/recipes/sshd.rb
150
+ - lib/dust/recipes/sudoers.rb
149
151
  - lib/dust/recipes/unattended_upgrades.rb
150
152
  - lib/dust/recipes/zabbix_agent.rb
151
153
  - lib/dust/server.rb