ktheory-vlad 2.0.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.
@@ -0,0 +1,63 @@
1
+ # $GEM_HOME/gems/vlad-1.2.0/lib/vlad/thin.rb
2
+ # Thin tasks for Vlad the Deployer
3
+ # By cnantais
4
+ require 'vlad'
5
+
6
+ namespace :vlad do
7
+ ##
8
+ # Thin app server
9
+
10
+ set :thin_address, "127.0.0.1"
11
+ set :thin_command, 'thin'
12
+ set(:thin_conf) { "#{shared_path}/thin_cluster.conf" }
13
+ set :thin_environment, "production"
14
+ set :thin_group, nil
15
+ set :thin_log_file, nil
16
+ set :thin_pid_file, nil
17
+ set :thin_port, nil
18
+ set :thin_socket, "/tmp/thin.sock"
19
+ set :thin_prefix, nil
20
+ set :thin_servers, 2
21
+ set :thin_user, nil
22
+ set :thin_rackup, nil
23
+
24
+ desc "Prepares application servers for deployment. thin
25
+ configuration is set via the thin_* variables.".cleanup
26
+
27
+ remote_task :setup_app, :roles => :app do
28
+ cmd = [
29
+ "#{thin_command} config",
30
+ "-s #{thin_servers}",
31
+ "-S #{thin_socket}",
32
+ "-e #{thin_environment}",
33
+ "-c #{current_path}",
34
+ "-C #{thin_conf}",
35
+ ("-a #{thin_address}" if thin_address),
36
+ ("-R #{thin_rackup}" if thin_rackup),
37
+ ("-P #{thin_pid_file}" if thin_pid_file),
38
+ ("-l #{thin_log_file}" if thin_log_file),
39
+ ("--user #{thin_user}" if thin_user),
40
+ ("--group #{thin_group}" if thin_group),
41
+ ("--prefix #{thin_prefix}" if thin_prefix),
42
+ ("-p #{thin_port}" if thin_port),
43
+ ].compact.join ' '
44
+
45
+ run cmd
46
+ end
47
+
48
+ def thin(cmd) # :nodoc:
49
+ "#{thin_command} #{cmd} -C #{thin_conf}"
50
+ end
51
+
52
+ desc "Restart the app servers"
53
+
54
+ remote_task :start_app, :roles => :app do
55
+ run thin("restart -s #{thin_servers}")
56
+ end
57
+
58
+ desc "Stop the app servers"
59
+
60
+ remote_task :stop_app, :roles => :app do
61
+ run thin("stop -s #{thin_servers}")
62
+ end
63
+ end
@@ -0,0 +1,73 @@
1
+ require 'rubygems'
2
+ require 'minitest/autorun'
3
+ require 'stringio'
4
+ require 'vlad'
5
+
6
+ class StringIO
7
+ def readpartial(size) read end # suck!
8
+ end
9
+
10
+ module Process
11
+ def self.expected status
12
+ @@expected ||= []
13
+ @@expected << status
14
+ end
15
+
16
+ class << self
17
+ alias :waitpid2_old :waitpid2
18
+
19
+ def waitpid2(pid)
20
+ [ @@expected.shift ]
21
+ end
22
+ end
23
+ end
24
+
25
+ class Rake::RemoteTask
26
+ attr_accessor :commands, :action, :input, :output, :error
27
+
28
+ Status = Struct.new :exitstatus
29
+
30
+ class Status
31
+ def success?() exitstatus == 0 end
32
+ end
33
+
34
+ def system *command
35
+ @commands << command
36
+ self.action ? self.action[command.join(' ')] : true
37
+ end
38
+
39
+ def popen4 *command
40
+ @commands << command
41
+
42
+ @input = StringIO.new
43
+ out = StringIO.new @output.shift.to_s
44
+ err = StringIO.new @error.shift.to_s
45
+
46
+ raise if block_given?
47
+
48
+ status = self.action ? self.action[command.join(' ')] : 0
49
+ Process.expected Status.new(status)
50
+
51
+ return 42, @input, out, err
52
+ end
53
+
54
+ def select reads, writes, errs, timeout
55
+ [reads, writes, errs]
56
+ end
57
+
58
+ end
59
+
60
+ class VladTestCase < MiniTest::Unit::TestCase
61
+ def setup
62
+ @vlad = Rake::RemoteTask
63
+ @vlad.reset
64
+ Rake.application.clear
65
+ @task_count = Rake.application.tasks.size
66
+ @vlad.set :domain, "example.com"
67
+ end
68
+
69
+ def util_set_hosts
70
+ @vlad.host "app.example.com", :app
71
+ @vlad.host "db.example.com", :db
72
+ end
73
+ end
@@ -0,0 +1,279 @@
1
+ require 'vlad_test_case'
2
+ require 'vlad'
3
+
4
+ class TestRakeRemoteTask < VladTestCase
5
+ # TODO: move to minitest
6
+ def assert_silent
7
+ out, err = capture_io do
8
+ yield
9
+ end
10
+
11
+ assert_empty err
12
+ assert_empty out
13
+ end
14
+
15
+ def test_enhance
16
+ util_set_hosts
17
+ body = Proc.new { 5 }
18
+ task = @vlad.remote_task(:some_task => :foo, &body)
19
+ action = Rake::RemoteTask::Action.new(task, body)
20
+ assert_equal [action], task.remote_actions
21
+ assert_equal task, action.task
22
+ assert_equal ["foo"], task.prerequisites
23
+ end
24
+
25
+ def test_enhance_with_no_task_body
26
+ util_set_hosts
27
+ util_setup_task
28
+ assert_equal [], @task.remote_actions
29
+ assert_equal [], @task.prerequisites
30
+ end
31
+
32
+ def test_execute
33
+ util_set_hosts
34
+ set :some_variable, 1
35
+ set :can_set_nil, nil
36
+ set :lies_are, false
37
+ x = 5
38
+ task = @vlad.remote_task(:some_task) { x += some_variable }
39
+ task.execute nil
40
+ assert_equal 1, task.some_variable
41
+ assert_equal 7, x
42
+ assert task.can_set_nil.nil?
43
+ assert_equal false, task.lies_are
44
+ end
45
+
46
+ def test_set_false
47
+ set :can_set_nil, nil
48
+ set :lies_are, false
49
+
50
+ assert_equal nil, task.can_set_nil
51
+
52
+ assert_equal false, task.lies_are
53
+ assert_equal false, Rake::RemoteTask.fetch(:lies_are)
54
+ end
55
+
56
+
57
+ def test_fetch_false
58
+ assert_equal false, Rake::RemoteTask.fetch(:unknown, false)
59
+ end
60
+
61
+ def test_execute_exposes_target_host
62
+ host "app.example.com", :app
63
+ task = remote_task(:target_task) { set(:test_target_host, target_host) }
64
+ task.execute nil
65
+ assert_equal "app.example.com", Rake::RemoteTask.fetch(:test_target_host)
66
+ end
67
+
68
+ def test_execute_with_no_hosts
69
+ @vlad.host "app.example.com", :app
70
+ t = @vlad.remote_task(:flunk, :roles => :db) { flunk "should not have run" }
71
+ e = assert_raises(Vlad::ConfigurationError) { t.execute nil }
72
+ assert_equal "No target hosts specified on task flunk for roles [:db]",
73
+ e.message
74
+ end
75
+
76
+ def test_execute_with_no_roles
77
+ t = @vlad.remote_task(:flunk, :roles => :junk) { flunk "should not have run" }
78
+ e = assert_raises(Vlad::ConfigurationError) { t.execute nil }
79
+ assert_equal "No target hosts specified on task flunk for roles [:junk]",
80
+ e.message
81
+ end
82
+
83
+ def test_execute_with_roles
84
+ util_set_hosts
85
+ set :some_variable, 1
86
+ x = 5
87
+ task = @vlad.remote_task(:some_task, :roles => :db) { x += some_variable }
88
+ task.execute nil
89
+ assert_equal 1, task.some_variable
90
+ assert_equal 6, x
91
+ end
92
+
93
+ def test_rsync
94
+ util_setup_task
95
+ @task.target_host = "app.example.com"
96
+
97
+ assert_silent do
98
+ @task.rsync 'localfile', 'host:remotefile'
99
+ end
100
+
101
+ commands = @task.commands
102
+
103
+ assert_equal 1, commands.size, 'not enough commands'
104
+ assert_equal(%w[rsync -azP --delete localfile host:remotefile],
105
+ commands.first)
106
+ end
107
+
108
+ def test_rsync_fail
109
+ util_setup_task
110
+ @task.target_host = "app.example.com"
111
+ @task.action = lambda { false }
112
+
113
+ e = assert_raises Vlad::CommandFailedError do
114
+ assert_silent do
115
+ @task.rsync 'local', 'host:remote'
116
+ end
117
+ end
118
+ exp = "execution failed: rsync -azP --delete local host:remote"
119
+ assert_equal exp, e.message
120
+ end
121
+
122
+ def test_rsync_deprecation
123
+ util_setup_task
124
+ @task.target_host = "app.example.com"
125
+
126
+ out, err = capture_io do
127
+ @task.rsync 'localfile', 'remotefile'
128
+ end
129
+
130
+ commands = @task.commands
131
+
132
+ assert_equal 1, commands.size, 'not enough commands'
133
+ assert_equal(%w[rsync -azP --delete localfile app.example.com:remotefile],
134
+ commands.first)
135
+
136
+ assert_equal("rsync deprecation: pass target_host:remote_path explicitly\n",
137
+ err)
138
+ assert_empty out
139
+ # flunk "not yet"
140
+ end
141
+
142
+ def test_get
143
+ util_setup_task
144
+ @task.target_host = "app.example.com"
145
+
146
+ assert_silent do
147
+ @task.get 'tmp', "remote1", "remote2"
148
+ end
149
+
150
+ commands = @task.commands
151
+
152
+ expected = %w[rsync -azP --delete app.example.com:remote1 app.example.com:remote2 tmp]
153
+
154
+ assert_equal 1, commands.size
155
+ assert_equal expected, commands.first
156
+ end
157
+
158
+ def test_put
159
+ util_setup_task
160
+ @task.target_host = "app.example.com"
161
+
162
+ assert_silent do
163
+ @task.put 'dest' do
164
+ "whatever"
165
+ end
166
+ end
167
+
168
+ commands = @task.commands
169
+
170
+ expected = %w[rsync -azP --delete HAPPY app.example.com:dest]
171
+ commands.first[3] = 'HAPPY'
172
+
173
+ assert_equal 1, commands.size
174
+ assert_equal expected, commands.first
175
+ end
176
+
177
+ def test_run
178
+ util_setup_task
179
+ @task.output << "file1\nfile2\n"
180
+ @task.target_host = "app.example.com"
181
+ result = nil
182
+
183
+ out, err = capture_io do
184
+ result = @task.run("ls")
185
+ end
186
+
187
+ commands = @task.commands
188
+
189
+ assert_equal 1, commands.size, 'not enough commands'
190
+ assert_equal ["ssh", "app.example.com", "ls"],
191
+ commands.first, 'app'
192
+ assert_equal "file1\nfile2\n", result
193
+
194
+ assert_equal "file1\nfile2\n", out
195
+ assert_equal '', err
196
+ end
197
+
198
+ def test_run_failing_command
199
+ util_set_hosts
200
+ util_setup_task
201
+ @task.input = StringIO.new "file1\nfile2\n"
202
+ @task.target_host = 'app.example.com'
203
+ @task.action = lambda { 1 }
204
+
205
+ e = assert_raises(Vlad::CommandFailedError) { @task.run("ls") }
206
+ assert_equal "execution failed with status 1: ssh app.example.com ls", e.message
207
+
208
+ assert_equal 1, @task.commands.size
209
+ end
210
+
211
+ def test_run_with_prefix_output
212
+ util_setup_task
213
+ @task.output << "file1\nfile2\n"
214
+ @task.target_host = "app.example.com"
215
+ result = nil
216
+
217
+ set :prefix_output, true
218
+
219
+ out, err = capture_io do
220
+ result = @task.run("ls")
221
+ end
222
+
223
+ assert_equal "app.example.com: file1\napp.example.com: file2\n", result
224
+ assert_equal "app.example.com: file1\napp.example.com: file2\n", out
225
+ # Reset to false
226
+ set :prefix_output, false
227
+ end
228
+
229
+ def test_run_sudo
230
+ util_setup_task
231
+ @task.output << "file1\nfile2\n"
232
+ @task.error << 'Password:'
233
+ @task.target_host = "app.example.com"
234
+ def @task.sudo_password() "my password" end # gets defined by set
235
+ result = nil
236
+
237
+ out, err = capture_io do
238
+ result = @task.run("sudo ls")
239
+ end
240
+
241
+ commands = @task.commands
242
+
243
+ assert_equal 1, commands.size, 'not enough commands'
244
+ assert_equal ['ssh', 'app.example.com', 'sudo ls'],
245
+ commands.first
246
+
247
+ assert_equal "my password\n", @task.input.string
248
+
249
+ # WARN: Technically incorrect, the password line should be
250
+ # first... this is an artifact of changes to the IO code in run
251
+ # and the fact that we have a very simplistic (non-blocking)
252
+ # testing model.
253
+ assert_equal "file1\nfile2\nPassword:\n", result
254
+
255
+ assert_equal "file1\nfile2\n", out
256
+ assert_equal "Password:\n", err
257
+ end
258
+
259
+ def test_sudo
260
+ util_setup_task
261
+ @task.target_host = "app.example.com"
262
+ @task.sudo "ls"
263
+
264
+ commands = @task.commands
265
+
266
+ assert_equal 1, commands.size, 'wrong number of commands'
267
+ assert_equal ["ssh", "app.example.com", "sudo -p Password: ls"],
268
+ commands.first, 'app'
269
+ end
270
+
271
+ def util_setup_task(options = {})
272
+ @task = @vlad.remote_task :test_task, options
273
+ @task.commands = []
274
+ @task.output = []
275
+ @task.error = []
276
+ @task.action = nil
277
+ @task
278
+ end
279
+ end
@@ -0,0 +1,210 @@
1
+ require 'vlad_test_case'
2
+ require 'vlad'
3
+
4
+ $TESTING = true
5
+
6
+ class TestVlad < VladTestCase
7
+ def test_all_hosts
8
+ util_set_hosts
9
+ assert_equal %w[app.example.com db.example.com], @vlad.all_hosts
10
+ end
11
+
12
+ def test_fetch
13
+ set :foo, 5
14
+ assert_equal 5, @vlad.fetch(:foo)
15
+ end
16
+
17
+ def test_fetch_with_default
18
+ assert_equal 5, @vlad.fetch(:not_here, 5)
19
+ end
20
+
21
+ def test_host
22
+ @vlad.host "test.example.com", :app, :db
23
+ expected = {"test.example.com" => {}}
24
+ assert_equal expected, @vlad.roles[:app]
25
+ assert_equal expected, @vlad.roles[:db]
26
+ end
27
+
28
+ def test_host_invalid
29
+ assert_raises(ArgumentError) { @vlad.host nil, :web }
30
+ end
31
+
32
+ def test_host_multiple_hosts
33
+ @vlad.host "test.example.com", :app, :db
34
+ @vlad.host "yarr.example.com", :app, :db, :no_release => true
35
+
36
+ expected = {
37
+ "test.example.com" => {},
38
+ "yarr.example.com" => {:no_release => true}
39
+ }
40
+
41
+ assert_equal expected, @vlad.roles[:app]
42
+ assert_equal expected, @vlad.roles[:db]
43
+ refute_equal(@vlad.roles[:db]["test.example.com"].object_id,
44
+ @vlad.roles[:app]["test.example.com"].object_id)
45
+ end
46
+
47
+ def test_hosts_for_array_of_roles
48
+ util_set_hosts
49
+ assert_equal %w[app.example.com db.example.com], @vlad.hosts_for([:app, :db])
50
+ end
51
+
52
+ def test_hosts_for_one_role
53
+ util_set_hosts
54
+ @vlad.host "app2.example.com", :app
55
+ assert_equal %w[app.example.com app2.example.com], @vlad.hosts_for(:app)
56
+ end
57
+
58
+ def test_hosts_for_multiple_roles
59
+ util_set_hosts
60
+ assert_equal %w[app.example.com db.example.com], @vlad.hosts_for(:app, :db)
61
+ end
62
+
63
+ def test_hosts_for_unique
64
+ util_set_hosts
65
+ @vlad.host "app.example.com", :web
66
+ assert_equal %w[app.example.com db.example.com], @vlad.hosts_for(:app, :db, :web)
67
+ end
68
+
69
+ def test_initialize
70
+ @vlad.set_defaults # ensure these three are virginal
71
+ assert_raises(Vlad::ConfigurationError) { @vlad.repository }
72
+ assert_raises(Vlad::ConfigurationError) { @vlad.deploy_to }
73
+ assert_raises(Vlad::ConfigurationError) { @vlad.domain }
74
+ end
75
+
76
+ def test_role
77
+ @vlad.role :app, "test.example.com"
78
+ expected = {"test.example.com" => {}}
79
+ assert_equal expected, @vlad.roles[:app]
80
+ end
81
+
82
+ def test_role_multiple_hosts
83
+ @vlad.role :app, "test.example.com"
84
+ @vlad.role :app, "yarr.example.com", :no_release => true
85
+ expected = {
86
+ "test.example.com" => {},
87
+ "yarr.example.com" => {:no_release => true}
88
+ }
89
+ assert_equal expected, @vlad.roles[:app]
90
+ end
91
+
92
+ def test_role_multiple_roles
93
+ @vlad.role :app, "test.example.com", :primary => true
94
+ @vlad.role :db, "yarr.example.com", :no_release => true
95
+ expected_db = { "yarr.example.com" => {:no_release => true} }
96
+ assert_equal expected_db, @vlad.roles[:db]
97
+ expected_app = { "test.example.com" => {:primary => true} }
98
+ assert_equal expected_app, @vlad.roles[:app]
99
+ end
100
+
101
+ def test_remote_task
102
+ t = @vlad.remote_task(:test_task) { 5 }
103
+ assert_equal @task_count + 1, Rake.application.tasks.size
104
+ assert_equal({ :roles => [] }, t.options)
105
+ end
106
+
107
+ def test_remote_task_all_hosts_by_default
108
+ util_set_hosts
109
+ t = @vlad.remote_task(:test_task) { 5 }
110
+ assert_equal %w[app.example.com db.example.com], t.target_hosts
111
+ end
112
+
113
+ def test_remote_task_environment_override
114
+ old_env_hosts = ENV["HOSTS"]
115
+ ENV["HOSTS"] = 'other1.example.com, other2.example.com'
116
+ util_set_hosts
117
+ t = @vlad.remote_task(:test_task) { 5 }
118
+ assert_equal %w[other1.example.com other2.example.com], t.target_hosts
119
+ ensure
120
+ ENV["HOSTS"] = old_env_hosts
121
+ end
122
+
123
+ def test_remote_task_body_set
124
+ set(:some_variable, 5)
125
+ @vlad.host 'www.example.com', :app
126
+ @vlad.remote_task(:some_task) do $some_task_result = some_variable end
127
+
128
+ Rake::Task['some_task'].execute nil
129
+ assert_equal @vlad.fetch(:some_variable), $some_task_result
130
+ end
131
+
132
+ def test_remote_task_with_options
133
+ t = @vlad.remote_task :test_task, :roles => [:app, :db] do
134
+ fail "should not run"
135
+ end
136
+ assert_equal({:roles => [:app, :db]}, t.options)
137
+ end
138
+
139
+ def test_remote_task_before_host_declaration
140
+ t = @vlad.remote_task :test_task, :roles => :web do 5 end
141
+ @vlad.host 'www.example.com', :web
142
+ assert_equal %w[www.example.com], t.target_hosts
143
+ end
144
+
145
+ def test_remote_task_role_override
146
+ host "db1", :db
147
+ host "db2", :db
148
+ host "db3", :db
149
+ host "master", :master_db
150
+
151
+ remote_task(:migrate_the_db, :roles => [:db]) { flunk "bad!" }
152
+ task = Rake::Task["migrate_the_db"]
153
+ assert_equal %w[db1 db2 db3], task.target_hosts
154
+
155
+ task.options[:roles] = :master_db
156
+ assert_equal %w[master], task.target_hosts
157
+
158
+ task.options[:roles] = [:master_db]
159
+ assert_equal %w[master], task.target_hosts
160
+ end
161
+
162
+ def test_set
163
+ set :win, 5
164
+ assert_equal 5, @vlad.win
165
+ end
166
+
167
+ def test_set_lazy_block_evaluation
168
+ set(:lose) { raise "lose" }
169
+ assert_raises(RuntimeError) { @vlad.lose }
170
+ end
171
+
172
+ def test_set_with_block
173
+ x = 1
174
+ set(:win) { x += 2 }
175
+
176
+ assert_equal 3, @vlad.win
177
+ assert_equal 3, @vlad.win
178
+ end
179
+
180
+ def test_set_with_reference
181
+ @vlad.instance_eval do
182
+ set(:var_one) { var_two }
183
+ set(:var_two) { var_three }
184
+ set(:var_three) { 5 }
185
+ end
186
+
187
+ assert_equal 5, @vlad.var_one
188
+ end
189
+
190
+ def test_set_with_block_and_value
191
+ e = assert_raises(ArgumentError) do
192
+ set(:loser, 5) { 6 }
193
+ end
194
+ assert_equal "cannot provide both a value and a block", e.message
195
+ end
196
+
197
+ def test_set_with_nil
198
+ set(:win, nil)
199
+ assert_equal nil, @vlad.win
200
+ end
201
+
202
+ def test_set_with_reserved_name
203
+ $TESTING = false
204
+ e = assert_raises(ArgumentError) { set(:all_hosts, []) }
205
+ assert_equal "cannot set reserved name: 'all_hosts'", e.message
206
+ ensure
207
+ $TESTING = true
208
+ end
209
+ end
210
+