dhill-sprinkle 0.3.3.1

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 (118) hide show
  1. data/.gitignore +3 -0
  2. data/CREDITS +33 -0
  3. data/Gemfile +4 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.markdown +242 -0
  6. data/Rakefile +2 -0
  7. data/VERSION +1 -0
  8. data/bin/sprinkle +95 -0
  9. data/examples/packages/build_essential.rb +9 -0
  10. data/examples/packages/databases/mysql.rb +13 -0
  11. data/examples/packages/databases/sqlite3.rb +16 -0
  12. data/examples/packages/phusion.rb +55 -0
  13. data/examples/packages/ruby/rails.rb +9 -0
  14. data/examples/packages/ruby/ruby.rb +17 -0
  15. data/examples/packages/ruby/rubygems.rb +17 -0
  16. data/examples/packages/scm/git.rb +11 -0
  17. data/examples/packages/scm/subversion.rb +4 -0
  18. data/examples/packages/servers/apache.rb +15 -0
  19. data/examples/rails/README +15 -0
  20. data/examples/rails/deploy.rb +2 -0
  21. data/examples/rails/packages/database.rb +9 -0
  22. data/examples/rails/packages/essential.rb +9 -0
  23. data/examples/rails/packages/rails.rb +29 -0
  24. data/examples/rails/packages/scm.rb +11 -0
  25. data/examples/rails/packages/search.rb +11 -0
  26. data/examples/rails/packages/server.rb +28 -0
  27. data/examples/rails/rails.rb +73 -0
  28. data/examples/sprinkle/sprinkle.rb +38 -0
  29. data/lib/sprinkle.rb +3 -0
  30. data/lib/sprinkle/actors/actors.rb +17 -0
  31. data/lib/sprinkle/actors/capistrano.rb +146 -0
  32. data/lib/sprinkle/actors/local.rb +37 -0
  33. data/lib/sprinkle/actors/ssh.rb +177 -0
  34. data/lib/sprinkle/actors/vlad.rb +83 -0
  35. data/lib/sprinkle/configurable.rb +31 -0
  36. data/lib/sprinkle/deployment.rb +73 -0
  37. data/lib/sprinkle/extensions/arbitrary_options.rb +10 -0
  38. data/lib/sprinkle/extensions/array.rb +5 -0
  39. data/lib/sprinkle/extensions/blank_slate.rb +5 -0
  40. data/lib/sprinkle/extensions/dsl_accessor.rb +15 -0
  41. data/lib/sprinkle/extensions/string.rb +10 -0
  42. data/lib/sprinkle/extensions/symbol.rb +7 -0
  43. data/lib/sprinkle/installers/apt.rb +52 -0
  44. data/lib/sprinkle/installers/binary.rb +46 -0
  45. data/lib/sprinkle/installers/bsd_port.rb +33 -0
  46. data/lib/sprinkle/installers/deb.rb +41 -0
  47. data/lib/sprinkle/installers/freebsd_pkg.rb +37 -0
  48. data/lib/sprinkle/installers/freebsd_portinstall.rb +36 -0
  49. data/lib/sprinkle/installers/gem.rb +64 -0
  50. data/lib/sprinkle/installers/install_package.rb +79 -0
  51. data/lib/sprinkle/installers/installer.rb +123 -0
  52. data/lib/sprinkle/installers/mac_port.rb +38 -0
  53. data/lib/sprinkle/installers/noop.rb +20 -0
  54. data/lib/sprinkle/installers/openbsd_pkg.rb +47 -0
  55. data/lib/sprinkle/installers/opensolaris_pkg.rb +43 -0
  56. data/lib/sprinkle/installers/push_text.rb +45 -0
  57. data/lib/sprinkle/installers/rake.rb +37 -0
  58. data/lib/sprinkle/installers/replace_text.rb +45 -0
  59. data/lib/sprinkle/installers/rpm.rb +37 -0
  60. data/lib/sprinkle/installers/runner.rb +18 -0
  61. data/lib/sprinkle/installers/smart.rb +29 -0
  62. data/lib/sprinkle/installers/source.rb +201 -0
  63. data/lib/sprinkle/installers/transfer.rb +178 -0
  64. data/lib/sprinkle/installers/user.rb +15 -0
  65. data/lib/sprinkle/installers/yum.rb +37 -0
  66. data/lib/sprinkle/installers/zypper.rb +43 -0
  67. data/lib/sprinkle/package.rb +326 -0
  68. data/lib/sprinkle/policy.rb +125 -0
  69. data/lib/sprinkle/script.rb +23 -0
  70. data/lib/sprinkle/verifiers/apt.rb +21 -0
  71. data/lib/sprinkle/verifiers/directory.rb +16 -0
  72. data/lib/sprinkle/verifiers/executable.rb +53 -0
  73. data/lib/sprinkle/verifiers/file.rb +34 -0
  74. data/lib/sprinkle/verifiers/package.rb +26 -0
  75. data/lib/sprinkle/verifiers/process.rb +21 -0
  76. data/lib/sprinkle/verifiers/rpm.rb +21 -0
  77. data/lib/sprinkle/verifiers/ruby.rb +25 -0
  78. data/lib/sprinkle/verifiers/symlink.rb +30 -0
  79. data/lib/sprinkle/verify.rb +114 -0
  80. data/lib/sprinkle/version.rb +3 -0
  81. data/script/console +8 -0
  82. data/script/destroy +14 -0
  83. data/script/generate +14 -0
  84. data/spec/spec.opts +1 -0
  85. data/spec/spec_helper.rb +17 -0
  86. data/spec/sprinkle/actors/capistrano_spec.rb +265 -0
  87. data/spec/sprinkle/actors/local_spec.rb +29 -0
  88. data/spec/sprinkle/configurable_spec.rb +46 -0
  89. data/spec/sprinkle/deployment_spec.rb +80 -0
  90. data/spec/sprinkle/extensions/array_spec.rb +19 -0
  91. data/spec/sprinkle/extensions/string_spec.rb +21 -0
  92. data/spec/sprinkle/installers/apt_spec.rb +70 -0
  93. data/spec/sprinkle/installers/bsd_port_spec.rb +42 -0
  94. data/spec/sprinkle/installers/freebsd_pkg_spec.rb +49 -0
  95. data/spec/sprinkle/installers/freebsd_portinstall_spec.rb +42 -0
  96. data/spec/sprinkle/installers/gem_spec.rb +107 -0
  97. data/spec/sprinkle/installers/installer_spec.rb +151 -0
  98. data/spec/sprinkle/installers/mac_port_spec.rb +42 -0
  99. data/spec/sprinkle/installers/noop_spec.rb +23 -0
  100. data/spec/sprinkle/installers/openbsd_pkg_spec.rb +49 -0
  101. data/spec/sprinkle/installers/opensolaris_pkg_spec.rb +49 -0
  102. data/spec/sprinkle/installers/push_text_spec.rb +66 -0
  103. data/spec/sprinkle/installers/rake_spec.rb +29 -0
  104. data/spec/sprinkle/installers/replace_text_spec.rb +45 -0
  105. data/spec/sprinkle/installers/rpm_spec.rb +50 -0
  106. data/spec/sprinkle/installers/runner_spec.rb +31 -0
  107. data/spec/sprinkle/installers/source_spec.rb +371 -0
  108. data/spec/sprinkle/installers/transfer_spec.rb +98 -0
  109. data/spec/sprinkle/installers/yum_spec.rb +49 -0
  110. data/spec/sprinkle/installers/zypper_spec.rb +49 -0
  111. data/spec/sprinkle/package_spec.rb +474 -0
  112. data/spec/sprinkle/policy_spec.rb +126 -0
  113. data/spec/sprinkle/script_spec.rb +51 -0
  114. data/spec/sprinkle/sprinkle_spec.rb +25 -0
  115. data/spec/sprinkle/verify_spec.rb +173 -0
  116. data/sprinkle-0.3.3.1.gem +0 -0
  117. data/sprinkle.gemspec +26 -0
  118. metadata +281 -0
@@ -0,0 +1,37 @@
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 do |command|
22
+ system command
23
+ return false if $?.to_i != 0
24
+ end
25
+ return true
26
+ end
27
+
28
+ def transfer(name, source, destination, roles, recursive = true, suppress_and_return_failures = false)
29
+ if recursive
30
+ flags = "-R "
31
+ end
32
+
33
+ system "cp #{flags}#{source} #{destination}"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,177 @@
1
+ require 'net/ssh/gateway'
2
+ require 'net/scp'
3
+
4
+ module Sprinkle
5
+ module Actors
6
+ class Ssh
7
+ attr_accessor :options
8
+
9
+ def initialize(options = {}, &block) #:nodoc:
10
+ @options = options.update(:user => 'root')
11
+ self.instance_eval &block if block
12
+ end
13
+
14
+ def roles(roles)
15
+ @options[:roles] = roles
16
+ end
17
+
18
+ def gateway(gateway)
19
+ @options[:gateway] = gateway
20
+ end
21
+
22
+ def user(user)
23
+ @options[:user] = user
24
+ end
25
+
26
+ def password(password)
27
+ @options[:password] = password
28
+ end
29
+
30
+ def process(name, commands, roles, suppress_and_return_failures = false)
31
+ return process_with_gateway(name, commands, roles) if gateway_defined?
32
+ r = process_direct(name, commands, roles)
33
+ logger.debug green "process returning #{r}"
34
+ return r
35
+ end
36
+
37
+ def transfer(name, source, destination, roles, recursive = true, suppress_and_return_failures = false)
38
+ return transfer_with_gateway(name, source, destination, roles, recursive) if gateway_defined?
39
+ transfer_direct(name, source, destination, roles, recursive)
40
+ end
41
+
42
+ protected
43
+
44
+ def process_with_gateway(name, commands, roles)
45
+ res = []
46
+ on_gateway do |gateway|
47
+ Array(roles).each { |role| res << execute_on_role(commands, role, gateway) }
48
+ end
49
+ !(res.include? false)
50
+ end
51
+
52
+ def process_direct(name, commands, roles)
53
+ res = []
54
+ Array(roles).each { |role| res << execute_on_role(commands, role) }
55
+ !(res.include? false)
56
+ end
57
+
58
+ def transfer_with_gateway(name, source, destination, roles, recursive)
59
+ on_gateway do |gateway|
60
+ Array(roles).each { |role| transfer_to_role(source, destination, role, recursive, gateway) }
61
+ end
62
+ end
63
+
64
+ def transfer_direct(name, source, destination, roles, recursive)
65
+ Array(roles).each { |role| transfer_to_role(source, destination, role, recursive) }
66
+ end
67
+
68
+ def execute_on_role(commands, role, gateway = nil)
69
+ hosts = @options[:roles][role]
70
+ res = []
71
+ Array(hosts).each { |host| res << execute_on_host(commands, host, gateway) }
72
+ !(res.include? false)
73
+ end
74
+
75
+ def transfer_to_role(source, destination, role, gateway = nil)
76
+ hosts = @options[:roles][role]
77
+ Array(hosts).each { |host| transfer_to_host(source, destination, host, gateway) }
78
+ end
79
+
80
+ def execute_on_host(commands, host, gateway = nil)
81
+ res = nil
82
+ logger.debug(blue "executing #{commands.inspect} on #{host}.")
83
+ if gateway # SSH connection via gateway
84
+ gateway.ssh(host, @options[:user]) do |ssh|
85
+ res = execute_on_connection(commands, ssh)
86
+ ssh.loop
87
+ end
88
+ else # direct SSH connection
89
+ Net::SSH.start(host, @options[:user], :password => @options[:password]) do |ssh|
90
+ res = execute_on_connection(commands, ssh)
91
+ ssh.loop
92
+ end
93
+ end
94
+ res.detect{|x| x!=0}.nil?
95
+ end
96
+
97
+ def execute_on_connection(commands, session)
98
+ res = []
99
+ Array(commands).each do |cmd|
100
+ session.open_channel do |channel|
101
+ channel.on_data do |ch, data|
102
+ logger.debug yellow("stdout said-->\n#{data}\n")
103
+ end
104
+ channel.on_extended_data do |ch, type, data|
105
+ next unless type == 1 # only handle stderr
106
+ logger.debug red("stderr said -->\n#{data}\n")
107
+ end
108
+
109
+ channel.on_request("exit-status") do |ch, data|
110
+ exit_code = data.read_long
111
+ if exit_code == 0
112
+ logger.debug(green 'success')
113
+ else
114
+ logger.debug(red('failed (%d).'%exit_code))
115
+ end
116
+ res << exit_code
117
+ end
118
+
119
+ channel.on_request("exit-signal") do |ch, data|
120
+ logger.debug red("#{cmd} was signaled!: #{data.read_long}")
121
+ end
122
+
123
+ channel.exec cmd do |ch, status|
124
+ logger.error("couldn't run remote command #{cmd}") unless status
125
+ end
126
+ end
127
+ end
128
+ res
129
+ end
130
+
131
+ def transfer_to_host(source, destination, host, recursive, gateway = nil)
132
+ if gateway # SSH connection via gateway
133
+ gateway.ssh(host, @options[:user]) do |ssh|
134
+ transfer_on_connection(source, destination, recursive, ssh)
135
+ end
136
+ else # direct SSH connection
137
+ Net::SSH.start(host, @options[:user]) do |ssh|
138
+ transfer_on_connection(source, destination, recursive, ssh)
139
+ end
140
+ end
141
+ end
142
+
143
+ def transfer_on_connection(source, destination, recursive, connection)
144
+ scp = Net::SCP.new(connection)
145
+ scp.upload! source, destination, :recursive => recursive
146
+ end
147
+
148
+ private
149
+ def color(code, s)
150
+ "\033[%sm%s\033[0m"%[code,s]
151
+ end
152
+ def red(s)
153
+ color(31, s)
154
+ end
155
+ def yellow(s)
156
+ color(33, s)
157
+ end
158
+ def green(s)
159
+ color(32, s)
160
+ end
161
+ def blue(s)
162
+ color(34, s)
163
+ end
164
+
165
+ def gateway_defined?
166
+ !! @options[:gateway]
167
+ end
168
+
169
+ def on_gateway(&block)
170
+ gateway = Net::SSH::Gateway.new(@options[:gateway], @options[:user])
171
+ block.call gateway
172
+ ensure
173
+ gateway.shutdown!
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,83 @@
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 vlad 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
+ require name
40
+ @loaded_recipes << name
41
+ end
42
+
43
+ def process(name, commands, roles, suppress_and_return_failures = false) #:nodoc:
44
+ commands = Array(commands)
45
+ if use_sudo
46
+ commands = commands.map{|x| "sudo #{x}"}
47
+ end
48
+ commands = commands.join(' && ')
49
+ puts "executing #{commands}"
50
+ t = remote_task(task_sym(name), :roles => roles) { run commands }
51
+
52
+ begin
53
+ t.invoke
54
+ return true
55
+ rescue ::Rake::CommandFailedError => e
56
+ return false if suppress_and_return_failures
57
+
58
+ # Reraise error if we're not suppressing it
59
+ raise
60
+ end
61
+ end
62
+
63
+ # Sorry, all transfers are recursive
64
+ def transfer(name, source, destination, roles, recursive = true, suppress_and_return_failures = false) #:nodoc:
65
+ begin
66
+ rsync source, destination
67
+ return true
68
+ rescue ::Rake::CommandFailedError => e
69
+ return false if suppress_and_return_failures
70
+
71
+ # Reraise error if we're not suppressing it
72
+ raise
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def task_sym(name)
79
+ "install_#{name.to_task_name}".to_sym
80
+ end
81
+ end
82
+ end
83
+ 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 = ("Sprinkle::Actors::" + type.to_s.titleize).constantize.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
@@ -0,0 +1,10 @@
1
+ module ArbitraryOptions #:nodoc:
2
+ def self.included(base)
3
+ base.alias_method_chain :method_missing, :arbitrary_options
4
+ end
5
+
6
+ def method_missing_with_arbitrary_options(sym, *args, &block)
7
+ self.class.dsl_accessor sym
8
+ send(sym, *args, &block)
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ class Array #:nodoc:
2
+ def to_task_name
3
+ collect(&:to_task_name).join('_')
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class BlankSlate #:nodoc:
2
+ instance_methods.each do |m|
3
+ undef_method(m) unless %w( __send__ __id__ send class inspect instance_eval instance_variables ).include?(m)
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ class Module #:nodoc:
2
+ def dsl_accessor(*symbols)
3
+ symbols.each do |sym|
4
+ class_eval %{
5
+ def #{sym}(*val)
6
+ if val.empty?
7
+ @#{sym}
8
+ else
9
+ @#{sym} = val.size == 1 ? val[0] : val
10
+ end
11
+ end
12
+ }
13
+ end
14
+ end
15
+ end