jsierles-sprinkle 0.1.9

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.
Files changed (89) hide show
  1. data/CREDITS +19 -0
  2. data/History.txt +4 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest.txt +87 -0
  5. data/README.txt +238 -0
  6. data/Rakefile +4 -0
  7. data/bin/sprinkle +86 -0
  8. data/config/hoe.rb +70 -0
  9. data/config/requirements.rb +17 -0
  10. data/examples/packages/build_essential.rb +9 -0
  11. data/examples/packages/databases/mysql.rb +13 -0
  12. data/examples/packages/databases/sqlite3.rb +16 -0
  13. data/examples/packages/phusion.rb +55 -0
  14. data/examples/packages/ruby/rails.rb +9 -0
  15. data/examples/packages/ruby/ruby.rb +17 -0
  16. data/examples/packages/ruby/rubygems.rb +17 -0
  17. data/examples/packages/scm/git.rb +11 -0
  18. data/examples/packages/scm/subversion.rb +4 -0
  19. data/examples/packages/servers/apache.rb +15 -0
  20. data/examples/rails/README +15 -0
  21. data/examples/rails/deploy.rb +2 -0
  22. data/examples/rails/packages/database.rb +9 -0
  23. data/examples/rails/packages/essential.rb +9 -0
  24. data/examples/rails/packages/rails.rb +28 -0
  25. data/examples/rails/packages/scm.rb +11 -0
  26. data/examples/rails/packages/search.rb +11 -0
  27. data/examples/rails/packages/server.rb +28 -0
  28. data/examples/rails/rails.rb +73 -0
  29. data/examples/sprinkle/sprinkle.rb +38 -0
  30. data/lib/sprinkle.rb +32 -0
  31. data/lib/sprinkle/actors/actors.rb +17 -0
  32. data/lib/sprinkle/actors/capistrano.rb +117 -0
  33. data/lib/sprinkle/actors/local.rb +26 -0
  34. data/lib/sprinkle/actors/ssh.rb +81 -0
  35. data/lib/sprinkle/actors/vlad.rb +65 -0
  36. data/lib/sprinkle/configurable.rb +31 -0
  37. data/lib/sprinkle/deployment.rb +73 -0
  38. data/lib/sprinkle/extensions/arbitrary_options.rb +10 -0
  39. data/lib/sprinkle/extensions/array.rb +5 -0
  40. data/lib/sprinkle/extensions/blank_slate.rb +5 -0
  41. data/lib/sprinkle/extensions/dsl_accessor.rb +15 -0
  42. data/lib/sprinkle/extensions/string.rb +10 -0
  43. data/lib/sprinkle/extensions/symbol.rb +7 -0
  44. data/lib/sprinkle/installers/apt.rb +52 -0
  45. data/lib/sprinkle/installers/deb.rb +38 -0
  46. data/lib/sprinkle/installers/gem.rb +62 -0
  47. data/lib/sprinkle/installers/installer.rb +120 -0
  48. data/lib/sprinkle/installers/rake.rb +37 -0
  49. data/lib/sprinkle/installers/rpm.rb +37 -0
  50. data/lib/sprinkle/installers/source.rb +179 -0
  51. data/lib/sprinkle/installers/yum.rb +37 -0
  52. data/lib/sprinkle/package.rb +233 -0
  53. data/lib/sprinkle/policy.rb +125 -0
  54. data/lib/sprinkle/script.rb +23 -0
  55. data/lib/sprinkle/verifiers/directory.rb +16 -0
  56. data/lib/sprinkle/verifiers/executable.rb +36 -0
  57. data/lib/sprinkle/verifiers/file.rb +20 -0
  58. data/lib/sprinkle/verifiers/process.rb +21 -0
  59. data/lib/sprinkle/verifiers/ruby.rb +25 -0
  60. data/lib/sprinkle/verifiers/symlink.rb +30 -0
  61. data/lib/sprinkle/verify.rb +114 -0
  62. data/lib/sprinkle/version.rb +9 -0
  63. data/script/destroy +14 -0
  64. data/script/generate +14 -0
  65. data/spec/spec.opts +1 -0
  66. data/spec/spec_helper.rb +17 -0
  67. data/spec/sprinkle/actors/capistrano_spec.rb +170 -0
  68. data/spec/sprinkle/actors/local_spec.rb +29 -0
  69. data/spec/sprinkle/configurable_spec.rb +46 -0
  70. data/spec/sprinkle/deployment_spec.rb +80 -0
  71. data/spec/sprinkle/extensions/array_spec.rb +19 -0
  72. data/spec/sprinkle/extensions/string_spec.rb +21 -0
  73. data/spec/sprinkle/installers/apt_spec.rb +70 -0
  74. data/spec/sprinkle/installers/gem_spec.rb +75 -0
  75. data/spec/sprinkle/installers/installer_spec.rb +151 -0
  76. data/spec/sprinkle/installers/rake_spec.rb +29 -0
  77. data/spec/sprinkle/installers/rpm_spec.rb +50 -0
  78. data/spec/sprinkle/installers/source_spec.rb +331 -0
  79. data/spec/sprinkle/installers/yum_spec.rb +49 -0
  80. data/spec/sprinkle/package_spec.rb +422 -0
  81. data/spec/sprinkle/policy_spec.rb +126 -0
  82. data/spec/sprinkle/script_spec.rb +51 -0
  83. data/spec/sprinkle/sprinkle_spec.rb +25 -0
  84. data/spec/sprinkle/verify_spec.rb +160 -0
  85. data/sprinkle.gemspec +70 -0
  86. data/tasks/deployment.rake +34 -0
  87. data/tasks/environment.rake +7 -0
  88. data/tasks/rspec.rake +21 -0
  89. metadata +180 -0
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env sprinkle -c -s
2
+
3
+ # Example of the simplest Sprinkle script to install a single gem on a remote host. This
4
+ # particular script assumes that rubygems (and ruby, etc) are already installed on the remote
5
+ # host. To see a larger example of installing an entire ruby, rubygems, gem stack from source,
6
+ # please see the rails example.
7
+
8
+ # Packages, only sprinkle is defined in this world
9
+
10
+ package :sprinkle do
11
+ description 'Sprinkle Provisioning Tool'
12
+ gem 'crafterm-sprinkle' do
13
+ source 'http://gems.github.com' # use alternate gem server
14
+ #repository '/opt/local/gems' # specify an alternate local gem repository
15
+ end
16
+ end
17
+
18
+
19
+ # Policies, sprinkle policy requires only the sprinkle gem
20
+
21
+ policy :sprinkle, :roles => :app do
22
+ requires :sprinkle
23
+ end
24
+
25
+
26
+ # Deployment settings
27
+
28
+ deployment do
29
+
30
+ # use vlad for deployment
31
+ delivery :vlad do
32
+ role :app, 'yourhost.com'
33
+ end
34
+
35
+ end
36
+
37
+ # End of script, given the above information, Spinkle will apply the defined policy on all roles using the
38
+ # deployment settings specified.
data/lib/sprinkle.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+
4
+ # Use active supports auto load mechanism
5
+ ActiveSupport::Dependencies.load_paths << File.dirname(__FILE__)
6
+
7
+ # Configure active support to log auto-loading of dependencies
8
+ #ActiveSupport::Dependencies::RAILS_DEFAULT_LOGGER = Logger.new($stdout)
9
+ #ActiveSupport::Dependencies.log_activity = true
10
+
11
+ # Load up extensions to existing classes
12
+ Dir[File.dirname(__FILE__) + '/sprinkle/extensions/*.rb'].each { |e| require e }
13
+ # Load up the verifiers so they can register themselves
14
+ Dir[File.dirname(__FILE__) + '/sprinkle/verifiers/*.rb'].each { |e| require e }
15
+
16
+ # Configuration options
17
+ module Sprinkle
18
+ OPTIONS = { :testing => false, :verbose => false, :force => false }
19
+ end
20
+
21
+ # Object is extended to give the package, policy, and deployment methods. To
22
+ # read about each method, see the corresponding module which is included.
23
+ #--
24
+ # Define a logging target and understand packages, policies and deployment DSL
25
+ #++
26
+ class Object
27
+ include Sprinkle::Package, Sprinkle::Policy, Sprinkle::Deployment
28
+
29
+ def logger # :nodoc:
30
+ @@__log__ ||= ActiveSupport::BufferedLogger.new($stdout, ActiveSupport::BufferedLogger::Severity::INFO)
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ #--
2
+ # The only point of this file is to give RDoc a definition for
3
+ # Sprinkle::Actors. This file in production is never actually included
4
+ # since ActiveSupport only on-demand loads classes which are needed
5
+ # and this module is never explicitly needed.
6
+ #++
7
+
8
+ module Sprinkle
9
+ # An actor is a method of command delivery to a remote machine. It is the
10
+ # layer between sprinkle and the SSH connection to run commands. This gives
11
+ # you the flexibility to define custom actors, for whatever purpose you need.
12
+ #
13
+ # 99% of the time, however, the two built-in actors Sprinkle::Actors::Capistrano
14
+ # and Sprinkle::Actors::Vlad will be enough.
15
+ module Actors
16
+ end
17
+ end
@@ -0,0 +1,117 @@
1
+ require 'capistrano/cli'
2
+
3
+ module Sprinkle
4
+ module Actors
5
+ # = Capistrano Delivery Method
6
+ #
7
+ # Capistrano is one of the delivery method options available out of the
8
+ # box with Sprinkle. If you have the capistrano gem install, you may use
9
+ # this delivery. The only configuration option available, and which is
10
+ # mandatory to include is +recipes+. An example:
11
+ #
12
+ # deployment do
13
+ # delivery :capistrano do
14
+ # recipes 'deploy'
15
+ # end
16
+ # end
17
+ #
18
+ # Recipes is given a list of files which capistrano will include and load.
19
+ # These recipes are mainly to set variables such as :user, :password, and to
20
+ # set the app domain which will be sprinkled.
21
+ class Capistrano
22
+ attr_accessor :config, :loaded_recipes #:nodoc:
23
+
24
+ def initialize(&block) #:nodoc:
25
+ @config = ::Capistrano::Configuration.new
26
+ @config.logger.level = Sprinkle::OPTIONS[:verbose] ? ::Capistrano::Logger::INFO : ::Capistrano::Logger::IMPORTANT
27
+ @config.set(:password) { ::Capistrano::CLI.password_prompt }
28
+ if block
29
+ self.instance_eval &block
30
+ else
31
+ @config.load 'deploy' # normally in the config directory for rails
32
+ end
33
+ end
34
+
35
+ # Defines a recipe file which will be included by capistrano. Use these
36
+ # recipe files to set capistrano specific configurations. Default recipe
37
+ # included is "deploy." But if any other recipe is specified, it will
38
+ # include that instead. Multiple recipes may be specified through multiple
39
+ # recipes calls, an example:
40
+ #
41
+ # deployment do
42
+ # delivery :capistrano do
43
+ # recipes 'deploy'
44
+ # recipes 'magic_beans'
45
+ # end
46
+ # end
47
+ def recipes(script)
48
+ @loaded_recipes ||= []
49
+ @config.load script
50
+ @loaded_recipes << script
51
+ end
52
+
53
+ def process(name, commands, roles, suppress_and_return_failures = false) #:nodoc:
54
+ define_task(name, roles) do
55
+ via = fetch(:run_method, :sudo)
56
+ commands.each do |command|
57
+ invoke_command command, :via => via
58
+ end
59
+ end
60
+
61
+ begin
62
+ run(name)
63
+ return true
64
+ rescue ::Capistrano::CommandError => e
65
+ return false if suppress_and_return_failures
66
+
67
+ # Reraise error if we're not suppressing it
68
+ raise
69
+ end
70
+ end
71
+
72
+ private
73
+
74
+ # REVISIT: can we set the description somehow?
75
+ def define_task(name, roles, &block)
76
+ @config.task task_sym(name), :roles => roles, &block
77
+ end
78
+
79
+ def run(task)
80
+ @config.send task_sym(task)
81
+ end
82
+
83
+ def task_sym(name)
84
+ "install_#{name.to_task_name}".to_sym
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+
91
+ =begin
92
+
93
+ # channel: the SSH channel object used for this response
94
+ # stream: either :err or :out, for stderr or stdout responses
95
+ # output: the text that the server is sending, might be in chunks
96
+ run "apt-get update" do |channel, stream, output|
97
+ if output =~ /Are you sure?/
98
+ answer = Capistrano::CLI.ui.ask("Are you sure: ")
99
+ channel.send_data(answer + "\n")
100
+ else
101
+ # allow the default callback to be processed
102
+ Capistrano::Configuration.default_io_proc.call[channel, stream, output]
103
+ end
104
+ end
105
+
106
+
107
+
108
+ You can tell subversion to use a different username+password by
109
+ setting a couple variables:
110
+ set :svn_username, "my svn username"
111
+ set :svn_password, "my svn password"
112
+ If you don't want to set the password explicitly in your recipe like
113
+ that, you can make capistrano prompt you for it like this:
114
+ set(:svn_password) { Capistrano::CLI.password_prompt("Subversion
115
+ password: ") }
116
+ - Jamis
117
+ =end
@@ -0,0 +1,26 @@
1
+ module Sprinkle
2
+ module Actors
3
+ # = Local Delivery Method
4
+ #
5
+ # This actor implementation performs any given commands on your local system, as
6
+ # opposed to other implementations that generally run commands on a remote system
7
+ # via the network.
8
+ #
9
+ # This is useful if you'd like to use Sprinkle to provision your local machine.
10
+ # To enable this actor, in your Sprinkle script specify the :local delivery mechanism.
11
+ #
12
+ # deployment do
13
+ # delivery :local
14
+ # end
15
+ #
16
+ # Note, your local machine will be assumed to be a member of all roles when applying policies
17
+ #
18
+ class Local
19
+
20
+ def process(name, commands, roles, suppress_and_return_failures = false) #:nodoc:
21
+ commands.each { |command| system command }
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,81 @@
1
+ require 'net/ssh/gateway'
2
+
3
+ module Sprinkle
4
+ module Actors
5
+ class Ssh
6
+ attr_accessor :options
7
+
8
+ def initialize(options = {}, &block) #:nodoc:
9
+ @options = options.update(:user => 'root')
10
+ self.instance_eval &block if block
11
+ end
12
+
13
+ def roles(roles)
14
+ @options[:roles] = roles
15
+ end
16
+
17
+ def gateway(gateway)
18
+ @options[:gateway] = gateway
19
+ end
20
+
21
+ def user(user)
22
+ @options[:user] = user
23
+ end
24
+
25
+ def process(name, commands, roles, suppress_and_return_failures = false)
26
+ return process_with_gateway(name, commands, roles) if gateway_defined?
27
+ process_direct(name, commands, roles)
28
+ end
29
+
30
+ protected
31
+
32
+ def process_with_gateway(name, commands, roles)
33
+ on_gateway do |gateway|
34
+ Array(roles).each { |role| execute_on_role(commands, role, gateway) }
35
+ end
36
+ end
37
+
38
+ def process_direct(name, commands, roles)
39
+ Array(roles).each { |role| execute_on_role(commands, role) }
40
+ end
41
+
42
+ def execute_on_role(commands, role, gateway = nil)
43
+ hosts = @options[:roles][role]
44
+ Array(hosts).each { |host| execute_on_host(commands, host, gateway) }
45
+ end
46
+
47
+ def execute_on_host(commands, host, gateway = nil)
48
+ if gateway # SSH connection via gateway
49
+ gateway.ssh(host, @options[:user]) do |ssh|
50
+ execute_on_connection(commands, ssh)
51
+ end
52
+ else # direct SSH connection
53
+ Net::SSH.start(host, @options[:user]) do |ssh|
54
+ execute_on_connection(commands, ssh)
55
+ end
56
+ end
57
+ end
58
+
59
+ def execute_on_connection(commands, connection)
60
+ Array(commands).each do |command|
61
+ connection.exec! command do |ch, stream, data|
62
+ logger.send((stream == :stderr ? 'error' : 'debug'), data)
63
+ end
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def gateway_defined?
70
+ !! @options[:gateway]
71
+ end
72
+
73
+ def on_gateway(&block)
74
+ gateway = Net::SSH::Gateway.new(@options[:gateway], @options[:user])
75
+ block.call gateway
76
+ ensure
77
+ gateway.shutdown!
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,65 @@
1
+ module Sprinkle
2
+ module Actors
3
+ # = Vlad Delivery Method
4
+ #
5
+ # Vlad is one of the delivery method options available out of the
6
+ # box with Sprinkle. If you have the vlad the deployer gem install, you
7
+ # may use this delivery. The only configuration option available, and
8
+ # which is mandatory to include is +script+. An example:
9
+ #
10
+ # deployment do
11
+ # delivery :vlad do
12
+ # script 'deploy'
13
+ # end
14
+ # end
15
+ #
16
+ # script is given a list of files which capistrano will include and load.
17
+ # These recipes are mainly to set variables such as :user, :password, and to
18
+ # set the app domain which will be sprinkled.
19
+ class Vlad
20
+ require 'vlad'
21
+ attr_accessor :loaded_recipes #:nodoc:
22
+
23
+ def initialize(&block) #:nodoc:
24
+ self.instance_eval &block if block
25
+ end
26
+
27
+ # Defines a script file which will be included by vlad. Use these
28
+ # script files to set vlad specific configurations. Multiple scripts
29
+ # may be specified through multiple script calls, an example:
30
+ #
31
+ # deployment do
32
+ # delivery :vlad do
33
+ # script 'deploy'
34
+ # script 'magic_beans'
35
+ # end
36
+ # end
37
+ def script(name)
38
+ @loaded_recipes ||= []
39
+ self.load name
40
+ @loaded_recipes << script
41
+ end
42
+
43
+ def process(name, commands, roles, suppress_and_return_failures = false) #:nodoc:
44
+ commands = commands.join ' && ' if commands.is_a? Array
45
+ t = remote_task(task_sym(name), :roles => roles) { run commands }
46
+
47
+ begin
48
+ t.invoke
49
+ return true
50
+ rescue ::Vlad::CommandFailedError => e
51
+ return false if suppress_and_return_failures
52
+
53
+ # Reraise error if we're not suppressing it
54
+ raise
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def task_sym(name)
61
+ "install_#{name.to_task_name}".to_sym
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,31 @@
1
+ module Sprinkle
2
+ #--
3
+ # TODO: Possible documentation?
4
+ #++
5
+ module Configurable #:nodoc:
6
+ attr_accessor :delivery
7
+
8
+ def defaults(deployment)
9
+ defaults = deployment.defaults[self.class.name.split(/::/).last.downcase.to_sym]
10
+ self.instance_eval(&defaults) if defaults
11
+ @delivery = deployment.style
12
+ end
13
+
14
+ def assert_delivery
15
+ raise 'Unknown command delivery target' unless @delivery
16
+ end
17
+
18
+ def method_missing(sym, *args, &block)
19
+ unless args.empty? # mutate if not set
20
+ @options ||= {}
21
+ @options[sym] = *args unless @options[sym]
22
+ end
23
+
24
+ @options[sym] || @package.send(sym, *args, &block) # try the parents options if unknown
25
+ end
26
+
27
+ def option?(sym)
28
+ !@options[sym].nil?
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,73 @@
1
+ module Sprinkle
2
+ # Deployment blocks specify deployment specific information about a
3
+ # sprinkle script. An example:
4
+ #
5
+ # deployment do
6
+ # # mechanism for deployment
7
+ # delivery :capistrano do
8
+ # recipes 'deploy'
9
+ # end
10
+ #
11
+ # # source based package installer defaults
12
+ # source do
13
+ # prefix '/usr/local'
14
+ # archives '/usr/local/sources'
15
+ # builds '/usr/local/build'
16
+ # end
17
+ # end
18
+ #
19
+ # What the above example does is tell sprinkle that we will be using
20
+ # *capistrano* (Sprinkle::Actors::Capistrano) for deployment and
21
+ # everything within the block is capistrano specific configuration.
22
+ # For more information on what options are available, check the corresponding
23
+ # Sprinkle::Actors doc page.
24
+ #
25
+ # In addition to what delivery mechanism we're using, we specify some
26
+ # configuration options for the "source" command. The only things
27
+ # configurable, at this time, in the deployment block other than
28
+ # the delivery method are installers. If installers are configurable,
29
+ # they will say so on their corresponding documentation page. See
30
+ # Sprinkle::Installers
31
+ #
32
+ # <b>Only one deployment block is on any given sprinkle script</b>
33
+ module Deployment
34
+ # The method outlined above which specifies deployment specific information
35
+ # for a sprinkle script. For more information, read the header of this module.
36
+ def deployment(&block)
37
+ @deployment = Deployment.new(&block)
38
+ end
39
+
40
+ class Deployment
41
+ attr_accessor :style, :defaults #:nodoc:
42
+
43
+ def initialize(&block) #:nodoc:
44
+ @defaults = {}
45
+ self.instance_eval(&block)
46
+ raise 'No delivery mechanism defined' unless @style
47
+ end
48
+
49
+ # Specifies which Sprinkle::Actors to use for delivery. Although all
50
+ # actors jobs are the same: to run remote commands on a server, you
51
+ # may have a personal preference. The block you pass is used to configure
52
+ # the actor. For more information on what configuration options are
53
+ # available, view the corresponding Sprinkle::Actors page.
54
+ def delivery(type, &block) #:doc:
55
+ @style = Actors.const_get(type.to_s.titleize).new &block
56
+ end
57
+
58
+ def method_missing(sym, *args, &block) #:nodoc:
59
+ @defaults[sym] = block
60
+ end
61
+
62
+ def respond_to?(sym) #:nodoc:
63
+ !!@defaults[sym]
64
+ end
65
+
66
+ def process #:nodoc:
67
+ POLICIES.each do |policy|
68
+ policy.process(self)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end