sunshine 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/History.txt +22 -2
  2. data/Manifest.txt +7 -0
  3. data/README.txt +333 -57
  4. data/Rakefile +1 -1
  5. data/lib/commands/add.rb +2 -2
  6. data/lib/commands/default.rb +15 -8
  7. data/lib/commands/list.rb +5 -3
  8. data/lib/commands/restart.rb +2 -2
  9. data/lib/commands/rm.rb +2 -2
  10. data/lib/commands/run.rb +2 -2
  11. data/lib/commands/start.rb +2 -2
  12. data/lib/commands/stop.rb +2 -2
  13. data/lib/sunshine.rb +117 -132
  14. data/lib/sunshine/app.rb +116 -10
  15. data/lib/sunshine/crontab.rb +11 -2
  16. data/lib/sunshine/daemon.rb +60 -46
  17. data/lib/sunshine/daemons/apache.rb +10 -2
  18. data/lib/sunshine/daemons/ar_sendmail.rb +0 -6
  19. data/lib/sunshine/daemons/delayed_job.rb +2 -0
  20. data/lib/sunshine/daemons/mongrel_rails.rb +32 -0
  21. data/lib/sunshine/daemons/nginx.rb +3 -0
  22. data/lib/sunshine/daemons/rainbows.rb +2 -0
  23. data/lib/sunshine/daemons/server.rb +51 -24
  24. data/lib/sunshine/daemons/server_cluster.rb +47 -0
  25. data/lib/sunshine/daemons/thin.rb +36 -0
  26. data/lib/sunshine/daemons/unicorn.rb +4 -1
  27. data/lib/sunshine/dependencies.rb +10 -3
  28. data/lib/sunshine/healthcheck.rb +2 -2
  29. data/lib/sunshine/remote_shell.rb +11 -2
  30. data/lib/sunshine/repo.rb +1 -1
  31. data/lib/sunshine/repos/rsync_repo.rb +1 -0
  32. data/templates/apache/apache.conf.erb +25 -18
  33. data/templates/mongrel_rails/mongrel_rails.conf.erb +9 -0
  34. data/templates/nginx/nginx.conf.erb +12 -9
  35. data/templates/thin/thin.conf.erb +12 -0
  36. data/test/helper_methods.rb +161 -0
  37. data/test/unit/test_daemon.rb +1 -8
  38. data/test/unit/test_nginx.rb +1 -1
  39. data/test/unit/test_server.rb +16 -0
  40. data/test/unit/test_server_cluster.rb +46 -0
  41. data/test/unit/test_sunshine.rb +18 -12
  42. metadata +14 -11
data/History.txt CHANGED
@@ -1,6 +1,26 @@
1
- === 1.0.3 / 2010
1
+ === 1.1.0 / 2010-04-02
2
2
 
3
- * Improvements:
3
+ * Improvements:
4
+
5
+ * Support for server clustering with the ServerCluster class.
6
+
7
+ * Added Daemon#status method.
8
+
9
+ * Added the -R option for loading external libraries and gems.
10
+
11
+ * Added support for Thin and MongrelRails.
12
+
13
+ * Added Server support for max connections configuration.
14
+
15
+ * Bugfixes:
16
+
17
+ * Daemons no longer create control scripts if they aren't used.
18
+
19
+ * Fixed Rsync repo to auto append "/" to urls for correct rsyncing.
20
+
21
+ === 1.0.3 / 2010-03-26
22
+
23
+ * Improvements:
4
24
 
5
25
  * Added App#call method.
6
26
 
data/Manifest.txt CHANGED
@@ -22,9 +22,12 @@ lib/sunshine/daemon.rb
22
22
  lib/sunshine/daemons/apache.rb
23
23
  lib/sunshine/daemons/ar_sendmail.rb
24
24
  lib/sunshine/daemons/delayed_job.rb
25
+ lib/sunshine/daemons/mongrel_rails.rb
25
26
  lib/sunshine/daemons/nginx.rb
26
27
  lib/sunshine/daemons/rainbows.rb
27
28
  lib/sunshine/daemons/server.rb
29
+ lib/sunshine/daemons/server_cluster.rb
30
+ lib/sunshine/daemons/thin.rb
28
31
  lib/sunshine/daemons/unicorn.rb
29
32
  lib/sunshine/dependencies.rb
30
33
  lib/sunshine/dependency_lib.rb
@@ -44,15 +47,18 @@ lib/sunshine/server_app.rb
44
47
  lib/sunshine/shell.rb
45
48
  templates/apache/apache.conf.erb
46
49
  templates/logrotate/logrotate.conf.erb
50
+ templates/mongrel_rails/mongrel_rails.conf.erb
47
51
  templates/nginx/nginx.conf.erb
48
52
  templates/nginx/nginx_optimize.conf
49
53
  templates/nginx/nginx_proxy.conf
50
54
  templates/rainbows/rainbows.conf.erb
51
55
  templates/sunshine/middleware/health.rb
52
56
  templates/sunshine/sunshine.rake
57
+ templates/thin/thin.conf.erb
53
58
  templates/unicorn/unicorn.conf.erb
54
59
  test/fixtures/app_configs/test_app.yml
55
60
  test/fixtures/sunshine_test/test_upload
61
+ test/helper_methods.rb
56
62
  test/mocks/mock_object.rb
57
63
  test/mocks/mock_open4.rb
58
64
  test/test_helper.rb
@@ -68,6 +74,7 @@ test/unit/test_remote_shell.rb
68
74
  test/unit/test_repo.rb
69
75
  test/unit/test_server.rb
70
76
  test/unit/test_server_app.rb
77
+ test/unit/test_server_cluster.rb
71
78
  test/unit/test_shell.rb
72
79
  test/unit/test_sunshine.rb
73
80
  test/unit/test_svn_repo.rb
data/README.txt CHANGED
@@ -1,34 +1,122 @@
1
1
  = Sunshine
2
2
 
3
+ http://github.com/yaksnrainbows/sunshine
4
+
3
5
  http://betalabs.yellowpages.com/
4
6
 
5
- == Description
6
7
 
7
- Sunshine is an object-oriented api for rack application deployment.
8
+ == Description
8
9
 
9
- Sunshine is open and it can do a lot! It's meant to be dug into and understood.
10
- Knowing how it works will let you do really neat things: classes are
11
- decoupled as much as possible to allow for optimal flexibility,
12
- and most can be used independently.
10
+ Sunshine is a framework for rack and rails application deployment.
13
11
 
14
12
  This gem was made possible by the sponsoring of AT&T Interactive
15
13
  (http://attinteractive.com).
16
14
 
17
- == Setup
15
+
16
+ == Setup and Usage
18
17
 
19
18
  Installing sunshine:
20
19
 
21
20
  gem install sunshine
22
21
 
23
- You can either use sunshine by requiring the gem in your script or
24
- by calling the sunshine command:
22
+ You can either use sunshine by requiring the gem in your script, such as
23
+ in a rakefile (which is more common):
24
+
25
+ rake sunshine:deploy
26
+
27
+ Or you can also call built-in sunshine commands:
25
28
 
26
29
  sunshine run my_deploy.rb -e qa
27
30
 
28
31
 
29
- == Deploy Scripts
32
+ == Rake Deploy Tasks in 5 Minutes
33
+
34
+ Although Sunshine comes with it's own bundle of commands, they should be used
35
+ to control deployed apps on remote servers in instances where deploy information
36
+ (e.g. your deploy yaml file) is unavailable. Their purpose is to query a server
37
+ where Sunshine apps have been deployed and have a nominal amount of information
38
+ and control over them. Sunshine control commands are run on a per-server basis.
39
+
40
+ Most of the time, you'll want to control the deploy on a per-app basis.
41
+ You have the deploy information and you need to do things involving that
42
+ specific deploy. Rake tasks are great for that, and Sunshine comes with a
43
+ template rake file that you can modify to fit your needs.
44
+
45
+ You can copy the template rake file to lib/tasks/ by running:
46
+ sunshine --rakefile lib/tasks/.
30
47
 
31
- Writing a Sunshine script is easy:
48
+ If you open the file, you'll see a variety of tasks that handle deployment, to
49
+ application start/stop/restart-ing, to health checks. Most likely, the two tasks
50
+ you'll need to update are the :app (for instantiation) and the :deploy tasks.
51
+
52
+ First off, if you're using rails, you'll probably want to update "task :app" to
53
+ "task :app => :environment" in order to get all the rails environment goodness.
54
+ You'll also want to make sure that the @app object gets instantiated with the
55
+ proper hash value or yaml file.
56
+
57
+ Second, you need to update your :deploy task. Add whatever instructions you need
58
+ to the @app.deploy block. Here's a sample of completed :app and :deploy tasks:
59
+
60
+ namespace :sunshine do
61
+
62
+ desc "Instantiate Sunshine"
63
+ task :app => :environment do
64
+ Sunshine.setup 'sudo' => 'app_user',
65
+ 'web_directory' => '/var/www',
66
+ 'deploy_env' => Rails.environment
67
+
68
+ @app = Sunshine::App.new \
69
+ :repo => Sunshine::SvnRepo.new("svn://subversion/repo/tags/release001"),
70
+ :remote_shells => 'user@my_server.com'
71
+ end
72
+
73
+
74
+ desc "Deploy the app"
75
+ task :deploy => :app do
76
+ Sunshine.setup 'trace' => true
77
+
78
+ @app.deploy do |app|
79
+
80
+ rainbows = Sunshine::Rainbows.new app, :port => 5001
81
+
82
+ nginx = Sunshine::Nginx.new app, :point_to => rainbows
83
+
84
+ app.run_geminstaller
85
+
86
+ rainbows.setup
87
+ nginx.setup
88
+ end
89
+
90
+ @app.start :force => true
91
+ end
92
+
93
+ ...
94
+ end
95
+
96
+ And that's it! Try running your Sunshine rake tasks!
97
+
98
+ rake sunshine:app # Instantiate Sunshine
99
+ rake sunshine:db_migrate # Run db:migrate on remote :db servers
100
+ rake sunshine:deploy # Deploy the app
101
+ rake sunshine:health # Get the health state
102
+ rake sunshine:health:disable # Turn off health check
103
+ rake sunshine:health:enable # Turn on health check
104
+ rake sunshine:health:remove # Remove health check
105
+ rake sunshine:info # Get deployed app info
106
+ rake sunshine:restart # Run the remote restart script
107
+ rake sunshine:start # Run the remote start script
108
+ rake sunshine:status # Check if the deployed app is running
109
+ rake sunshine:stop # Run the remote stop script
110
+
111
+
112
+ == Understanding Deployment
113
+
114
+ === The App Class
115
+
116
+ Writing a Sunshine script is easy.
117
+ App objects are the core of Sunshine deployment. The Sunshine paradygm
118
+ is to construct an app object, and run custom deploy code by passing
119
+ a block to its deploy method:
32
120
 
33
121
  options = {
34
122
  :name => 'myapp',
@@ -36,12 +124,13 @@ Writing a Sunshine script is easy:
36
124
  :root_path => '/usr/local/myapp'
37
125
  }
38
126
 
39
- options[:remote_shells] = case Sunshine.deploy_env
40
- when 'qa'
41
- ['qa1.svr.com', 'qa2.svr.com']
42
- else
43
- 'localhost'
44
- end
127
+ options[:remote_shells] =
128
+ case Sunshine.deploy_env
129
+ when 'qa'
130
+ ['qa1.svr.com', 'qa2.svr.com']
131
+ else
132
+ 'localhost'
133
+ end
45
134
 
46
135
  Sunshine::App.deploy(options) do |app|
47
136
 
@@ -52,15 +141,32 @@ Writing a Sunshine script is easy:
52
141
 
53
142
  end
54
143
 
144
+ An App holds information about where to deploy an application to and
145
+ how to deploy it, as well as many convenience methods to setup and
146
+ manipulate the deployment process. Most of these methods support passing
147
+ remote shell find options:
148
+
149
+ app.rake 'db:migrate', :role => :db
150
+ app.deploy :host => 'server1.com'
151
+
152
+ See Sunshine::App#find for more information.
55
153
 
56
- The App::deploy and App::new methods also support passing
57
- a path to a yaml file:
154
+
155
+ === Working With Environments
156
+
157
+ Environment specific setups can be accomplished in a few ways. The most
158
+ obvious way is to create a different script for each environment. You can
159
+ also define the App's constructor hash on a per-environment basis
160
+ (as seen above), which gives you lots of control.
161
+ That said, the App class also provides a mechanism for environment handling
162
+ using configuration files.
163
+ The App::new methods support passing a path to a yaml config file:
58
164
 
59
165
  app = Sunshine::App.new("path/to/config.yml")
60
166
  app.deploy{|app| Sunshine::Rainbows.new(app).restart }
61
167
 
62
168
 
63
- The yaml file can also be any IO stream whos output will parse to yaml.
169
+ The yaml file can also be any IO stream who's output will parse to yaml.
64
170
  This can be ueful for passing the file's DATA and keep all the deploy
65
171
  information in one place:
66
172
 
@@ -109,51 +215,74 @@ Yaml files are read on a deploy-environment basis so its format reflects this:
109
215
 
110
216
  In this example, :prod inherits top level values from :qa (only :repo in this
111
217
  instance). The :inherits key also supports an array as its value.
218
+ All environments also inherit from the :default environment. The :default is
219
+ also used if the app's deploy_env is not found in the config.
220
+ See Sunshine::App for more information.
112
221
 
113
222
 
114
- == Using rake is great!
223
+ == Servers
115
224
 
116
- Although Sunshine comes with it's own bundle of commands, they should be used
117
- to control deployed apps on remote servers in instances where deploy information
118
- (e.g. your deploy yaml file) is unavailable. Their purpose is to query a server
119
- where Sunshine apps have been deployed and have a nominal amount of information
120
- and control over them. Sunshine control commands are run on a per-server basis.
225
+ === Basics
121
226
 
122
- Most of the time though, you'll want to control the deploy on a per-app basis.
123
- You have the deploy information and you need to do things involving that
124
- specific deploy. Rake tasks are great for that, and Sunshine comes with a
125
- template rake file that you can modify to fit your needs.
227
+ Sunshine lets you install and setup server applications to run your app on.
228
+ The typical approach to serving ruby applications is to run Nginx or Apache
229
+ as a load balancer in front of a backend such as Thin, or Mongrels.
230
+ Using Sunshine, this is most commonly defined as a part of the deploy process:
126
231
 
127
- You can copy the template rake file to lib/tasks/ by running:
128
- sunshine --rakefile lib/tasks/.
232
+ app.deploy do |app|
233
+ backend = Sunshine::Thin.new app, :port => 5000
234
+ nginx = Sunshine::Nginx.new app, :point_to => backend
129
235
 
130
- If you open the file, you'll see a variety of tasks that handle deployment, to
131
- application start/stop/restart-ing, to health checks. Most likely, the two tasks
132
- you'll need to update are the :app (for instantiation) and the :deploy tasks.
236
+ backend.setup
237
+ nginx.setup
238
+ end
133
239
 
134
- First off, if you're using rails, you'll probably want to update "task :app" to
135
- "task :app => :environment" in order to get all the rails environment goodness.
136
- You'll also want to make sure that the @app object gets instantiated with the
137
- proper hash value or yaml file.
240
+ app.start :force => true
138
241
 
139
- Second, you need to update your :deploy task. Add whatever instructions you need
140
- to the @app.deploy block.
242
+ When a new Server is instantiated and its setup method is run, it is added to
243
+ the app's control scripts. This means that when the deploy is complete, those
244
+ servers can be controlled by the app's start/stop/restart/status methods.
141
245
 
142
- And that's it! Try running your Sunshine rake tasks!
143
246
 
144
- rake sunshine:app # Instantiate Sunshine
145
- rake sunshine:db_migrate # Run db:migrate on remote :db servers
146
- rake sunshine:deploy # Deploy the app
147
- rake sunshine:health # Get the health state
148
- rake sunshine:health:disable # Turn off health check
149
- rake sunshine:health:enable # Turn on health check
150
- rake sunshine:health:remove # Remove health check
151
- rake sunshine:info # Get deployed app info
152
- rake sunshine:restart # Run the remote restart script
153
- rake sunshine:start # Run the remote start script
154
- rake sunshine:status # Check if the deployed app is running
155
- rake sunshine:stop # Run the remote stop script
156
-
247
+ === Load Balancing
248
+
249
+ Since frontend servers support load balancing, you can also point them to
250
+ server clusters:
251
+
252
+ backend = Sunshine::Thin.new_cluster 10, app, :port => 5000
253
+ nginx = Sunshine::Nginx.new app, :point_to => backend
254
+
255
+ backend.setup
256
+ nginx.setup
257
+
258
+ In this instance, Nginx will know to forward requests to the cluster of Thin
259
+ servers created. You could do this more explicitely with the following:
260
+
261
+ backend = Array.new
262
+
263
+ 5000.upto(5009) do |port|
264
+ thin = Sunshine::Thin.new app, :port => port, :name => "thin.#{port}"
265
+ thin.setup
266
+
267
+ backend << thin
268
+ end
269
+
270
+ Sunshine::Nginx.new app, :point_to => backend
271
+
272
+
273
+ === Phusion Passenger
274
+
275
+ If you are running a lower traffic application, Phusion Passenger is available
276
+ for both Nginx and Apache. Passenger will be used by default if no backend
277
+ is specified. You could have an Nginx Passenger setup on port 80 with a
278
+ single line:
279
+
280
+ Sunshine::Nginx.new(app).setup
281
+
282
+ Easy!
283
+
284
+ Servers let you do much more configuration with log files, config files, etc.
285
+ For more information, see Sunshine::Server.
157
286
 
158
287
 
159
288
  == Dependencies
@@ -191,6 +320,7 @@ with Sunshine:
191
320
  Warning: If the :call options isn't specified, the dependency will attempt to
192
321
  install on the local system.
193
322
 
323
+ See Sunshine::Dependency for more information.
194
324
 
195
325
  === Internal Sunshine Dependencies (advanced)
196
326
 
@@ -224,6 +354,151 @@ server_apps use the same dependency definition, you may consider:
224
354
  Sunshine.dependencies.apt 'rubygems', :version => '1.3.2'
225
355
  # ... and so on
226
356
 
357
+ Note: You can disable automatic dependency installation by setting Sunshine's
358
+ auto_dependencies config to false.
359
+
360
+
361
+ == Using Permissions
362
+
363
+ In order to deploy applications successfully, it's important to know how,
364
+ where, and when to use permissions in Sunshine deploy scripts.
365
+
366
+ === The Shell Class
367
+
368
+ The primary handler of permissions is the Sunshine::Shell class. Since all
369
+ commands are run through a Shell object, it naturally handles permission
370
+ changes. The following will create a new remote shell which is logged into
371
+ as user "bob" but will use root to perform all calls:
372
+
373
+ # The following two lines are equivalent:
374
+ svr = Sunshine::RemoteShell.new "bob@myserver.com", :sudo => true
375
+ svr = Sunshine::RemoteShell.new "myserver.com", :user => "bob" :sudo => true
376
+
377
+ Sudo can also be set after instantiation. Let's change the permissions back to
378
+ its default:
379
+
380
+ svr.sudo = nil
381
+
382
+ You can of course also run single commands with a one-off sudo setting:
383
+
384
+ svr.call "whoami", :sudo => true
385
+ #=> "root"
386
+
387
+ Shell sudo values are important! Depending on what the value of shell.sudo is,
388
+ behavior will change dramatically:
389
+
390
+ - sudo = true -> sudo -H command
391
+ - sudo = 'root' -> sudo -H -u root command
392
+ - sudo = 'usr' -> sudo -H -u usr command
393
+ - sudo = false -> enforce never using sudo
394
+ - sudo = nil -> passthrough (don't care)
395
+
396
+ Here are a few examples of these values being used:
397
+
398
+ svr = Sunshine::RemoteShell.new "bob@myserver.com", :sudo => true
399
+
400
+ svr.call "whoami" #=> root
401
+ svr.call "whoami", :sudo => "usr" #=> usr
402
+ svr.call "whoami", :sudo => nil #=> root
403
+ svr.call "whoami", :sudo => false #=> bob
404
+
405
+
406
+ These values are crucial as other Sunshine classes have and pass around other
407
+ sudo requirements/values to shell objects.
408
+
409
+
410
+ === Who Affects Sudo
411
+
412
+ There are 3 main places to beware of how sudo gets used.
413
+
414
+ ==== Apps
415
+
416
+ The first, most obvious place is the App class:
417
+
418
+ app.sudo = "bob"
419
+ app.server_apps.first.shell.sudo #=> "bob"
420
+
421
+ app.sudo = true
422
+ app.server_apps.first.shell.sudo #=> true
423
+
424
+ Since the App class effectively owns the shells it uses, setting sudo on the
425
+ App will permanently change the sudo value of its shells.
426
+
427
+ Note: You may notice that you can set a sudo config value on the Sunshine
428
+ module. This is used for the default value of Sunshine::App#sudo and is passed
429
+ along to an app's shells on instantiation.
430
+
431
+
432
+ ==== Dependencies
433
+
434
+ Since Sunshine also deals with installing dependencies, the Dependency class
435
+ and its children all have a class level sudo setting which is set to true
436
+ by default. This means that any dependency will by default run its commands
437
+ using sudo:
438
+
439
+ dep = Sunshine::Apt.new "libdvdread"
440
+ dep.install! :call => shell
441
+
442
+ #=> sudo -H apt-get install libdvdread
443
+
444
+ This can be changed on the class level:
445
+
446
+ shell.sudo = "usr"
447
+
448
+ Sunshine::Apt.sudo = nil # let the shell handle sudo
449
+ dep.install! :call => shell
450
+
451
+ #=> sudo -H -u usr apt-get install libdvdread
452
+
453
+ It can also be set on an individual basis:
454
+
455
+ dep.install! :call => shell, :sudo => nil
456
+
457
+
458
+ ==== Servers
459
+
460
+ Because of how unix works with servers and ports, it's not uncommon to have to
461
+ run start/stop/restart server commands with upgraded permissions. This is true
462
+ for Apache and Nginx on ports below 1024. Due to this, servers automatically try
463
+ to adjust their permissions to run their commands correctly. Since servers
464
+ should run their commands consistantly, the only way to affect their sudo value
465
+ is on a server instance basis:
466
+
467
+ server = Nginx.new app, :sudo => nil # let the shell handle sudo
468
+
469
+ However, the above will most likely cause Nginx's start command to fail if
470
+ shell permissions don't allow running root processes.
471
+
472
+ Note: Servers will ONLY touch permissions if their port is smaller than 1024.
473
+
474
+
475
+ == Sunshine Configuration
476
+
477
+ Aside from passing the sunshine command options, Sunshine can be configured
478
+ both in the deploy script by calling Sunshine.setup and globally in the
479
+ ~/.sunshine file. The following is a list of supported config keys:
480
+
481
+ 'auto' -> Automate calls; fail instead of prompting the user;
482
+ defaults to false.
483
+
484
+ 'auto_dependencies' -> Check and install missing deploy dependencies;
485
+ defaults to true.
486
+
487
+ 'deploy_env' -> The default deploy environment to use;
488
+ defaults to :development.
489
+
490
+ 'level' -> Logger's debug level; defaults to 'info'.
491
+
492
+ 'max_deploy_versions' -> The maximum number of deploys to keep on a server;
493
+ defaults to 5.
494
+
495
+ 'require' -> Require external ruby libs or gems; defaults to nil.
496
+
497
+ 'trace' -> Show detailed output messages; defaults to false.
498
+
499
+ 'web_directory' -> Path to where apps should be deployed to;
500
+ defaults to '/var/www'.
501
+
227
502
 
228
503
  == Deployed Application Control
229
504
 
@@ -251,11 +526,12 @@ For more help on sunshine commands, use 'sunshine COMMAND --help'.
251
526
  For more information about control scripts, see the
252
527
  Sunshine::App#build_control_scripts method.
253
528
 
254
- == LICENSE:
529
+
530
+ == Licence
255
531
 
256
532
  (The MIT License)
257
533
 
258
- Copyright (c) 2010 FIX
534
+ Copyright (c) 2010
259
535
 
260
536
  Permission is hereby granted, free of charge, to any person obtaining
261
537
  a copy of this software and associated documentation files (the