powcloud-sprinkle 0.3.0

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 (106) hide show
  1. data/.gitignore +5 -0
  2. data/CREDITS +33 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.markdown +241 -0
  5. data/Rakefile +50 -0
  6. data/VERSION +1 -0
  7. data/bin/sprinkle +90 -0
  8. data/examples/packages/build_essential.rb +9 -0
  9. data/examples/packages/databases/mysql.rb +13 -0
  10. data/examples/packages/databases/sqlite3.rb +16 -0
  11. data/examples/packages/phusion.rb +55 -0
  12. data/examples/packages/ruby/rails.rb +9 -0
  13. data/examples/packages/ruby/ruby.rb +17 -0
  14. data/examples/packages/ruby/rubygems.rb +17 -0
  15. data/examples/packages/scm/git.rb +11 -0
  16. data/examples/packages/scm/subversion.rb +4 -0
  17. data/examples/packages/servers/apache.rb +15 -0
  18. data/examples/rails/README +15 -0
  19. data/examples/rails/deploy.rb +2 -0
  20. data/examples/rails/packages/database.rb +9 -0
  21. data/examples/rails/packages/essential.rb +9 -0
  22. data/examples/rails/packages/rails.rb +29 -0
  23. data/examples/rails/packages/scm.rb +11 -0
  24. data/examples/rails/packages/search.rb +11 -0
  25. data/examples/rails/packages/server.rb +28 -0
  26. data/examples/rails/rails.rb +73 -0
  27. data/examples/sprinkle/sprinkle.rb +38 -0
  28. data/lib/sprinkle/actors/actors.rb +17 -0
  29. data/lib/sprinkle/actors/capistrano.rb +140 -0
  30. data/lib/sprinkle/actors/local.rb +37 -0
  31. data/lib/sprinkle/actors/ssh.rb +123 -0
  32. data/lib/sprinkle/actors/vlad.rb +78 -0
  33. data/lib/sprinkle/configurable.rb +31 -0
  34. data/lib/sprinkle/deployment.rb +73 -0
  35. data/lib/sprinkle/extensions/arbitrary_options.rb +10 -0
  36. data/lib/sprinkle/extensions/array.rb +5 -0
  37. data/lib/sprinkle/extensions/blank_slate.rb +5 -0
  38. data/lib/sprinkle/extensions/dsl_accessor.rb +15 -0
  39. data/lib/sprinkle/extensions/string.rb +10 -0
  40. data/lib/sprinkle/extensions/symbol.rb +7 -0
  41. data/lib/sprinkle/installers/apt.rb +52 -0
  42. data/lib/sprinkle/installers/binary.rb +46 -0
  43. data/lib/sprinkle/installers/bsd_port.rb +33 -0
  44. data/lib/sprinkle/installers/deb.rb +38 -0
  45. data/lib/sprinkle/installers/freebsd_pkg.rb +37 -0
  46. data/lib/sprinkle/installers/freebsd_portinstall.rb +36 -0
  47. data/lib/sprinkle/installers/gem.rb +64 -0
  48. data/lib/sprinkle/installers/install_package.rb +79 -0
  49. data/lib/sprinkle/installers/installer.rb +120 -0
  50. data/lib/sprinkle/installers/mac_port.rb +38 -0
  51. data/lib/sprinkle/installers/noop.rb +20 -0
  52. data/lib/sprinkle/installers/openbsd_pkg.rb +47 -0
  53. data/lib/sprinkle/installers/opensolaris_pkg.rb +43 -0
  54. data/lib/sprinkle/installers/push_text.rb +45 -0
  55. data/lib/sprinkle/installers/rake.rb +37 -0
  56. data/lib/sprinkle/installers/rpm.rb +37 -0
  57. data/lib/sprinkle/installers/smart.rb +29 -0
  58. data/lib/sprinkle/installers/source.rb +190 -0
  59. data/lib/sprinkle/installers/transfer.rb +164 -0
  60. data/lib/sprinkle/installers/yum.rb +37 -0
  61. data/lib/sprinkle/package.rb +309 -0
  62. data/lib/sprinkle/policy.rb +125 -0
  63. data/lib/sprinkle/script.rb +23 -0
  64. data/lib/sprinkle/verifiers/directory.rb +16 -0
  65. data/lib/sprinkle/verifiers/executable.rb +53 -0
  66. data/lib/sprinkle/verifiers/file.rb +26 -0
  67. data/lib/sprinkle/verifiers/package.rb +26 -0
  68. data/lib/sprinkle/verifiers/process.rb +21 -0
  69. data/lib/sprinkle/verifiers/rpm.rb +21 -0
  70. data/lib/sprinkle/verifiers/ruby.rb +25 -0
  71. data/lib/sprinkle/verifiers/symlink.rb +30 -0
  72. data/lib/sprinkle/verify.rb +114 -0
  73. data/lib/sprinkle.rb +32 -0
  74. data/script/console +8 -0
  75. data/script/destroy +14 -0
  76. data/script/generate +14 -0
  77. data/spec/spec.opts +1 -0
  78. data/spec/spec_helper.rb +17 -0
  79. data/spec/sprinkle/actors/capistrano_spec.rb +265 -0
  80. data/spec/sprinkle/actors/local_spec.rb +29 -0
  81. data/spec/sprinkle/configurable_spec.rb +46 -0
  82. data/spec/sprinkle/deployment_spec.rb +80 -0
  83. data/spec/sprinkle/extensions/array_spec.rb +19 -0
  84. data/spec/sprinkle/extensions/string_spec.rb +21 -0
  85. data/spec/sprinkle/installers/apt_spec.rb +70 -0
  86. data/spec/sprinkle/installers/bsd_port_spec.rb +42 -0
  87. data/spec/sprinkle/installers/freebsd_pkg_spec.rb +49 -0
  88. data/spec/sprinkle/installers/freebsd_portinstall_spec.rb +42 -0
  89. data/spec/sprinkle/installers/gem_spec.rb +107 -0
  90. data/spec/sprinkle/installers/installer_spec.rb +151 -0
  91. data/spec/sprinkle/installers/mac_port_spec.rb +42 -0
  92. data/spec/sprinkle/installers/noop_spec.rb +23 -0
  93. data/spec/sprinkle/installers/openbsd_pkg_spec.rb +49 -0
  94. data/spec/sprinkle/installers/opensolaris_pkg_spec.rb +49 -0
  95. data/spec/sprinkle/installers/push_text_spec.rb +66 -0
  96. data/spec/sprinkle/installers/rake_spec.rb +29 -0
  97. data/spec/sprinkle/installers/rpm_spec.rb +50 -0
  98. data/spec/sprinkle/installers/source_spec.rb +371 -0
  99. data/spec/sprinkle/installers/transfer_spec.rb +98 -0
  100. data/spec/sprinkle/installers/yum_spec.rb +49 -0
  101. data/spec/sprinkle/package_spec.rb +466 -0
  102. data/spec/sprinkle/policy_spec.rb +126 -0
  103. data/spec/sprinkle/script_spec.rb +51 -0
  104. data/spec/sprinkle/sprinkle_spec.rb +25 -0
  105. data/spec/sprinkle/verify_spec.rb +174 -0
  106. metadata +244 -0
@@ -0,0 +1,140 @@
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
+
29
+ @config.set(:_sprinkle_actor, self)
30
+
31
+ def @config.recipes(script)
32
+ _sprinkle_actor.recipes(script)
33
+ end
34
+
35
+ if block
36
+ @config.instance_eval &block
37
+ else
38
+ @config.load 'deploy' # normally in the config directory for rails
39
+ end
40
+ end
41
+
42
+ # Defines a recipe file which will be included by capistrano. Use these
43
+ # recipe files to set capistrano specific configurations. Default recipe
44
+ # included is "deploy." But if any other recipe is specified, it will
45
+ # include that instead. Multiple recipes may be specified through multiple
46
+ # recipes calls, an example:
47
+ #
48
+ # deployment do
49
+ # delivery :capistrano do
50
+ # recipes 'deploy'
51
+ # recipes 'magic_beans'
52
+ # end
53
+ # end
54
+ def recipes(script)
55
+ @loaded_recipes ||= []
56
+ @config.load script
57
+ @loaded_recipes << script
58
+ end
59
+
60
+ def process(name, commands, roles, suppress_and_return_failures = false) #:nodoc:
61
+ define_task(name, roles) do
62
+ via = fetch(:run_method, :sudo)
63
+ commands.each do |command|
64
+ invoke_command command, :via => via
65
+ end
66
+ end
67
+
68
+ begin
69
+ run(name)
70
+ return true
71
+ rescue ::Capistrano::CommandError => e
72
+ return false if suppress_and_return_failures
73
+
74
+ # Reraise error if we're not suppressing it
75
+ raise
76
+ end
77
+ end
78
+
79
+ def transfer(name, source, destination, roles, recursive = true, suppress_and_return_failures = false)
80
+ define_task(name, roles) do
81
+ upload source, destination, :via => :scp, :recursive => recursive
82
+ end
83
+
84
+ begin
85
+ run(name)
86
+ return true
87
+ rescue ::Capistrano::CommandError => e
88
+ return false if suppress_and_return_failures
89
+
90
+ # Reraise error if we're not suppressing it
91
+ raise
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ # REVISIT: can we set the description somehow?
98
+ def define_task(name, roles, &block)
99
+ @config.task task_sym(name), :roles => roles, &block
100
+ end
101
+
102
+ def run(task)
103
+ @config.send task_sym(task)
104
+ end
105
+
106
+ def task_sym(name)
107
+ "install_#{name.to_task_name}".to_sym
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+
114
+ =begin
115
+
116
+ # channel: the SSH channel object used for this response
117
+ # stream: either :err or :out, for stderr or stdout responses
118
+ # output: the text that the server is sending, might be in chunks
119
+ run "apt-get update" do |channel, stream, output|
120
+ if output =~ /Are you sure?/
121
+ answer = Capistrano::CLI.ui.ask("Are you sure: ")
122
+ channel.send_data(answer + "\n")
123
+ else
124
+ # allow the default callback to be processed
125
+ Capistrano::Configuration.default_io_proc.call[channel, stream, output]
126
+ end
127
+ end
128
+
129
+
130
+
131
+ You can tell subversion to use a different username+password by
132
+ setting a couple variables:
133
+ set :svn_username, "my svn username"
134
+ set :svn_password, "my svn password"
135
+ If you don't want to set the password explicitly in your recipe like
136
+ that, you can make capistrano prompt you for it like this:
137
+ set(:svn_password) { Capistrano::CLI.password_prompt("Subversion
138
+ password: ") }
139
+ - Jamis
140
+ =end
@@ -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,123 @@
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
+ process_direct(name, commands, roles)
33
+ end
34
+
35
+ def transfer(name, source, destination, roles, recursive = true, suppress_and_return_failures = false)
36
+ return transfer_with_gateway(name, source, destination, roles, recursive) if gateway_defined?
37
+ transfer_direct(name, source, destination, roles, recursive)
38
+ end
39
+
40
+ protected
41
+
42
+ def process_with_gateway(name, commands, roles)
43
+ on_gateway do |gateway|
44
+ Array(roles).each { |role| execute_on_role(commands, role, gateway) }
45
+ end
46
+ end
47
+
48
+ def process_direct(name, commands, roles)
49
+ Array(roles).each { |role| execute_on_role(commands, role) }
50
+ end
51
+
52
+ def transfer_with_gateway(name, source, destination, roles, recursive)
53
+ on_gateway do |gateway|
54
+ Array(roles).each { |role| transfer_to_role(source, destination, role, recursive, gateway) }
55
+ end
56
+ end
57
+
58
+ def transfer_direct(name, source, destination, roles, recursive)
59
+ Array(roles).each { |role| transfer_to_role(source, destination, role, recursive) }
60
+ end
61
+
62
+ def execute_on_role(commands, role, gateway = nil)
63
+ hosts = @options[:roles][role]
64
+ Array(hosts).each { |host| execute_on_host(commands, host, gateway) }
65
+ end
66
+
67
+ def transfer_to_role(source, destination, role, gateway = nil)
68
+ hosts = @options[:roles][role]
69
+ Array(hosts).each { |host| transfer_to_host(source, destination, host, gateway) }
70
+ end
71
+
72
+ def execute_on_host(commands, host, gateway = nil)
73
+ if gateway # SSH connection via gateway
74
+ gateway.ssh(host, @options[:user]) do |ssh|
75
+ execute_on_connection(commands, ssh)
76
+ end
77
+ else # direct SSH connection
78
+ Net::SSH.start(host, @options[:user], :password => @options[:password]) do |ssh|
79
+ execute_on_connection(commands, ssh)
80
+ end
81
+ end
82
+ end
83
+
84
+ def execute_on_connection(commands, connection)
85
+ Array(commands).each do |command|
86
+ connection.exec! command do |ch, stream, data|
87
+ logger.send((stream == :stderr ? 'error' : 'debug'), data)
88
+ end
89
+ end
90
+ end
91
+
92
+ def transfer_to_host(source, destination, host, recursive, gateway = nil)
93
+ if gateway # SSH connection via gateway
94
+ gateway.ssh(host, @options[:user]) do |ssh|
95
+ transfer_on_connection(source, destination, recursive, ssh)
96
+ end
97
+ else # direct SSH connection
98
+ Net::SSH.start(host, @options[:user]) do |ssh|
99
+ transfer_on_connection(source, destination, recursive, ssh)
100
+ end
101
+ end
102
+ end
103
+
104
+ def transfer_on_connection(source, destination, recursive, connection)
105
+ scp = Net::SCP.new(connection)
106
+ scp.upload! source, destination, :recursive => recursive
107
+ end
108
+
109
+ private
110
+
111
+ def gateway_defined?
112
+ !! @options[:gateway]
113
+ end
114
+
115
+ def on_gateway(&block)
116
+ gateway = Net::SSH::Gateway.new(@options[:gateway], @options[:user])
117
+ block.call gateway
118
+ ensure
119
+ gateway.shutdown!
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,78 @@
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
+ # Sorry, all transfers are recursive
59
+ def transfer(name, source, destination, roles, recursive = true, suppress_and_return_failures = false) #:nodoc:
60
+ begin
61
+ rsync source, destination
62
+ return true
63
+ rescue ::Vlad::CommandFailedError => e
64
+ return false if suppress_and_return_failures
65
+
66
+ # Reraise error if we're not suppressing it
67
+ raise
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def task_sym(name)
74
+ "install_#{name.to_task_name}".to_sym
75
+ end
76
+ end
77
+ end
78
+ 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