powcloud-sprinkle 0.3.0

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