dhill-sprinkle 0.3.3.1

Sign up to get free protection for your applications and to get access to all the features.
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