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/commands/script.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/trap_stack.rb,
lib/sunshine/daemons/thin.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/daemons/mongrel_rails.rb,
lib/sunshine/daemons/server_cluster.rb,
lib/sunshine/package_managers/dependency.rb

Overview

Main module, used for configuration and running commands.

Defined Under Namespace

Classes: ARSendmail, AddCommand, Apache, App, Apt, Binder, CmdError, ConnectionError, Crontab, Daemon, DaemonError, DefaultCommand, DelayedJob, Dependency, DependencyError, DependencyLib, DeployError, Exception, Gem, GitRepo, InstallError, ListCommand, MissingDependency, MongrelRails, Nginx, Output, Rainbows, RemoteShell, Repo, RepoError, RestartCommand, RmCommand, RsyncRepo, RunCommand, ScriptCommand, Server, ServerApp, ServerCluster, Shell, StartCommand, StopCommand, SvnRepo, Thin, TimeoutError, TrapStack, Unicorn, UninstallError, Yum

Constant Summary collapse

VERSION =

Sunshine version.

'1.2.5'
APP_LIST_PATH =

Path to the list of installed sunshine apps.

"~/.sunshine_list"
COMMANDS =

Commands supported by Sunshine.

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

File DATA from Sunshine run files.

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

Default configuration.

{
  'auto_dependencies'   => true,
  'deploy_env'          => :development,
  'exception_behavior'  => :revert,
  'exclude_paths'       => [],
  'interactive'         => true,
  'level'               => 'info',
  'max_deploy_versions' => 5,
  'remote_checkouts'    => false,
  'threads_enabled'     => true,
  'timeout'             => 300,
  'sigint_behavior'     => :revert,
  'web_directory'       => '/srv/http'
}
PATH =

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

Dir.getwd
ROOT =

Root directory of the Sunshine gem.

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

Default Sunshine config file

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

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

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

Class Method Summary collapse

Class Method Details

.auto_dependencies?Boolean

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

Returns:

  • (Boolean)


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

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

.cleanupObject

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



254
255
256
# File 'lib/sunshine.rb', line 254

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

.configObject

Returns the Sunshine config hash.



81
82
83
# File 'lib/sunshine.rb', line 81

def self.config
  @config ||= DEFAULT_CONFIG.dup
end

.create_default_config!Object



285
286
287
288
289
290
291
292
293
294
# File 'lib/sunshine.rb', line 285

def self.create_default_config!
  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
end

.dependencies(&block) ⇒ Object

Returns the main Sunshine dependencies library. If passed a block, evaluates the block within the dependency lib instance:

Sunshine.dependencies do
  yum 'new_dep'
  gem 'commander'
end


113
114
115
116
117
# File 'lib/sunshine.rb', line 113

def self.dependencies(&block)
  @dependency_lib ||= DependencyLib.new
  @dependency_lib.instance_eval(&block) if block_given?
  @dependency_lib
end

.deploy_envObject

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



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

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

.exception_behaviorObject

Defines what to do when deploy raises an exception. Supported values are:

::revert:  Revert to the previous deploy.
::console: Start an interactive ruby shell within the app's context.
::exit:    Stop deploy and exit, leaving deploy in unfinished state.
::prompt:  Ask what to do.

Defaults to :revert. Overridden in the config.



129
130
131
# File 'lib/sunshine.rb', line 129

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

.exclude_pathsObject

Array of paths or globs that should be excluded from the checkout. Does not work with remote_checkouts enabled.



138
139
140
# File 'lib/sunshine.rb', line 138

def self.exclude_paths
  @config['exclude_paths']
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


378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/sunshine.rb', line 378

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 "ru" #=> Sunshine::RunCommand
find_command "l" #=> Sunshine::ListCommand
find_command "zzz" #=> nil


361
362
363
364
365
366
# File 'lib/sunshine.rb', line 361

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

  Sunshine.const_get "#{commands.first.capitalize}Command"
end

.interactive?Boolean

Should sunshine ever ask for user input? True by default. Overridden in the config or with the -a option.

Returns:

  • (Boolean)


147
148
149
# File 'lib/sunshine.rb', line 147

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

.load_config_file(conf) ⇒ Object

Loads a yaml config file to run setup with.



262
263
264
# File 'lib/sunshine.rb', line 262

def self.load_config_file conf
  setup YAML.load_file(conf)
end

.load_user_configObject

Loads the USER_CONFIG_FILE and runs setup. Creates the default config file and exits if not present.



271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/sunshine.rb', line 271

def self.load_user_config
  create_default_config!
  load_config_file USER_CONFIG_FILE

  @config['deploy_env'] =
    ENV['DEPLOY_ENV'] ||
    ENV['env']        ||
    ENV['RACK_ENV']   ||
    ENV['RAILS_ENV']  ||
    @config['deploy_env']

  @config
end

.loggerObject

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



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

def self.logger
  @logger
end

.max_deploy_versionsObject

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



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

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

.remote_checkouts?Boolean

Check if the codebase should be checked out remotely, or checked out locally and rsynced up. Overridden in the config.

Returns:

  • (Boolean)


173
174
175
# File 'lib/sunshine.rb', line 173

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

.require_libs(*libs) ⇒ Object

Loads an array of libraries or gems.



299
300
301
# File 'lib/sunshine.rb', line 299

def self.require_libs(*libs)
  libs.compact.each{|lib| require lib }
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}
run %w{--rakefile}


340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/sunshine.rb', line 340

def self.run argv=ARGV
  command = find_command argv.first
  argv.shift if command

  command ||= DefaultCommand

  setup command.parse_args(argv)

  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


308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/sunshine.rb', line 308

def self.setup new_config={}, reset=false
  @config = DEFAULT_CONFIG.dup if reset

  TrapStack.trap_signal :INT do |msg|
    $stderr << "\n\n"
    logger.indent = 0
    logger.fatal :INT, "Caught INT signal!"
    logger.info :INT, msg
  end

  TrapStack.add_trap "Disconnecting all remote shells." do
    RemoteShell.disconnect_all
  end


  require_libs(*new_config['require'])

  config.merge! new_config

  log_level = Logger.const_get config['level'].upcase rescue Logger::INFO
  @logger   = Sunshine::Output.new :level => log_level

  config
end

.shellObject

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



181
182
183
# File 'lib/sunshine.rb', line 181

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

.sigint_behaviorObject

Defines what to do when sigint is sent during deploys. Supported values are:

::revert:  Revert to the previous deploy.
::console: Start an interactive ruby shell within the app's context.
::exit:    Stop deploy and exit, leaving deploy in unfinished state.
::prompt:  Ask what to do.

Defaults to :revert. Overridden in the config.



195
196
197
# File 'lib/sunshine.rb', line 195

def self.sigint_behavior
  @config['sigint_behavior']
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.



246
247
248
# File 'lib/sunshine.rb', line 246

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

.timeoutObject

How long to wait on a command to finish when no output is received. Defaults to 300 (seconds). Overridden in the config. Set to false to disable timeout.



205
206
207
# File 'lib/sunshine.rb', line 205

def self.timeout
  @config['timeout']
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)


216
217
218
# File 'lib/sunshine.rb', line 216

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

.use_threads?Boolean

Check if App objects should use threads when iterating over ServerApps. Defaults to true, overridden with the ‘threads_enabled’ config.

Returns:

  • (Boolean)


225
226
227
# File 'lib/sunshine.rb', line 225

def self.use_threads?
  @config['threads_enabled']
end

.web_directoryObject

The default directory where apps should be deployed to: ‘/var/www’ by default. Overridden in the config. See also App#deploy_path.



235
236
237
# File 'lib/sunshine.rb', line 235

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