seesaw 0.1.0 → 0.2.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/History.txt CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.2.0 / 2007-08-19
2
+
3
+ * added seesaw::switch command to switch to a guaranteed running cluster configuration
4
+ * added seesaw::configure command to autogenerate configuration files
5
+
6
+
1
7
  == 0.1.0 / 2007-08-18
2
8
 
3
9
  * 1 major enhancement
data/lib/seesaw/init.rb CHANGED
@@ -3,46 +3,49 @@ require 'mongrel'
3
3
  require 'yaml'
4
4
  require 'fileutils'
5
5
  require 'seesaw/mongrel_cluster_patch'
6
+ require "erb"
6
7
 
7
8
  module Seesaw
8
- VERSION = '0.1.0'
9
+ VERSION = '0.2.0'
9
10
 
10
11
  module CommandBase
12
+ def log(message)
13
+ puts message
14
+ end
15
+
11
16
  def symlink(cluster)
12
- p "symlink to #{cluster}"
17
+ log "symlink to #{cluster}"
13
18
  file = File.join(@config_path, @config_files[cluster])
14
- p "target: #{file}"
15
- FileUtils.ln_sf( file, @config_symlink)
19
+ system("#{@symlink_cmd} #{file} #{@config_symlink}")
16
20
  end
17
21
 
18
22
  def restart_mongrels(cluster=nil)
19
- p "restart mongrels #{cluster}"
23
+ log "restart mongrels #{cluster}"
20
24
  stop_mongrels(cluster)
21
25
  start_mongrels(cluster)
22
26
  end
23
27
 
24
28
  def start_mongrels(cluster=nil)
25
- p "start mongrels #{cluster}"
29
+ log "start mongrels #{cluster}"
26
30
  cmd = "mongrel_rails seesaw::start"
27
- cmd << " --cluster #{cluster}" if cluster
31
+ cmd << " --cluster #{cluster}" if cluster && cluster != "all"
28
32
  system(cmd)
29
33
  end
30
34
 
31
35
  def stop_mongrels(cluster=nil)
32
- p "stop mongrels #{cluster}"
36
+ log "stop mongrels #{cluster}"
33
37
  cmd = "mongrel_rails seesaw::stop"
34
38
  cmd << " --cluster #{cluster}" if cluster
35
39
  system(cmd)
36
40
  end
37
41
 
38
42
  def restart_http(cluster=nil)
39
- p "nginx restart"
43
+ log "webserver restart"
40
44
  system(@restart_cmd)
41
- sleep 5
42
45
  end
43
46
 
44
47
  def shutdown_half_cluster(half)
45
- p "shutdown half #{half}"
48
+ log "shutdown half #{half}"
46
49
  other_half = half == 1 ? 2 : 1
47
50
  symlink(other_half)
48
51
  restart_http
@@ -50,14 +53,14 @@ module Seesaw
50
53
  end
51
54
 
52
55
  def switch_to_half_cluster(half)
53
- p "switch_to_half_cluster #{half}"
56
+ log "switch_to_half_cluster #{half}"
54
57
  other_half = half == 1 ? 2 : 1
55
58
  shutdown_half_cluster(other_half)
56
59
  start_mongrels(other_half)
57
60
  end
58
61
 
59
62
  def start_cluster
60
- p "start cluster"
63
+ log "start cluster"
61
64
  symlink("all")
62
65
  restart_http
63
66
  end
@@ -72,6 +75,7 @@ module Seesaw
72
75
  @config_symlink = @options["config_symlink"] || "cluster.conf"
73
76
  @config_symlink = File.join(@config_path, @config_symlink)
74
77
  @restart_cmd = @options["restart_cmd"] || "apachectl graceful"
78
+ @symlink_cmd = @options["symlink_cmd"] || "ln -sf"
75
79
  end
76
80
 
77
81
  def validate
@@ -87,21 +91,146 @@ module Seesaw
87
91
 
88
92
  end
89
93
 
90
- class Migrate < GemPlugin::Plugin "/commands"
94
+ class Ripple < GemPlugin::Plugin "/commands"
91
95
  include Mongrel::Command::Base
92
96
  include CommandBase
93
97
 
94
98
  def run
95
99
  parse_options
96
- p "c1"
97
100
  switch_to_half_cluster(1)
98
- p "c2"
99
101
  switch_to_half_cluster(2)
100
- p "nighty night"
101
- sleep 20
102
- p "all"
103
102
  start_cluster
104
- p "done"
103
+ log "done"
105
104
  end
106
105
  end
107
- end
106
+
107
+ class Switch < GemPlugin::Plugin "/commands"
108
+ include Mongrel::Command::Base
109
+ include CommandBase
110
+
111
+ def configure
112
+ options [
113
+ ['-C', '--config PATH', "Path to cluster configuration file", :@config_file, "config/seesaw.yml"],
114
+ ['', '--cluster CLUSTER', "Switch to cluster configuration CLUSTER: [1|2|all]", :@cluster, 'all']
115
+ ]
116
+ end
117
+
118
+ def validate
119
+ valid?(["1","2","all"].include?(@cluster), "invalid option for --cluster")
120
+ @valid
121
+ end
122
+
123
+ def run
124
+ parse_options
125
+ unless "all" == @cluster
126
+ @cluster = @cluster.to_i
127
+ other_half = @cluster == 1 ? 2 : 1
128
+ end
129
+ start_mongrels(@cluster)
130
+ symlink(@cluster)
131
+ restart_http
132
+ stop_mongrels(other_half) unless "all" == @cluster
133
+ end
134
+ end
135
+
136
+ class Configure < GemPlugin::Plugin "/commands"
137
+ include Mongrel::Command::Base
138
+
139
+ def configure
140
+ options [
141
+ ['-N', '--num-servers INT', "Number of Mongrel servers", :@servers, 2],
142
+ ['-C', '--config PATH', "Path to seesaw configuration file", :@config_file, 'config/seesaw.yml'],
143
+ ['-M', '--mongrel PATH', "Path to mongrel cluster configuration file", :@mongrel_config_file, 'config/mongrel_cluster.yml'],
144
+ ['', '--http_config PATH', "Path to the http server configuration includes", :@http_config_path, "config/http_cluster"],
145
+ ['', '--server TYPE', "Webserver to generate example configuration for. TYPE can be nginx or apache. Default is nginx.", :@server, 'nginx']
146
+ ]
147
+ end
148
+
149
+ def validate
150
+ valid?(['nginx','apache'].include?(@server), "Server must be nginx or apache")
151
+ valid_dir? File.dirname(@config_file), "Path to config file not valid: #{@config_file}"
152
+ valid?(File.exist?(@mongrel_config_file), "Path to mongrel cluster config file not valid: #{@mongrel_config_file}")
153
+
154
+ return @valid
155
+ end
156
+
157
+ def write_config_include(file, ports)
158
+
159
+ log "writing #{file}"
160
+
161
+ ip = "127.0.0.1"
162
+ server_lines = ""
163
+ line_template = ERB.new(INCLUDES[@server][:server_line])
164
+ ports.each do |port|
165
+ server_lines << line_template.result(binding)
166
+ end
167
+
168
+ template = ERB.new(INCLUDES[@server][:template])
169
+ File.open(file, "w") { |f| f.write(template.result(binding)) }
170
+ end
171
+
172
+ def run
173
+ restart_cmds = {
174
+ 'nginx' => "sudo kill -HUP `cat /opt/local/var/log/nginx.pid`",
175
+ 'apache' => "sudo apachectl graceful"
176
+ }
177
+
178
+ @options = {}
179
+
180
+ @options["config_path"] = @http_config_path
181
+ @options["restart_cmd"] = restart_cmds[@server]
182
+ @options["symlink_cmd"] = "ln -sf"
183
+ @options["config_symlink"] = "cluster.conf"
184
+ @options["config_files"] = {}
185
+ @options["config_files"]["all"] = "cluster_all.conf"
186
+ @options["config_files"][1] = "cluster_1.conf"
187
+ @options["config_files"][2] = "cluster_2.conf"
188
+
189
+ # write seesaw configuration
190
+ log "Writing configuration file to #{@config_file}."
191
+ File.open(@config_file,"w") {|f| f.write(@options.to_yaml)}
192
+
193
+ # read mongrel cluster configuration to find number of servers
194
+ mongrel_conf = YAML.load(File.read(@mongrel_config_file))
195
+
196
+ # create cluster config directory if it doesn't exist
197
+ Dir.mkdir(@http_config_path) unless File.exist?(@http_config_path)
198
+
199
+ # write cluster configuration files for appropriate server
200
+ start_port = mongrel_conf["port"]
201
+ end_port = mongrel_conf["port"]+mongrel_conf["servers"] - 1
202
+ mid_port = ((end_port+start_port)/2.0).ceil
203
+
204
+ # full cluster
205
+ write_config_include(File.join(@http_config_path,@options["config_files"]["all"]), (start_port..end_port))
206
+
207
+ # front half
208
+ write_config_include(File.join(@http_config_path,@options["config_files"][1]), (start_port..mid_port-1))
209
+
210
+ # back half
211
+ write_config_include(File.join(@http_config_path,@options["config_files"][2]), (mid_port..end_port))
212
+
213
+ # symlink
214
+ system("#{@options["symlink_cmd"]} #{File.expand_path(File.join(@http_config_path,@options["config_files"]["all"]))} #{File.join(@http_config_path,@options["config_symlink"])}")
215
+
216
+ log "Don't forget to include #{File.expand_path("#{@http_config_path}/cluster.conf")} in your webserver configuration."
217
+ end
218
+ end
219
+
220
+ INCLUDES = {}
221
+ INCLUDES['nginx'] = {}
222
+ INCLUDES['apache'] = {}
223
+ INCLUDES['nginx'][:template]=<<-TEMPLATE
224
+ upstream mongrel_pack {
225
+ <%= server_lines %>}
226
+ TEMPLATE
227
+ INCLUDES['nginx'][:server_line] = " server <%=ip%>:<%=port%>;\n"
228
+
229
+ INCLUDES['apache'][:template]=<<-TEMPLATE
230
+ <Proxy balancer://mongrel_pack>
231
+ <%= server_lines %></Proxy>
232
+ TEMPLATE
233
+ INCLUDES['apache'][:server_line] = " BalancerMember http://<%=ip%>:<%=port%>;\n"
234
+
235
+ end
236
+
@@ -287,7 +287,7 @@ module Seesaw
287
287
 
288
288
  end
289
289
 
290
- class Configure < GemPlugin::Plugin "/commands"
290
+ class ConfigureMongrels < GemPlugin::Plugin "/commands"
291
291
  include ExecBase
292
292
 
293
293
  def configure
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: seesaw
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2007-08-18 00:00:00 +10:00
6
+ version: 0.2.0
7
+ date: 2007-08-19 00:00:00 +10:00
8
8
  summary: Ripple-restart a mongrel cluster with no downtime
9
9
  require_paths:
10
10
  - lib