Module: Sunshine

Defined in:
lib/sunshine.rb,
lib/commands/rm.rb,
lib/commands/add.rb,
lib/commands/run.rb,
lib/sunshine/app.rb,
lib/commands/list.rb,
lib/commands/stop.rb,
lib/sunshine/repo.rb,
lib/commands/start.rb,
lib/sunshine/shell.rb,
lib/sunshine/binder.rb,
lib/sunshine/daemon.rb,
lib/sunshine/output.rb,
lib/commands/default.rb,
lib/commands/restart.rb,
lib/sunshine/crontab.rb,
lib/sunshine/exceptions.rb,
lib/sunshine/server_app.rb,
lib/sunshine/healthcheck.rb,
lib/sunshine/remote_shell.rb,
lib/sunshine/daemons/nginx.rb,
lib/sunshine/daemons/apache.rb,
lib/sunshine/daemons/server.rb,
lib/sunshine/dependency_lib.rb,
lib/sunshine/repos/git_repo.rb,
lib/sunshine/repos/svn_repo.rb,
lib/sunshine/daemons/unicorn.rb,
lib/sunshine/daemons/rainbows.rb,
lib/sunshine/repos/rsync_repo.rb,
lib/sunshine/daemons/ar_sendmail.rb,
lib/sunshine/daemons/delayed_job.rb,
lib/sunshine/package_managers/apt.rb,
lib/sunshine/package_managers/gem.rb,
lib/sunshine/package_managers/yum.rb,
lib/sunshine/package_managers/dependency.rb

Overview

Sunshine is an object oriented deploy tool for rack applications.

Writing a Sunshine config script is easy:

options = {
  :name => 'myapp',
  :repo => {:type => :svn, :url => 'svn://blah...'},
  :deploy_path => '/usr/local/myapp',
  :remote_shells => ['[email protected]']
}

Sunshine::App.deploy(options) do |app|

  app.yum_install 'sqlite'
  app.gem_install 'sqlite3-ruby'

  app.rake "db:migrate"

  app_server = Sunshine::Rainbows.new(app)
  app_server.restart

  Sunshine::Nginx.new(app, :point_to => app_server).restart

end

The App::deploy and App::new methods also support passing a path to a yaml file:

app = Sunshine::App.new("path/to/config.yml")
app.deploy{|app| Sunshine::Rainbows.new(app).restart }

Command line execution:

Usage:
  sunshine -h/--help
  sunshine -v/--version
  sunshine command [arguments...] [options...]

Examples:
  sunshine run deploy_script.rb
  sunshine restart myapp -r [email protected],[email protected]
  sunshine list myapp myotherapp --health -r [email protected]
  sunshine list myapp --status

Commands:
  add       Register an app with sunshine
  list      Display deployed apps
  restart   Restart a deployed app
  rm        Unregister an app with sunshine
  run       Run a Sunshine script
  start     Start a deployed app
  stop      Stop a deployed app

 For more help on sunshine commands, use 'sunshine COMMAND --help'

Defined Under Namespace

Classes: ARSendmail, AddCommand, Apache, App, Apt, Binder, CmdError, CriticalDeployError, Crontab, Daemon, DefaultCommand, DelayedJob, Dependency, DependencyError, DependencyLib, DeployError, Exception, FatalDeployError, Gem, GitRepo, Healthcheck, ListCommand, Nginx, Output, Rainbows, RemoteShell, Repo, RepoError, RestartCommand, RmCommand, RsyncRepo, RunCommand, SSHCmdError, Server, ServerApp, Shell, StartCommand, StopCommand, SvnRepo, Unicorn, Yum

Constant Summary collapse

VERSION =

Sunshine version.

'1.0.2'
APP_LIST_PATH =

Path to the list of installed sunshine apps.

"~/.sunshine_list"
READ_LIST_CMD =
"test -f #{Sunshine::APP_LIST_PATH} && "+
"cat #{APP_LIST_PATH} || echo ''"
COMMANDS =

Commands supported by Sunshine

%w{add list restart rm run start stop}
USER_CONFIG_FILE =

Default Sunshine config file

File.expand_path("~/.sunshine")
DEFAULT_CONFIG =

Default configuration

{
  'level'               => 'info',
  'deploy_env'          => :development,
  'auto'                => false,
  'max_deploy_versions' => 5,
  'web_directory'       => '/var/www',
  'auto_dependencies'   => true
}
TMP_DIR =

Temp directory used by various sunshine classes for uploads, checkouts, etc…

File.join Dir.tmpdir, "sunshine_#{$$}"
PATH =

Path where sunshine assumes repo information can be found if missing.

Dir.getwd
DATA =

File DATA from sunshine run files.

defined?(::DATA) ? ::DATA : nil
ROOT =

Root directory of the Sunshine gem.

File.expand_path File.join(File.dirname(__FILE__), "..")

Class Method Summary collapse

Class Method Details

.add_trap(desc, &block) ⇒ Object

Adds an INT signal trap with its description on the stack. Returns a trap_item Array.



164
165
166
167
168
# File 'lib/sunshine.rb', line 164

def self.add_trap desc, &block
  trap_item = [desc, block]
  (@trap_stack ||= []).unshift trap_item
  trap_item
end

.auto_dependencies?Boolean

Automatically install dependencies as needed. Defaults to true. Overridden in the ~/.sunshine config file or at setup time.

Returns:

  • (Boolean)


100
101
102
# File 'lib/sunshine.rb', line 100

def self.auto_dependencies?
  @config['auto_dependencies']
end

.call_trap(trap_item) ⇒ Object

Call a trap item and display it’s message.



178
179
180
181
182
183
184
185
186
# File 'lib/sunshine.rb', line 178

def self.call_trap trap_item
  return unless trap_item

  msg, block = trap_item

  logger.info :INT, msg do
    block.call
  end
end

.cleanupObject

Cleanup after sunshine has run, remove temp dirs, etc…



264
265
266
# File 'lib/sunshine.rb', line 264

def self.cleanup
  FileUtils.rm_rf TMP_DIR if Dir.glob("#{TMP_DIR}/*").empty?
end

.delete_trap(trap_item) ⇒ Object

Remove a trap_item from the stack.



192
193
194
# File 'lib/sunshine.rb', line 192

def self.delete_trap trap_item
  @trap_stack.delete trap_item
end

.dependenciesObject

Returns the main Sunshine dependencies library.



107
108
109
# File 'lib/sunshine.rb', line 107

def self.dependencies
  @dependency_lib ||= DependencyLib.new
end

.deploy_envObject

The default deploy environment to use. Set with the -e option. See App#deploy_env for app specific deploy environments.



91
92
93
# File 'lib/sunshine.rb', line 91

def self.deploy_env
  @config['deploy_env'].to_s
end

.exit(status, msg = nil) ⇒ Object

Exits sunshine process and returns the appropriate exit code

exit 0, "ok"
exit false, "ok"
  # both output: stdout >> ok - exitcode 0
exit 1, "oh noes"
exit true, "oh noes"
  # both output: stderr >> oh noes - exitcode 1


333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/sunshine.rb', line 333

def self.exit status, msg=nil
  self.cleanup

  status = case status
  when true
    0
  when false
    1
  when Integer
    status
  else
    status.to_i
  end

  output = status == 0 ? $stdout : $stderr

  output << "#{msg}\n" if !msg.nil?

  Kernel.exit status
end

.find_command(name) ⇒ Object

Find the sunshine command to run based on the passed name. Handles partial command names if they can be uniquely mapped to a command.

find_command "dep" #=> "run"
find_command "zzz" #=> false


318
319
320
321
# File 'lib/sunshine.rb', line 318

def self.find_command name
  commands = COMMANDS.select{|c| c =~ /^#{name}/}
  commands.length == 1 && commands.first
end

.interactive?Boolean

Should sunshine ever ask for user input? True by default; overridden with the -a option.

Returns:

  • (Boolean)


126
127
128
# File 'lib/sunshine.rb', line 126

def self.interactive?
  !@config['auto']
end

.loggerObject

Handles all output for sunshine. See Sunshine::Output.



134
135
136
137
# File 'lib/sunshine.rb', line 134

def self.logger
  @logger ||= Sunshine::Output.new \
    :level => Logger.const_get(@config['level'].upcase)
end

.max_deploy_versionsObject

Maximum number of deploys (history) to keep on the remote server, 5 by default. Overridden in the ~/.sunshine config file.



144
145
146
# File 'lib/sunshine.rb', line 144

def self.max_deploy_versions
  @config['max_deploy_versions']
end

.run(argv = ARGV) ⇒ Object

Run sunshine with the passed argv and exits with appropriate exitcode.

run %w{run my_script.rb -l debug}
run %w{list -d}


285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/sunshine.rb', line 285

def self.run argv=ARGV
  unless File.file? USER_CONFIG_FILE
    File.open(USER_CONFIG_FILE, "w+"){|f| f.write DEFAULT_CONFIG.to_yaml}

    msg = "Missing config file was created for you: #{USER_CONFIG_FILE}\n\n"
    msg << DEFAULT_CONFIG.to_yaml

    self.exit 1, msg
  end

  command_name = find_command argv.first
  argv.shift if command_name
  command_name ||= "default"

  command = Sunshine.const_get("#{command_name.capitalize}Command")

  config = YAML.load_file USER_CONFIG_FILE
  config.merge! command.parse_args(argv)

  self.setup config, true

  result = command.exec argv, config

  self.exit(*result)
end

.setup(new_config = {}, reset = false) ⇒ Object

Setup sunshine with a custom config:

Sunshine.setup 'level' => 'debug', 'deploy_env' => :production


273
274
275
276
277
# File 'lib/sunshine.rb', line 273

def self.setup new_config={}, reset=false
  @config = DEFAULT_CONFIG.dup if !defined?(@config) || reset
  @config.merge! new_config
  @config
end

.shellObject

Handles input/output to the shell. See Sunshine::Shell.



83
84
85
# File 'lib/sunshine.rb', line 83

def self.shell
  @shell ||= Sunshine::Shell.new
end

.sudoObject

Global value of sudo to use. Returns true, nil, or a username. This value can be assigned by default in ~/.sunshine or with the –sudo [username] option. Defaults to nil.



212
213
214
# File 'lib/sunshine.rb', line 212

def self.sudo
  @config['sudo']
end

.trace?Boolean

Check if trace log should be output at all. This value can be assigned by default in ~/.sunshine or switched off with the run command’s –no-trace option. Defaults to true.

Returns:

  • (Boolean)


155
156
157
# File 'lib/sunshine.rb', line 155

def self.trace?
  @config['trace']
end

.web_directoryObject

The default directory where apps should be deployed to: ‘/var/www’ by default. Overridden in the ~/.sunshine config file or at setup time. See also App#deploy_path.



117
118
119
# File 'lib/sunshine.rb', line 117

def self.web_directory
  @config['web_directory']
end