le1t0-deprec 2.1.6.006 → 2.1.6.007

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,5 +1,23 @@
1
1
  # deprec changelog
2
2
 
3
+ = 2.1.6.007 (Jun 10, 2010)
4
+
5
+ * some adjustments to nagios recipe
6
+ * support setting known_hosts for monitoring user in nagios recipe
7
+ * added easy setting of known_hosts for deploy_user in ssh recipe
8
+ * added default profiles
9
+ * rewrote keepalived recipe, added possibility of manually switching master + added configurability of scripts and instances
10
+ * small bugfix for loading god configs
11
+ * added comments for profile recipe
12
+ * commented redhat-cluster recipe
13
+ * small bugfix for rvm recipe
14
+ * commented s3utils recipe
15
+ * commented java recipe
16
+ * added comments to iptables recipe
17
+ * added comments to imagemagick recipe
18
+ * added config_project + comments to god recipe
19
+ * added comments + some small modifications + small bugfix to ssh recipe
20
+
3
21
  = 2.1.6.006 (Jun 4, 2010)
4
22
 
5
23
  * again fixed variable names in rails recipe for being compatible with modify-alternatives-registration branch
@@ -198,7 +198,9 @@ module Deprec2
198
198
  END
199
199
  end
200
200
 
201
+ # allow string substitutions in files on the server
201
202
  def substitute_in_file(filename, old_value, new_value, sep_char='/')
203
+ # XXX sort out single quotes in 'value' - they'l break command!
202
204
  sudo <<-END
203
205
  sh -c "
204
206
  perl -p -i -e 's#{sep_char}#{old_value}#{sep_char}#{new_value}#{sep_char}' #{filename}
@@ -27,6 +27,8 @@ Capistrano::Configuration.instance(:must_exist).load do
27
27
 
28
28
  # Service defaults
29
29
  #
30
+ # load all directories under lib/deprec/recipes, and set :none to the default selection for the respective
31
+ # recipe collection type (i.e. db, app, web, etc)
30
32
  Dir.glob("#{File.dirname(__FILE__)}/*").each do |entry|
31
33
  default "#{File.basename(entry)}_choice".to_sym, :none if File.directory?(entry)
32
34
  end
@@ -81,7 +83,10 @@ Capistrano::Configuration.instance(:must_exist).load do
81
83
  # link application specific recipes into canonical task names
82
84
  # e.g. deprec:web:restart => deprec:nginx:restart
83
85
 
84
-
86
+ # load all directories under lib/deprec/recipes, create a two element array for each, setting the first value
87
+ # to the directory name (as a symbol; the canonicalized namespace), the second to the variable which sets the
88
+ # selection for this recipe collection type. These arrays are collected, empty entries removed and then
89
+ # everything is flattened to a single array, leaving alternating key-values for conversion to a hash.
85
90
  namespaces_to_connect = Hash[*(Dir.glob("#{File.dirname(__FILE__)}/*").collect do |entry|
86
91
  [ File.basename(entry).to_sym, "#{File.basename(entry)}_choice".to_sym ] if File.directory?(entry)
87
92
  end.compact.flatten)]
@@ -36,9 +36,28 @@ Capistrano::Configuration.instance(:must_exist).load do
36
36
 
37
37
  desc "Push god config files to server"
38
38
  task :config, :roles => :god do
39
+ config_system
40
+ config_project
41
+ end
42
+
43
+ task :config_system, :roles => :god do
39
44
  sudo "install -d /etc/god/conf.d"
40
45
  deprec2.push_configs(:god, SYSTEM_CONFIG_FILES[:god])
41
46
  end
47
+
48
+ # Push any files named *.god.#{rails_env} in directory config/god/ to servers with :god role,
49
+ # remove the .#{rails_env} extension and put them in #{deploy_to}/god/. Next, link them to /etc/god/conf.d/
50
+ task :config_project, :roles => :god do
51
+ Dir.new(File.join("config", "god")).entries.select { |e| e =~ /\.god\.#{rails_env}$/ }.each do |entry|
52
+ base_entry = File.basename(entry, ".#{rails_env}")
53
+ file = File.join("config", "god", entry)
54
+ full_remote_path = File.join(deploy_to, 'god', base_entry)
55
+ run "mkdir -p #{File.join(deploy_to, 'god')}"
56
+ std.su_put File.read(file), full_remote_path, '/tmp/', :mode=>0644
57
+ sudo "chown root:root #{full_remote_path}"
58
+ sudo "ln -nsf #{full_remote_path} /etc/god/conf.d/#{application}-#{base_entry}"
59
+ end if File.directory?(File.join("config", "god"))
60
+ end
42
61
 
43
62
  desc "Start God"
44
63
  task :start, :roles => :god do
@@ -7,8 +7,10 @@ Capistrano::Configuration.instance(:must_exist).load do
7
7
 
8
8
  desc "Install imagemagick & rmagick"
9
9
  task :install, :roles => :app do
10
- uninstall # make sure package is uninstalled (if there is any), before attempting source uninstall, since source
11
- # uninstall would also remove binary package files
10
+ # make sure binary package is uninstalled (if there is any), before attempting source uninstall, since source
11
+ # uninstall would also remove binary package files
12
+ uninstall
13
+ # uninstall source (forced, might not be there) so we are sure no old files are left behind
12
14
  top.deprec.imagemagick_src.uninstall
13
15
  apt.install( {:base => %w(imagemagick libmagick9-dev libmagick10)}, :stable )
14
16
  gem2.install 'rmagick' if imagemagick_include_rmagick
@@ -13,6 +13,7 @@ Capistrano::Configuration.instance(:must_exist).load do
13
13
 
14
14
  desc "Install imagemagick & rmagick"
15
15
  task :install, :roles => :app do
16
+ # make sure there is no binary package (force uninstall), since we install in the same location
16
17
  top.deprec.imagemagick_bin.uninstall
17
18
  install_deps
18
19
  deprec2.download_src(SRC_PACKAGES[:imagemagick], src_dir)
@@ -30,7 +31,8 @@ Capistrano::Configuration.instance(:must_exist).load do
30
31
  task :install_deps, :roles => :app do
31
32
  # install binary packages, so all needed dependencies are installed
32
33
  apt.install( {:base => %w(imagemagick libmagick9-dev libperl-dev libmagick10)}, :stable )
33
- # remove binary packages, leaving the dependencies
34
+ # remove binary packages, leaving the dependencies, so we can install from src without needing all deps from
35
+ # source as well
34
36
  apt.install( {:base => %w(imagemagick- libmagick9-dev- libmagick10-)}, :stable )
35
37
  end
36
38
 
@@ -3,6 +3,7 @@ Capistrano::Configuration.instance(:must_exist).load do
3
3
  namespace :deprec do
4
4
  namespace :iptables do
5
5
 
6
+ # see iptables-init script and iptables-default file for syntax
6
7
  set :iptables_allowed, "tcp:22,80,443"
7
8
  set :iptables_forwards, ""
8
9
  set :iptables_binary, "/sbin/iptables"
@@ -1,12 +1,15 @@
1
1
  def accept_license
2
+ # don't ask to accept the license if already preset
2
3
  return if java_dlj_11_license_accepted
3
4
  in_license = false
5
+ # read license text from bottom of this file
4
6
  Capistrano::CLI.ui.say(IO.readlines(__FILE__).collect do |line|
5
7
  in_license = false if line =~ /^# END_LICENSE/
6
8
  current_line = in_license ? line.strip.gsub(/^#[ ]?/, '') : nil
7
9
  in_license = true if line =~ /^# START_LICENSE/
8
10
  current_line
9
11
  end.compact.join("\n"))
12
+ # ask whether user accepts the license
10
13
  prompt = "Accept license (YES, [NO])? "
11
14
  answer = Capistrano::CLI.ui.ask(prompt) do |q|
12
15
  q.overwrite = false
@@ -14,6 +17,7 @@ def accept_license
14
17
  q.validate = /(yes)|(no)|\n/i
15
18
  q.responses[:not_valid] = prompt
16
19
  end
20
+ # set variable to true if license is accepted
17
21
  if answer.upcase == 'YES'
18
22
  set :java_dlj_11_license_accepted, true
19
23
  end
@@ -25,13 +29,16 @@ Capistrano::Configuration.instance(:must_exist).load do
25
29
  namespace :java do
26
30
 
27
31
  set :java_include_jdk, false
32
+ # Set this variable to true in your deployment recipe to accept the license contained below
28
33
  set :java_dlj_11_license_accepted, false
29
34
  set :java_stopthread, true # no idea what this does, but it defaults to true on Hardy and should be preset for auto inst
30
35
 
31
36
  desc "Install Java"
32
37
  task :install do
33
38
  accept_license
39
+ # only install if license was accepted
34
40
  if java_dlj_11_license_accepted
41
+ # preseed questions for debconf, so automatic install works
35
42
  debconf_set_selections_file = "/tmp/java_debconf_set_selections.#{Time.now.strftime("%Y%m%d%H%M%S")}"
36
43
  debconf_set_selections = [
37
44
  "sun-java6-jre sun-java6-jre/stopthread boolean #{java_stopthread}",
@@ -41,16 +48,21 @@ Capistrano::Configuration.instance(:must_exist).load do
41
48
  "sun-java6-bin shared/present-sun-dlj-v1-1 note",
42
49
  "sun-java6-jre shared/present-sun-dlj-v1-1 note"
43
50
  ]
51
+ # select packages to install
44
52
  packages = %w(sun-java6-bin sun-java6-jre)
45
53
  if java_include_jdk
46
54
  packages << "sun-java6-jdk"
55
+ # add preseed answers if also installing jdk
47
56
  debconf_set_selections += [
48
57
  "sun-java6-jdk shared/accepted-sun-dlj-v1-1 boolean #{java_dlj_11_license_accepted}",
49
58
  "sun-java6-jdk shared/present-sun-dlj-v1-1 note"
50
59
  ]
51
60
  end
61
+ # upload preseeded selections
52
62
  put debconf_set_selections.join("\n"), debconf_set_selections_file, :mode => 0644
63
+ # insert preseeded selections into debconf db
53
64
  sudo "debconf-set-selections #{debconf_set_selections_file} ; rm -f #{debconf_set_selections_file}"
65
+ # install java
54
66
  apt.install( {:base => packages}, :stable )
55
67
  end
56
68
  end
@@ -2,15 +2,37 @@
2
2
  Capistrano::Configuration.instance(:must_exist).load do
3
3
  namespace :deprec do
4
4
  namespace :keepalived do
5
-
6
- set :keepalived_script, 'killall -0 haproxy'
7
- set :keepalived_virtual_ipaddress, '192.168.0.99'
8
- set :keepalived_virtual_router_id, '51'
9
- set :keepalived_interface, 'eth0'
10
- set :keepalived_interval, '2' # check every 2 seconds
11
- set :keepalived_weight, '2' # add 2 points of prio if OK
12
- set :keepalived_priority, '101' # 101 on master, 100 on backup
13
- set :keepalived_state, 'MASTER'
5
+
6
+ # :keepalived_scripts should contain a hash where each key is the suffix of the vrrp_script registration,
7
+ # and the value is again a hash, containing as key => value pairs:
8
+ # :script => 'killall -0 haproxy' or any script which returns a 0 or 1 exit value
9
+ # :interval => 1
10
+ # :weight => 2
11
+ set :keepalived_scripts, {
12
+ :haproxy => {
13
+ :script => 'killall -0 haproxy',
14
+ :interval => 1,
15
+ :weight => 2
16
+ }
17
+ }
18
+
19
+ # :keepalived_instances should contain a hash with at least one key => value pair. The key should be a string
20
+ # with the virtual IP address. The value is again a hash with some settings, containing as key => value pairs:
21
+ # :virtual_router_id => '51' or any unique integer among all VRRP instances on the same subnet
22
+ # :interface => 'eth0'
23
+ # :priority => '101', usually should be one higher for MASTER than for BACKUP
24
+ # :state => 'MASTER' or 'BACKUP', automatically adds :wanted_state to :scripts below
25
+ # :scripts => symbol or hash of scripts to execute for this instance, when left undefined all scripts defined above
26
+ # are added
27
+ set :keepalived_instances, {
28
+ "192.168.0.99" => {
29
+ :virtual_router_id => '51',
30
+ :interface => 'eth0',
31
+ :priority => '101',
32
+ :state => 'MASTER',
33
+ :scripts => :haproxy
34
+ }
35
+ }
14
36
 
15
37
  desc "Install keepalived on server"
16
38
  task :install, :roles => :failover do
@@ -12,6 +12,10 @@ Capistrano::Configuration.instance(:must_exist).load do
12
12
  set :nagios_htpasswd_file, '/usr/local/nagios/etc/htpasswd.users'
13
13
  # default :application, 'nagios'
14
14
  set :nagios_ssh_key, nil
15
+ # all SSH hostnames or IPs that nagios should check
16
+ set :nagios_known_hosts, [ ]
17
+ # allow nagios user on check_hosts to do certain commands through sudo
18
+ set :nagios_sudo_commands, [ ] # i.e.: %w(/usr/bin/killall /bin/kill /sbin/iptables /bin/cat)
15
19
 
16
20
  SRC_PACKAGES[:nagios] = {
17
21
  :url => "http://prdownloads.sourceforge.net/sourceforge/nagios/nagios-3.2.0.tar.gz",
@@ -52,7 +56,7 @@ Capistrano::Configuration.instance(:must_exist).load do
52
56
 
53
57
  task :create_nagios_user, :roles => :nagios do
54
58
  deprec2.groupadd(nagios_group)
55
- deprec2.useradd(nagios_user, :group => nagios_group, :homedir => false)
59
+ deprec2.useradd(nagios_user, :group => nagios_group)
56
60
  # deprec2.add_user_to_group(nagios_user, apache_user)
57
61
  deprec2.groupadd(nagios_cmd_group)
58
62
  deprec2.add_user_to_group(nagios_user, nagios_cmd_group)
@@ -145,6 +149,10 @@ Capistrano::Configuration.instance(:must_exist).load do
145
149
  deprec2.push_configs(:nagios, SYSTEM_CONFIG_FILES[:nagios])
146
150
  config_check
147
151
  restart
152
+ if nagios_known_hosts.size > 0
153
+ put nagios_known_hosts.join("\n"), tmp_file = "/tmp/ssh_keyscan_#{Time.now.strftime("%Y%m%d%H%M%S")}.txt", :mode => 0644
154
+ run "ssh-keyscan -f #{tmp_file} -t rsa > ~nagios/.ssh/known_hosts ; rm -f #{tmp_file} ; chown #{nagios_user}:#{nagios_group} ~nagios/.ssh/known_hosts"
155
+ end
148
156
  end
149
157
 
150
158
  desc "Run Nagios config check"
@@ -212,35 +220,45 @@ Capistrano::Configuration.instance(:must_exist).load do
212
220
  create_nagios_user
213
221
  deprec2.download_src(SRC_PACKAGES[:nagios_plugins], src_dir)
214
222
  deprec2.install_from_src(SRC_PACKAGES[:nagios_plugins], src_dir)
223
+ config_access
224
+ install_custom
215
225
  end
216
226
 
227
+ # allow the user to install custom plugins from RAILS_ROOT/config/nagios_plugins/plugins
228
+ # any file there is uploaded to /usr/local/nagios/libexec and chmodded to 755
217
229
  desc "Install user plugins for nagios from config/nagios_plugins/plugins in user's project"
218
230
  task :install_custom do
219
- remote_path = File.join('/', 'usr', 'local', 'nagios', 'libexec')
220
231
  plugins_path = File.join('config', 'nagios_plugins', 'plugins')
221
- Dir.new(plugins_path).entries.each do |entry|
222
- remote_plugin = File.join(remote_path, entry)
223
- plugin = File.join(plugins_path, entry)
224
- if File.file?(plugin)
225
- std.su_put File.read(plugin), remote_plugin, '/tmp', :mode => 0755
232
+ if File.directory?(plugins_path)
233
+ remote_path = File.join('/', 'usr', 'local', 'nagios', 'libexec')
234
+ Dir.new(plugins_path).entries.each do |entry|
235
+ remote_plugin = File.join(remote_path, entry)
236
+ plugin = File.join(plugins_path, entry)
237
+ if File.file?(plugin)
238
+ std.su_put File.read(plugin), remote_plugin, '/tmp', :mode => 0755
239
+ end
226
240
  end
227
241
  end
228
242
  end
229
243
 
244
+ # configure ssh + sudo for nagios:
245
+ # * allow certain commands so nagios can do checks (killall, kill, iptables, cat) as root
246
+ # * add nagios ssh key to authorized keys on servers to check (if the variable is set)
230
247
  desc "configure ssh + sudo access for nagios_user"
231
248
  task :config_access do
232
- deprec2.append_to_file_if_missing('/etc/sudoers', "#{nagios_user} ALL=(root) NOPASSWD:/usr/bin/killall")
233
- deprec2.append_to_file_if_missing('/etc/sudoers', "#{nagios_user} ALL=(root) NOPASSWD:/bin/kill")
234
- deprec2.append_to_file_if_missing('/etc/sudoers', "#{nagios_user} ALL=(root) NOPASSWD:/sbin/iptables")
235
- deprec2.append_to_file_if_missing('/etc/sudoers', "#{nagios_user} ALL=(root) NOPASSWD:/bin/cat")
236
- sudo "mkdir -p /home/#{nagios_user}/.ssh"
237
- sudo "chmod 700 /home/#{nagios_user}/.ssh"
238
- if nagios_ssh_key
239
- sudo "echo '#{nagios_ssh_key}' >> /tmp/authorized_keys_file_for_nagios_user.tmp"
249
+ nagios_sudo_commands.each do |command|
250
+ deprec2.append_to_file_if_missing('/etc/sudoers', "#{nagios_user} ALL=(root) NOPASSWD:#{command}")
251
+ end
252
+ unless nagios_ssh_key.nil?
253
+ sudo "mkdir -p /home/#{nagios_user}/.ssh"
254
+ sudo "chmod 700 /home/#{nagios_user}/.ssh"
255
+ if nagios_ssh_key
256
+ sudo "echo '#{nagios_ssh_key}' >> /tmp/authorized_keys_file_for_nagios_user.tmp"
257
+ end
258
+ sudo "mv /tmp/authorized_keys_file_for_nagios_user.tmp /home/#{nagios_user}/.ssh/authorized_keys"
259
+ sudo "chmod 600 /home/#{nagios_user}/.ssh/authorized_keys"
260
+ sudo "chown -R nagios:nagios /home/#{nagios_user}/.ssh"
240
261
  end
241
- sudo "mv /tmp/authorized_keys_file_for_nagios_user.tmp /home/#{nagios_user}/.ssh/authorized_keys"
242
- sudo "chmod 600 /home/#{nagios_user}/.ssh/authorized_keys"
243
- sudo "chown -R nagios:nagios /home/#{nagios_user}/.ssh"
244
262
  end
245
263
 
246
264
  # Install dependencies for nagios plugins
@@ -1,44 +1,124 @@
1
1
  # Copyright 2009-2010 by le1t0@github. All rights reserved.
2
+
3
+ # A little bit about profiles.. What I wanted to achieve was having a list of tasks which I can run,
4
+ # which install a server from bare install to fully functional with only one deprec call. Before,
5
+ # I fixed this by writing pages and pages of capistrano tasks performing each step, installing,
6
+ # configuring and activating all that was needed and for all different configurations. I really
7
+ # didn't like this as it was a nightmare to maintain. So I knew I wanted something that very compactly
8
+ # can describe the steps to take to fully install a server.
9
+ #
10
+ # I had no idea what to name it, I based my ideas on the notion of tasks in the debian linux distribution, but
11
+ # since the word task is already taken in capistrano, I just went for the word profile :) So a profile is
12
+ # basically an ordered list of recipes to run, including which tasks to perform on them; furthermore, a
13
+ # profile can reference other profiles, so you can extract out generic definitions. I defined
14
+ # [ :config_gen, :install, :config, :activate, :start ] to be the default list of tasks to perform on a recipe,
15
+ # but made it possible to override this list per profile (for example when you want to make profiles which can
16
+ # give you a status overview of the entire server farm or something).. Each profile would mention only the name
17
+ # of a recipe to run, and possibly (as arguments) the list of tasks to include this recipe for. So when a profile
18
+ # should run in the 5 mentioned tasks, and you add recipe imagemagick with as an argument :install, then it would
19
+ # only run install on the imagemagick recipe. Finally, I added the option of calling a custom task (i.e. not one
20
+ # of the 5 default ones). Some examples:
21
+ #
22
+ # profile :tools, :install do |p, r| # only execute the :install task on the include recipes in this profile
23
+ # r.ubuntu
24
+ # r.nagios_plugins
25
+ # r.imagemagick
26
+ # r.aspell
27
+ # end
28
+ #
29
+ # profile :base do |p, r| # the 'p' object allows you to call other profiles, the 'r' object allows you to call recipes
30
+ # r.iptables
31
+ # r.postfix
32
+ # r.ntp
33
+ # r.ubuntu.utils.bash :config # call :config in utils.bash namespace of ubuntu recipe
34
+ # p.tools # include another profile in this profile
35
+ # end
36
+ #
37
+ # profile :app_base do |p, r| # this profile, as most others, doesn't define a custom set of tasks, so it runs [ :config_gen, :install, :config, :activate, :start ]
38
+ # r.call.passenger.config_gen_system :config_gen
39
+ # r.call.rails.install_stack :install # run custom task :install_stack during the :install phase on the rails recipe; use call to define calling a custom task
40
+ # r.java
41
+ # end
42
+ #
43
+ # profile :db_base do |p, r|
44
+ # r.mysql
45
+ # r.sphinx :install # only execute :install for sphinx, for the others run the defaults ([ :config_gen, :install, :config, :activate, :start ])
46
+ # r.java
47
+ # end
48
+ #
49
+ # profile :composite_server do |p, r| # make a profile purely based on other profiles
50
+ # p.base
51
+ # p.app_base
52
+ # p.db_base
53
+ # end
54
+
2
55
  Capistrano::Configuration.instance(:must_exist).load do
3
56
  class DeprecProfile
57
+ # list of profiles or recipes to call for this profile
4
58
  attr_accessor :tasks_to_call
59
+ # keep track the current called profile/recipe. We can't add them directly to :tasks_to_call, because we need to support
60
+ # (namespace) nested tasks and literal tasks as well.
5
61
  attr_accessor :current_task
62
+ # boolean which states whether we are in the sub namespace of a recipe or just the base recipe
6
63
  attr_accessor :sub_namespace
64
+ # if we want to call another task than the default for a certain step (i.e. calling :install_all_my_stuff instead
65
+ # of just :install for the install step) this variable (boolean) tells us whether this is the case
7
66
  attr_accessor :literal
8
67
 
9
68
  def initialize
69
+ # by default, we have no profiles/recipes defined and we don't start out in a sub_namespace
10
70
  @tasks_to_call = []
11
71
  @sub_namespace = false
12
72
  end
13
73
 
14
74
  def call
75
+ # only support calling literal tasks when we are not in a sub_namespace
15
76
  if !@sub_namespace
77
+ # since method_missing won't be called now, we need to call finalize, before continuing
16
78
  finalize
17
- @literal = true # can't set directly in current_task, since it will run finalize again in method_missing then (wrongly)
79
+ @literal = true # can't set directly in :current_task, since it will run finalize again in method_missing then (wrongly)
18
80
  end
19
81
  self
20
82
  end
21
83
 
84
+ # the very core of the profiles code, which implements the DSL for defining profiles and recipes to call
22
85
  def method_missing(method_name, *args, &block)
23
86
  obj = nil
87
+ # if we are not in a sub_namespace, then this is a base recipe or profile to call
24
88
  if !@sub_namespace
89
+ # call finalize, so any previous current_task gets registered
25
90
  finalize
91
+ # make sure we start out fresh
26
92
  @current_task ||= {}
93
+ # if we want to call a literal task, define it now in the :current_task variable, and reset the literal variable
94
+ # for next tasks to come
27
95
  @current_task[:literal] = true if @literal
28
96
  @literal = false
97
+ # define the name of the recipe or profile to call
29
98
  @current_task[:name] = method_name.to_s
99
+ # define any arguments as well, which could be a list of symbols overriding (only_recipe_tasks) below. Use this
100
+ # when you want a certain recipe or profile to only execute for one or more certain steps. I.e. when the entire
101
+ # profile executes for :install and :config steps, but you want imagemagick to only execute for the :install step,
102
+ # you would use this.
30
103
  @current_task[:args] = args.size == 0 ? nil : args.flatten
104
+ # return a copy of ourselves, since we don't want to contaminate the current one with the sub_namespace setting,
105
+ # as we can never set it to false anymore (no way to detect it)
31
106
  obj = self.dup
32
107
  obj.sub_namespace = true
33
108
  else
109
+ # we are in a sub_namespace, so define the sub_namespace name by concatting it to the existing name with a dot
34
110
  @current_task[:name] = [ @current_task[:name], method_name.to_s ].join('.')
35
- @current_task[:args] = args.size == 0 ? nil : args.flatten
111
+ # register any arguments as well
112
+ @current_task[:args] = args.size == 0 ? nil : args.flatten
113
+ # return our self, so we can also go into another sub_namespace
36
114
  obj = self
37
115
  end
38
116
  obj
39
117
  end
40
118
 
41
119
  def finalize
120
+ # if a current task is defined, make sure it gets registered in :tasks_to_call and reset :current_task,
121
+ # for a possible next call
42
122
  if !@current_task.nil?
43
123
  @tasks_to_call << @current_task
44
124
  @current_task = nil
@@ -46,11 +126,20 @@ Capistrano::Configuration.instance(:must_exist).load do
46
126
  end
47
127
  end
48
128
 
129
+ # define a profile, with arguments
130
+ # - a name for the resulting task which executes the profile
131
+ # - optionally an array of (or just one) symbol(s) of task names to execute (by default) within the recipes
132
+ # contained in this profile
133
+ # - a block containing calls to either other profiles or recipes
49
134
  def profile(profile_task_name, *only_recipe_tasks, &block)
50
135
  only_recipe_tasks = [ :config_gen, :install, :config, :activate, :start ] if only_recipe_tasks.size == 0
136
+ # Execute the block with two arguments, the first will contain profiles which should be called, the second
137
+ # will contain recipes which should be called
51
138
  yield(profiles = DeprecProfile.new, recipes = DeprecProfile.new)
52
139
  profiles.finalize
53
140
  recipes.finalize
141
+ # define a list of distclean tasks which remove all stamps for the respective profile for either all step tasks
142
+ # (only_recipe_tasks) or one of these
54
143
  ([ :all ] + only_recipe_tasks).each do |tsk|
55
144
  cmd = "
56
145
  namespace :deprec do\nnamespace :profiles do\nnamespace :#{profile_task_name} do\nnamespace :distclean do\ndesc '#{profile_task_name}:distclean:#{tsk}'\ntask :#{tsk} do\n
@@ -58,7 +147,9 @@ Capistrano::Configuration.instance(:must_exist).load do
58
147
  "
59
148
  puts cmd if ENV['DEBUG_PROFILES']
60
149
  eval(cmd)
61
- end
150
+ end
151
+ # define the :all task for the profile, which calls all tasks defined in (only_recipe_tasks) on the profile itself, and
152
+ # stamps its success. Remove all stamps when successful
62
153
  cmd = "
63
154
  namespace :deprec do\nnamespace :profiles do\nnamespace :#{profile_task_name} do\ndesc '#{profile_task_name}:all'\ntask :all do\n
64
155
  #{only_recipe_tasks.collect do |n|
@@ -71,6 +162,9 @@ Capistrano::Configuration.instance(:must_exist).load do
71
162
  "
72
163
  puts cmd if ENV['DEBUG_PROFILES']
73
164
  eval(cmd)
165
+ # define the various tasks defined in (only_recipe_tasks) for this profile, they should call their respective step task
166
+ # on the profiles and recipes contained within this profile, and stamp their success. Remove all stamps if everything
167
+ # was successful
74
168
  only_recipe_tasks.each do |rt|
75
169
  cmd = "
76
170
  desc '#{profile_task_name}:#{rt}'\nnamespace :deprec do\nnamespace :profiles do\nnamespace :#{profile_task_name} do\ntask :#{rt} do\n
@@ -97,11 +191,14 @@ Capistrano::Configuration.instance(:must_exist).load do
97
191
  end
98
192
  end
99
193
 
194
+ # create a stamp for the currently executed profile, the recipe that has been completed and specifically which task
195
+ # has been run on it
100
196
  def profile_stamp(profile_name, executing_recipe, executing_task)
101
197
  stamp_name = "stamp-#{profile_name.gsub(/:/, '_')}-#{executing_task_name(executing_recipe, executing_task)}"
102
198
  run "mkdir -p ~/.deprec ; touch ~/.deprec/#{stamp_name}"
103
199
  end
104
-
200
+
201
+ # check whether a stamp already exists
105
202
  def profile_stamp_exists?(profile_name, executing_recipe, executing_task)
106
203
  stamp_name = "stamp-#{profile_name.gsub(/:/, '_')}-#{executing_task_name(executing_recipe, executing_task)}"
107
204
  result = nil
@@ -111,10 +208,12 @@ Capistrano::Configuration.instance(:must_exist).load do
111
208
  result
112
209
  end
113
210
 
211
+ # remove all stamps for a profile
114
212
  def remove_profile_stamps(profile_name)
115
213
  run "mkdir -p ~/.deprec ; rm -f ~/.deprec/stamp-#{profile_name.gsub(/:/, '_')}-*"
116
214
  end
117
215
 
216
+ # helper method for the stamp and stamp_exists? methods above
118
217
  def executing_task_name(executing_recipe, executing_task)
119
218
  if executing_recipe =~ /\./
120
219
  "#{executing_recipe.gsub(/\./, '_')}--#{executing_task}"
@@ -122,4 +221,24 @@ Capistrano::Configuration.instance(:must_exist).load do
122
221
  "#{executing_recipe}_#{executing_task}"
123
222
  end
124
223
  end
224
+
225
+ profile :rails_stack, :install do |p, r|
226
+ r.ruby
227
+ r.rails
228
+ r.svn
229
+ r.git
230
+ r.web
231
+ r.app
232
+ r.monit if use_monit
233
+ r.logrotate if use_logrotate
234
+ end
235
+
236
+ profile :single_server do |p,r|
237
+ p.rails_stack
238
+ r.iptables
239
+ r.postfix
240
+ r.ntp
241
+ r.mysql
242
+ end
243
+
125
244
  end
@@ -3,6 +3,7 @@ Capistrano::Configuration.instance(:must_exist).load do
3
3
  namespace :deprec do
4
4
  namespace :redhat_cluster do
5
5
 
6
+ # check redhat cluster's cluster.conf manpage for explanation of configuring this
6
7
  set :redhat_cluster_name, 'storagecluster'
7
8
  set :redhat_cluster_config_version, '1'
8
9
  set :redhat_cluster_nodes, [
@@ -114,11 +115,14 @@ Capistrano::Configuration.instance(:must_exist).load do
114
115
  end
115
116
 
116
117
  task :config_common, :roles => [:storage_client, :storage_server] do
118
+ # add some modules to load
117
119
  deprec2.append_to_file_if_missing('/etc/modules', 'dm-mod')
118
120
  deprec2.append_to_file_if_missing('/etc/modules', 'gfs')
119
121
  deprec2.append_to_file_if_missing('/etc/modules', 'lock_dlm')
120
- deprec2.append_to_file_if_missing('/etc/modules', 'gnbd')
122
+ deprec2.append_to_file_if_missing('/etc/modules', 'gnbd')
123
+ # comment out default setting of locking_type
121
124
  deprec2.substitute_in_file('/etc/lvm/lvm.conf', '^(\s*)(locking_type = 1\s*)$', '$1#$2')
125
+ # uncomment these settings in config file
122
126
  deprec2.substitute_in_file('/etc/lvm/lvm.conf', '^(\s*)#\s*(locking_library = \"liblvm2clusterlock.so\"\s*)$', '$1$2')
123
127
  deprec2.substitute_in_file('/etc/lvm/lvm.conf', '^(\s*)#\s*(locking_type = 2\s*)$', '$1$2')
124
128
  deprec2.substitute_in_file('/etc/lvm/lvm.conf', '^(\s*)#\s*(library_dir = \"/lib/lvm2\"\s*)$', '$1$2', '%')
@@ -19,9 +19,9 @@ EOF
19
19
  task :install_rubies do
20
20
  rvm_rubies.each_with_index do |ruby, i|
21
21
  run "rvm install #{ruby}"
22
- run "rvm --default #{ruby}" if i == 0 && (rvm_default_ruby.empty? || rvm_default_ruby.nil?)
22
+ run "rvm --default #{ruby}" if i == 0 && (rvm_default_ruby.nil? || rvm_default_ruby.empty?)
23
23
  end
24
- if !(rvm_default_ruby.empty? || rvm_default_ruby.nil?)
24
+ if !(rvm_default_ruby.nil? || rvm_default_ruby.empty?)
25
25
  set_default = rvm_default_ruby == "system" ? rvm_default_ruby : "--default #{rvm_default_ruby}"
26
26
  run "rvm #{set_default}"
27
27
  end
@@ -4,7 +4,7 @@ Capistrano::Configuration.instance(:must_exist).load do
4
4
  namespace :s3utils do
5
5
 
6
6
  set :s3utils_bucket_location, 'EU'
7
- set :s3utils_calling_format, 'SUBDOMAIN'
7
+ set :s3utils_calling_format, 'SUBDOMAIN' # used by s3sync in s3config.yml
8
8
  set :s3utils_access_key, "0123456789ABCDEFGHIJ"
9
9
  set :s3utils_secret_key, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcd"
10
10
  set :s3utils_passphrase, "my_passphrase"
@@ -19,7 +19,7 @@ Capistrano::Configuration.instance(:must_exist).load do
19
19
  :install => 'cp -a S3 s3cmd /usr/local/bin/ ; cp s3cmd.1 /usr/local/share/man/man1/ ;'
20
20
  }
21
21
 
22
- # setting it as a class variable makes it initialize too early, making 'user' contain the wrong value!
22
+ # XXX - setting it as a class variable makes it initialize too early, making 'user' contain the wrong value! - le1t0
23
23
  def s3utils_system_config_files
24
24
  [
25
25
  {:template => "s3cfg",
@@ -3,15 +3,23 @@ Capistrano::Configuration.instance(:must_exist).load do
3
3
  namespace :deprec do
4
4
  namespace :ssh do
5
5
 
6
- # hash of :user => :ssh_key combinations
7
- # :ssh_*_keys can be:
8
- # - one key (a string)
9
- # - an array of keys
6
+ # define SSH keys for each user
7
+ # :ssh_user_keys should be a hash, with:
8
+ # * the keys being any identifier for the user
9
+ # * the values being either:
10
+ # ** one SSH key in the form of a string
11
+ # ** multiple SSH keys in the form of an array of strings
12
+ # Define this variable in the main deploy.rb when using multistage capistrano
10
13
  set :ssh_user_keys, { }
11
- set :ssh_host_keys, { }
12
- # an array of symbols or strings containing user_names/host_names as defined in :ssh_*_keys
14
+ # :ssh_users should contain an array of user identifiers as defined in :ssh_user_keys,
15
+ # use this variable to define which users have access to the all the servers defined.
16
+ # Specify this variable in a stage deploy file when using multistage capistrano
17
+ # (so you can have different users have access to different servers)
13
18
  set :ssh_users, [ ]
14
- set :ssh_hosts, [ ]
19
+ # :ssh_known_hosts variable should contain the hostnames or IP addresses (as an array of strings)
20
+ # of all hosts that should be put in the deploy_user's known_hosts file. This known_hosts file will
21
+ # be put on all defined servers.
22
+ set :ssh_known_hosts, [ ]
15
23
 
16
24
  SYSTEM_CONFIG_FILES[:ssh] = [
17
25
 
@@ -43,6 +51,10 @@ Capistrano::Configuration.instance(:must_exist).load do
43
51
  restart
44
52
  end
45
53
 
54
+ # set access for SSH:
55
+ # * add keys of users to authorized_keys file of deploy_user
56
+ # * add host keys to known hosts file of deploy_user
57
+ desc "create authorized_keys and known_hosts files on servers"
46
58
  task :set_access do
47
59
  if ssh_users.size > 0
48
60
  run "rm -f ~/.ssh/authorized_keys.new"
@@ -56,16 +68,9 @@ Capistrano::Configuration.instance(:must_exist).load do
56
68
  run "mv ~/.ssh/authorized_keys.new ~/.ssh/authorized_keys"
57
69
  end
58
70
 
59
- if ssh_hosts.size > 0
60
- run "rm -f ~/.ssh/known_hosts.new"
61
- ssh_hosts.each do |ssh_user|
62
- keys = [ssh_host_keys[ssh_user]].flatten
63
- keys.each do |ssh_key|
64
- deprec2.append_to_file_if_missing('~/.ssh/known_hosts.new', ssh_key)
65
- end
66
- end
67
- run "cp ~/.ssh/known_hosts ~/.ssh/known_hosts.bak"
68
- run "mv ~/.ssh/known_hosts.new ~/.ssh/known_hosts"
71
+ if ssh_known_hosts.size > 0
72
+ put ssh_known_hosts.join("\n"), tmp_file = "/tmp/ssh_keyscan_#{Time.now.strftime("%Y%m%d%H%M%S")}.txt", :mode => 0644
73
+ run "ssh-keyscan -f #{tmp_file} -t rsa > ~/.ssh/known_hosts ; rm -f #{tmp_file}"
69
74
  end
70
75
  end
71
76
 
@@ -47,7 +47,9 @@ function define_forwards () {
47
47
  srcport="$(echo $forward | cut -d '>' -f 1 | cut -d ':' -f 2)"
48
48
  destip="$(echo $forward | cut -d ';' -f 1 | cut -d '>' -f '2' | cut -d ':' -f 1)"
49
49
  destport="$(echo $forward | cut -d ';' -f 1 | cut -d '>' -f '2' | cut -d ':' -f 2)"
50
+ # define forward in the nat chain, redirect to the destination IP and port
50
51
  $IPTABLES -t nat -A PREROUTING -p $proto -d $localip --dport $srcport -j DNAT --to $destip:$destport
52
+ # allow access to the destination IP and port in the FORWARD chain
51
53
  $IPTABLES -A FORWARD -p $proto -d $destip --dport $destport -j ACCEPT
52
54
  } ; done
53
55
  }
@@ -71,7 +73,9 @@ function set_default_rules () {
71
73
 
72
74
  # don't call parse_sources directly! It's called by set_allowed_rules
73
75
  function parse_sources () {
76
+ # parse all sources
74
77
  for sourcedef in $1 ; do {
78
+ # define targets for each source
75
79
  parse_targets "$2" "-s ${sourcedef}"
76
80
  } ; done
77
81
  }
@@ -79,13 +83,18 @@ function parse_sources () {
79
83
  # don't call parse_targets directly! It's called by set_allowed_rules
80
84
  function parse_targets () {
81
85
  sourcedef="$2"
86
+ # parse all targets
82
87
  for targetdef in $1 ; do {
88
+ # targets should be define as:
89
+ # protocol[,protocol[,...]][:port[,port[,...]]]
83
90
  protocols="$(echo $targetdef | awk -F ":" '{ print $1; }' | sed 's/,/ /g')"
84
91
  ports="$(echo $targetdef | awk -F ":" '{ print $2; }' | sed 's/,/ /g')"
85
92
  for protocol in ${protocols} ; do {
93
+ # if no ports are defined, just allow access to the entire protocol (i.e. pptp, vrrp, etc)
86
94
  if [ -z "${ports}" ] ; then
87
95
  $IPTABLES -A INPUT -p ${protocol} ${sourcedef} -m state --state NEW -j ACCEPT ;
88
96
  else
97
+ # for each defined port, allow access to the defined source or the world (if empty)
89
98
  for port in ${ports} ; do {
90
99
  OPT="--dport"
91
100
  [ "$protocol" = "icmp" ] && OPT="--icmp-type"
@@ -97,12 +106,18 @@ function parse_targets () {
97
106
  }
98
107
 
99
108
  function set_allowed_rules () {
109
+ # all rules should be defined in one space separated variable called allowed
100
110
  for ruledef in ${allowed} ; do {
111
+ # everything before the @ sign defines the target specification (i.e. IP + port or protocol to allow access to)
112
+ # targets should be semi colon (;) separated (which are changed to spaces for easy parsing)
101
113
  target="$(echo $ruledef | awk -F "@" '{ print $1; }' | sed 's/;/ /g')"
114
+ # everything after the @ sign defines the source specification (i.e. IP, etc from where the request is coming)
115
+ # sources should be comma (,) separated (which are changed to spaces for easy parsing)
102
116
  source="$(echo $ruledef | awk -F "@" '{ print $2; }' | sed 's/,/ /g')"
117
+ # if there is no source specification (allow entire world), then only define the target
103
118
  if [ -z "${source}" ] ; then
104
119
  parse_targets "$target"
105
- else
120
+ else # else define the source first
106
121
  parse_sources "$source" "$target"
107
122
  fi
108
123
  } ; done
@@ -1,18 +1,38 @@
1
- vrrp_script chk_haproxy { # Requires keepalived-1.1.13
2
- script "<%= keepalived_script %>" # cheaper than pidof
3
- interval <%= keepalived_interval %> # check every 2 seconds
4
- weight <%= keepalived_weight %> # add 2 points of prio if OK
1
+ # touch /etc/keepalived/MASTER to make a BACKUP keepalived be MASTER. Remove it to make it BACKUP again.
2
+ vrrp_script chk_wanted_state {
3
+ script "test -e /etc/keepalived/MASTER"
4
+ interval 1
5
+ weight 2
5
6
  }
6
7
 
7
- vrrp_instance VI_1 {
8
- interface <%= keepalived_interface %>
9
- state <%= keepalived_state %>
10
- virtual_router_id <%= keepalived_virtual_router_id %>
11
- priority <%= keepalived_priority %>
8
+ <% keepalived_scripts.each do |name, settings| %>
9
+ vrrp_script chk_<%= name.to_s %> {
10
+ script "<%= settings[:script] %>"
11
+ interval <%= settings[:interval] %>
12
+ weight <%= settings[:weight] %>
13
+ }
14
+ <% end %>
15
+
16
+ <% instance_counter = 1 %>
17
+ <% keepalived_instances.each do |virtual_ipaddress, settings| %>
18
+ vrrp_instance VI_<%= instance_counter %> {
19
+ interface <%= settings[:interface] %>
20
+ state <%= settings[:state] %>
21
+ virtual_router_id <%= settings[:virtual_router_id] %>
22
+ priority <%= settings[:priority] %>
12
23
  virtual_ipaddress {
13
- <%= keepalived_virtual_ipaddress %>
24
+ <%= virtual_ipaddress %>
14
25
  }
26
+ <% if settings[:state] != 'MASTER' %>
27
+ track_script {
28
+ chk_wanted_state
29
+ }
30
+ <% end %>
31
+ <% (settings[:scripts].nil? || [settings[:scripts]].flatten.empty? ? keepalived_scripts.keys : [settings[:scripts]].flatten).each do |name| %>
15
32
  track_script {
16
- chk_haproxy
33
+ chk_<%= name.to_s %>
17
34
  }
18
- }
35
+ <% end %>
36
+ }
37
+ <% instance_counter += 1 %>
38
+ <% end %>
metadata CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
6
6
  - 2
7
7
  - 1
8
8
  - 6
9
- - 6
10
- version: 2.1.6.006
9
+ - 7
10
+ version: 2.1.6.007
11
11
  platform: ruby
12
12
  authors:
13
13
  - Le1t0
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-04 00:00:00 +02:00
18
+ date: 2010-06-10 00:00:00 +02:00
19
19
  default_executable: depify
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency