seesaw 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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