engineyard-serverside 1.2.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 (220) hide show
  1. data/LICENSE +19 -0
  2. data/bin/engineyard-serverside +10 -0
  3. data/lib/engineyard-serverside.rb +49 -0
  4. data/lib/engineyard-serverside/bundle_installer.rb +4 -0
  5. data/lib/engineyard-serverside/cli.rb +146 -0
  6. data/lib/engineyard-serverside/configuration.rb +130 -0
  7. data/lib/engineyard-serverside/default_maintenance_page.html +29 -0
  8. data/lib/engineyard-serverside/deploy.rb +321 -0
  9. data/lib/engineyard-serverside/deploy_hook.rb +80 -0
  10. data/lib/engineyard-serverside/lockfile_parser.rb +55 -0
  11. data/lib/engineyard-serverside/logged_output.rb +78 -0
  12. data/lib/engineyard-serverside/server.rb +70 -0
  13. data/lib/engineyard-serverside/strategies/git.rb +136 -0
  14. data/lib/engineyard-serverside/task.rb +62 -0
  15. data/lib/engineyard-serverside/version.rb +3 -0
  16. data/lib/vendor/dataflow/HISTORY +52 -0
  17. data/lib/vendor/dataflow/LICENSE +19 -0
  18. data/lib/vendor/dataflow/README.textile +290 -0
  19. data/lib/vendor/dataflow/Rakefile +36 -0
  20. data/lib/vendor/dataflow/dataflow.rb +120 -0
  21. data/lib/vendor/dataflow/dataflow/actor.rb +22 -0
  22. data/lib/vendor/dataflow/dataflow/equality.rb +28 -0
  23. data/lib/vendor/dataflow/dataflow/future_queue.rb +24 -0
  24. data/lib/vendor/dataflow/dataflow/port.rb +54 -0
  25. data/lib/vendor/dataflow/examples/barrier.rb +9 -0
  26. data/lib/vendor/dataflow/examples/data_driven.rb +17 -0
  27. data/lib/vendor/dataflow/examples/dataflow_http_gets.rb +13 -0
  28. data/lib/vendor/dataflow/examples/flow.rb +20 -0
  29. data/lib/vendor/dataflow/examples/future_http_gets.rb +12 -0
  30. data/lib/vendor/dataflow/examples/future_queue.rb +11 -0
  31. data/lib/vendor/dataflow/examples/instance_variables.rb +15 -0
  32. data/lib/vendor/dataflow/examples/laziness.rb +9 -0
  33. data/lib/vendor/dataflow/examples/local_variables.rb +11 -0
  34. data/lib/vendor/dataflow/examples/messages.rb +26 -0
  35. data/lib/vendor/dataflow/examples/port_http_gets.rb +13 -0
  36. data/lib/vendor/dataflow/examples/port_send.rb +10 -0
  37. data/lib/vendor/dataflow/examples/ring.rb +21 -0
  38. data/lib/vendor/dataflow/spec/actor_spec.rb +28 -0
  39. data/lib/vendor/dataflow/spec/anonymous_variables_spec.rb +21 -0
  40. data/lib/vendor/dataflow/spec/barrier_spec.rb +25 -0
  41. data/lib/vendor/dataflow/spec/by_need_spec.rb +55 -0
  42. data/lib/vendor/dataflow/spec/dataflow_spec.rb +151 -0
  43. data/lib/vendor/dataflow/spec/equality_spec.rb +40 -0
  44. data/lib/vendor/dataflow/spec/flow_spec.rb +25 -0
  45. data/lib/vendor/dataflow/spec/forker_spec.rb +28 -0
  46. data/lib/vendor/dataflow/spec/future_queue_spec.rb +31 -0
  47. data/lib/vendor/dataflow/spec/inspect_spec.rb +19 -0
  48. data/lib/vendor/dataflow/spec/need_later_spec.rb +12 -0
  49. data/lib/vendor/dataflow/spec/port_spec.rb +26 -0
  50. data/lib/vendor/dataflow/spec/spec.opts +1 -0
  51. data/lib/vendor/dataflow/spec/spec_helper.rb +10 -0
  52. data/lib/vendor/escape/Readme +21 -0
  53. data/lib/vendor/escape/doc_include/template/qualitysmith.rb +631 -0
  54. data/lib/vendor/escape/lib/escape.rb +247 -0
  55. data/lib/vendor/json_pure/CHANGES +166 -0
  56. data/lib/vendor/json_pure/COPYING +58 -0
  57. data/lib/vendor/json_pure/GPL +340 -0
  58. data/lib/vendor/json_pure/README +358 -0
  59. data/lib/vendor/json_pure/Rakefile +292 -0
  60. data/lib/vendor/json_pure/TODO +1 -0
  61. data/lib/vendor/json_pure/VERSION +1 -0
  62. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +52 -0
  63. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +1000 -0
  64. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +1001 -0
  65. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +900 -0
  66. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +901 -0
  67. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +1000 -0
  68. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +1001 -0
  69. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +261 -0
  70. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +1000 -0
  71. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +1001 -0
  72. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +1000 -0
  73. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +1001 -0
  74. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +1000 -0
  75. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +1001 -0
  76. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +262 -0
  77. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +1000 -0
  78. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +1001 -0
  79. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +82 -0
  80. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +34 -0
  81. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +900 -0
  82. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +901 -0
  83. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +81 -0
  84. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +1000 -0
  85. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +1001 -0
  86. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +82 -0
  87. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +1000 -0
  88. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +1001 -0
  89. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +82 -0
  90. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +1000 -0
  91. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +1001 -0
  92. data/lib/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +82 -0
  93. data/lib/vendor/json_pure/benchmarks/generator2_benchmark.rb +222 -0
  94. data/lib/vendor/json_pure/benchmarks/generator_benchmark.rb +224 -0
  95. data/lib/vendor/json_pure/benchmarks/ohai.json +1216 -0
  96. data/lib/vendor/json_pure/benchmarks/ohai.ruby +1 -0
  97. data/lib/vendor/json_pure/benchmarks/parser2_benchmark.rb +251 -0
  98. data/lib/vendor/json_pure/benchmarks/parser_benchmark.rb +259 -0
  99. data/lib/vendor/json_pure/bin/edit_json.rb +9 -0
  100. data/lib/vendor/json_pure/bin/prettify_json.rb +75 -0
  101. data/lib/vendor/json_pure/data/example.json +1 -0
  102. data/lib/vendor/json_pure/data/index.html +38 -0
  103. data/lib/vendor/json_pure/data/prototype.js +4184 -0
  104. data/lib/vendor/json_pure/ext/json/ext/generator/extconf.rb +16 -0
  105. data/lib/vendor/json_pure/ext/json/ext/generator/generator.c +1323 -0
  106. data/lib/vendor/json_pure/ext/json/ext/generator/generator.h +170 -0
  107. data/lib/vendor/json_pure/ext/json/ext/parser/extconf.rb +15 -0
  108. data/lib/vendor/json_pure/ext/json/ext/parser/parser.c +1935 -0
  109. data/lib/vendor/json_pure/ext/json/ext/parser/parser.h +71 -0
  110. data/lib/vendor/json_pure/ext/json/ext/parser/parser.rl +792 -0
  111. data/lib/vendor/json_pure/install.rb +26 -0
  112. data/lib/vendor/json_pure/lib/json.rb +10 -0
  113. data/lib/vendor/json_pure/lib/json/Array.xpm +21 -0
  114. data/lib/vendor/json_pure/lib/json/FalseClass.xpm +21 -0
  115. data/lib/vendor/json_pure/lib/json/Hash.xpm +21 -0
  116. data/lib/vendor/json_pure/lib/json/Key.xpm +73 -0
  117. data/lib/vendor/json_pure/lib/json/NilClass.xpm +21 -0
  118. data/lib/vendor/json_pure/lib/json/Numeric.xpm +28 -0
  119. data/lib/vendor/json_pure/lib/json/String.xpm +96 -0
  120. data/lib/vendor/json_pure/lib/json/TrueClass.xpm +21 -0
  121. data/lib/vendor/json_pure/lib/json/add/core.rb +148 -0
  122. data/lib/vendor/json_pure/lib/json/add/rails.rb +58 -0
  123. data/lib/vendor/json_pure/lib/json/common.rb +397 -0
  124. data/lib/vendor/json_pure/lib/json/editor.rb +1371 -0
  125. data/lib/vendor/json_pure/lib/json/ext.rb +15 -0
  126. data/lib/vendor/json_pure/lib/json/json.xpm +1499 -0
  127. data/lib/vendor/json_pure/lib/json/pure.rb +77 -0
  128. data/lib/vendor/json_pure/lib/json/pure/generator.rb +452 -0
  129. data/lib/vendor/json_pure/lib/json/pure/parser.rb +307 -0
  130. data/lib/vendor/json_pure/lib/json/version.rb +8 -0
  131. data/lib/vendor/json_pure/tests/fixtures/fail1.json +1 -0
  132. data/lib/vendor/json_pure/tests/fixtures/fail10.json +1 -0
  133. data/lib/vendor/json_pure/tests/fixtures/fail11.json +1 -0
  134. data/lib/vendor/json_pure/tests/fixtures/fail12.json +1 -0
  135. data/lib/vendor/json_pure/tests/fixtures/fail13.json +1 -0
  136. data/lib/vendor/json_pure/tests/fixtures/fail14.json +1 -0
  137. data/lib/vendor/json_pure/tests/fixtures/fail18.json +1 -0
  138. data/lib/vendor/json_pure/tests/fixtures/fail19.json +1 -0
  139. data/lib/vendor/json_pure/tests/fixtures/fail2.json +1 -0
  140. data/lib/vendor/json_pure/tests/fixtures/fail20.json +1 -0
  141. data/lib/vendor/json_pure/tests/fixtures/fail21.json +1 -0
  142. data/lib/vendor/json_pure/tests/fixtures/fail22.json +1 -0
  143. data/lib/vendor/json_pure/tests/fixtures/fail23.json +1 -0
  144. data/lib/vendor/json_pure/tests/fixtures/fail24.json +1 -0
  145. data/lib/vendor/json_pure/tests/fixtures/fail25.json +1 -0
  146. data/lib/vendor/json_pure/tests/fixtures/fail27.json +2 -0
  147. data/lib/vendor/json_pure/tests/fixtures/fail28.json +2 -0
  148. data/lib/vendor/json_pure/tests/fixtures/fail3.json +1 -0
  149. data/lib/vendor/json_pure/tests/fixtures/fail4.json +1 -0
  150. data/lib/vendor/json_pure/tests/fixtures/fail5.json +1 -0
  151. data/lib/vendor/json_pure/tests/fixtures/fail6.json +1 -0
  152. data/lib/vendor/json_pure/tests/fixtures/fail7.json +1 -0
  153. data/lib/vendor/json_pure/tests/fixtures/fail8.json +1 -0
  154. data/lib/vendor/json_pure/tests/fixtures/fail9.json +1 -0
  155. data/lib/vendor/json_pure/tests/fixtures/pass1.json +56 -0
  156. data/lib/vendor/json_pure/tests/fixtures/pass15.json +1 -0
  157. data/lib/vendor/json_pure/tests/fixtures/pass16.json +1 -0
  158. data/lib/vendor/json_pure/tests/fixtures/pass17.json +1 -0
  159. data/lib/vendor/json_pure/tests/fixtures/pass2.json +1 -0
  160. data/lib/vendor/json_pure/tests/fixtures/pass26.json +1 -0
  161. data/lib/vendor/json_pure/tests/fixtures/pass3.json +6 -0
  162. data/lib/vendor/json_pure/tests/test_json.rb +361 -0
  163. data/lib/vendor/json_pure/tests/test_json_addition.rb +162 -0
  164. data/lib/vendor/json_pure/tests/test_json_encoding.rb +68 -0
  165. data/lib/vendor/json_pure/tests/test_json_fixtures.rb +34 -0
  166. data/lib/vendor/json_pure/tests/test_json_generate.rb +122 -0
  167. data/lib/vendor/json_pure/tests/test_json_rails.rb +144 -0
  168. data/lib/vendor/json_pure/tests/test_json_unicode.rb +76 -0
  169. data/lib/vendor/json_pure/tools/fuzz.rb +139 -0
  170. data/lib/vendor/json_pure/tools/server.rb +61 -0
  171. data/lib/vendor/open4/lib/open4.rb +403 -0
  172. data/lib/vendor/thor/CHANGELOG.rdoc +89 -0
  173. data/lib/vendor/thor/LICENSE +20 -0
  174. data/lib/vendor/thor/README.rdoc +297 -0
  175. data/lib/vendor/thor/Thorfile +69 -0
  176. data/lib/vendor/thor/bin/rake2thor +86 -0
  177. data/lib/vendor/thor/bin/thor +6 -0
  178. data/lib/vendor/thor/lib/thor.rb +244 -0
  179. data/lib/vendor/thor/lib/thor/actions.rb +275 -0
  180. data/lib/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  181. data/lib/vendor/thor/lib/thor/actions/directory.rb +91 -0
  182. data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
  183. data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
  184. data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
  185. data/lib/vendor/thor/lib/thor/base.rb +540 -0
  186. data/lib/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
  187. data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  188. data/lib/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
  189. data/lib/vendor/thor/lib/thor/error.rb +30 -0
  190. data/lib/vendor/thor/lib/thor/group.rb +271 -0
  191. data/lib/vendor/thor/lib/thor/invocation.rb +180 -0
  192. data/lib/vendor/thor/lib/thor/parser.rb +4 -0
  193. data/lib/vendor/thor/lib/thor/parser/argument.rb +67 -0
  194. data/lib/vendor/thor/lib/thor/parser/arguments.rb +150 -0
  195. data/lib/vendor/thor/lib/thor/parser/option.rb +128 -0
  196. data/lib/vendor/thor/lib/thor/parser/options.rb +169 -0
  197. data/lib/vendor/thor/lib/thor/rake_compat.rb +66 -0
  198. data/lib/vendor/thor/lib/thor/runner.rb +314 -0
  199. data/lib/vendor/thor/lib/thor/shell.rb +83 -0
  200. data/lib/vendor/thor/lib/thor/shell/basic.rb +239 -0
  201. data/lib/vendor/thor/lib/thor/shell/color.rb +108 -0
  202. data/lib/vendor/thor/lib/thor/task.rb +102 -0
  203. data/lib/vendor/thor/lib/thor/util.rb +230 -0
  204. data/lib/vendor/thor/lib/thor/version.rb +3 -0
  205. data/lib/vendor/thor/thor.gemspec +120 -0
  206. data/spec/custom_deploy_spec.rb +95 -0
  207. data/spec/deploy_hook_spec.rb +211 -0
  208. data/spec/fixtures/gitrepo.tar.gz +0 -0
  209. data/spec/fixtures/gitrepo/foo +0 -0
  210. data/spec/fixtures/invalid_hook.rb +1 -0
  211. data/spec/fixtures/valid_hook.rb +1 -0
  212. data/spec/git_strategy_spec.rb +22 -0
  213. data/spec/lockfile_parser_spec.rb +30 -0
  214. data/spec/spec_helper.rb +37 -0
  215. data/spec/support/lockfiles/0.9-no-bundler +111 -0
  216. data/spec/support/lockfiles/0.9-with-bundler +117 -0
  217. data/spec/support/lockfiles/1.0-no-bundler +54 -0
  218. data/spec/support/lockfiles/1.0.0.rc.1-with-bundler +162 -0
  219. data/spec/support/lockfiles/not-a-lockfile +10 -0
  220. metadata +279 -0
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Engine Yard, Inc
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ begin
3
+ require 'rubygems'
4
+ rescue LoadError
5
+ end
6
+
7
+ $LOAD_PATH.push(File.expand_path("../lib", File.dirname(__FILE__)))
8
+ require 'engineyard-serverside'
9
+
10
+ EY::CLI.start
@@ -0,0 +1,49 @@
1
+ $LOAD_PATH.push(File.expand_path("engineyard-serverside", File.dirname(__FILE__)))
2
+ $LOAD_PATH.unshift File.expand_path('vendor/thor/lib', File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift File.expand_path('vendor/open4/lib', File.dirname(__FILE__))
4
+ $LOAD_PATH.unshift File.expand_path('vendor/escape/lib', File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift File.expand_path('vendor/json_pure/lib', File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift File.expand_path('vendor/dataflow', File.dirname(__FILE__))
7
+
8
+ require 'escape'
9
+ require 'json'
10
+ require 'dataflow'
11
+
12
+ require 'version'
13
+ require 'strategies/git'
14
+ require 'task'
15
+ require 'server'
16
+ require 'deploy'
17
+ require 'deploy_hook'
18
+ require 'lockfile_parser'
19
+ require 'bundle_installer'
20
+ require 'cli'
21
+ require 'configuration'
22
+
23
+ module EY
24
+ def self.node
25
+ @node ||= deep_indifferentize(JSON.parse(dna_json))
26
+ end
27
+
28
+ def self.dna_json
29
+ @dna_json ||= `sudo cat /etc/chef/dna.json`
30
+ end
31
+
32
+ RemoteFailure = Class.new StandardError
33
+
34
+ private
35
+ def self.deep_indifferentize(thing)
36
+ if thing.kind_of?(Hash)
37
+ indifferent_hash = Thor::CoreExt::HashWithIndifferentAccess.new
38
+ thing.each do |k, v|
39
+ indifferent_hash[k] = deep_indifferentize(v)
40
+ end
41
+ indifferent_hash
42
+ elsif thing.kind_of?(Array)
43
+ thing.map {|x| deep_indifferentize(x)}
44
+ else
45
+ thing
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,4 @@
1
+ module EY
2
+ class BundleInstaller < Struct.new(:version, :options)
3
+ end
4
+ end
@@ -0,0 +1,146 @@
1
+ require 'thor'
2
+
3
+ module EY
4
+ class CLI < Thor
5
+ include Dataflow
6
+
7
+ def self.start(*)
8
+ super
9
+ rescue RemoteFailure
10
+ exit(1)
11
+ end
12
+
13
+ method_option :migrate, :type => :string,
14
+ :desc => "Run migrations with this deploy",
15
+ :aliases => ["-m"]
16
+
17
+ method_option :branch, :type => :string,
18
+ :desc => "Git ref to deploy, defaults to master. May be a branch, a tag, or a SHA",
19
+ :aliases => %w[-b --ref --tag]
20
+
21
+ method_option :repo, :type => :string,
22
+ :desc => "Remote repo to deploy",
23
+ :aliases => ["-r"]
24
+
25
+ method_option :app, :type => :string,
26
+ :required => true,
27
+ :desc => "Application to deploy",
28
+ :aliases => ["-a"]
29
+
30
+ method_option :framework_env, :type => :string,
31
+ :required => true,
32
+ :desc => "Ruby web framework environment",
33
+ :aliases => ["-e"]
34
+
35
+ method_option :config, :type => :string,
36
+ :desc => "Additional configuration"
37
+
38
+ method_option :stack, :type => :string,
39
+ :desc => "Web stack (so we can restart it correctly)"
40
+
41
+ method_option :instances, :type => :array,
42
+ :desc => "Instances in cluster"
43
+
44
+ method_option :verbose, :type => :boolean,
45
+ :default => false,
46
+ :desc => "Verbose output",
47
+ :aliases => ["-v"]
48
+
49
+ desc "deploy", "Deploy code from /data/<app>"
50
+ def deploy(default_task=:deploy)
51
+ EY::Server.all = parse_instances(options[:instances])
52
+ EY::LoggedOutput.verbose = options[:verbose]
53
+ EY::LoggedOutput.logfile = File.join(ENV['HOME'], "#{options[:app]}-deploy.log")
54
+
55
+ invoke :propagate
56
+ EY::Deploy.run(options.merge("default_task" => default_task))
57
+ end
58
+
59
+ method_option :app, :type => :string,
60
+ :required => true,
61
+ :desc => "Which application's hooks to run",
62
+ :aliases => ["-a"]
63
+
64
+ method_option :release_path, :type => :string,
65
+ :desc => "Value for #release_path in hooks (mostly for internal coordination)",
66
+ :aliases => ["-r"]
67
+
68
+ method_option :current_role, :type => :string,
69
+ :desc => "Value for #current_role in hooks"
70
+
71
+ method_option :framework_env, :type => :string,
72
+ :required => true,
73
+ :desc => "Ruby web framework environment",
74
+ :aliases => ["-e"]
75
+
76
+ method_option :config, :type => :string,
77
+ :desc => "Additional configuration"
78
+
79
+ method_option :current_name, :type => :string,
80
+ :desc => "Value for #current_name in hooks"
81
+
82
+ desc "hook [NAME]", "Run a particular deploy hook"
83
+ def hook(hook_name)
84
+ EY::DeployHook.new(options).run(hook_name)
85
+ end
86
+
87
+ desc "install_bundler [VERSION]", "Make sure VERSION of bundler is installed (in system ruby)"
88
+ def install_bundler(version)
89
+ egrep_escaped_version = version.gsub(/\./, '\.')
90
+ # the grep "bundler " is so that gems like bundler08 don't get
91
+ # their versions considered too
92
+ #
93
+ # the [,$] is to stop us from looking for e.g. 0.9.2, seeing
94
+ # 0.9.22, and mistakenly thinking 0.9.2 is there
95
+ has_bundler_cmd = "gem list bundler | grep \"bundler \" | egrep -q '#{egrep_escaped_version}[,)]'"
96
+
97
+ unless system(has_bundler_cmd)
98
+ system("gem install bundler -q --no-rdoc --no-ri -v '#{version}'")
99
+ end
100
+ end
101
+
102
+ desc "propagate", "Propagate the engineyard-serverside gem to the other instances in the cluster. This will install exactly version #{VERSION} and remove other versions if found."
103
+ def propagate
104
+ config = EY::Deploy::Configuration.new
105
+ gem_filename = "engineyard-serverside-#{VERSION}.gem"
106
+ local_gem_file = File.join(Gem.dir, 'cache', gem_filename)
107
+ remote_gem_file = File.join(Dir.tmpdir, gem_filename)
108
+ gem_binary = File.join(Gem.default_bindir, 'gem')
109
+
110
+ EY::Server.config = config
111
+
112
+ barrier(*(EY::Server.all.find_all do |server|
113
+ !server.local? # of course this machine has it
114
+ end.map do |server|
115
+ need_later do
116
+ egrep_escaped_version = VERSION.gsub(/\./, '\.')
117
+ # the [,)] is to stop us from looking for e.g. 0.5.1, seeing
118
+ # 0.5.11, and mistakenly thinking 0.5.1 is there
119
+ has_gem_cmd = "#{gem_binary} list engineyard-serverside | grep \"engineyard-serverside\" | egrep -q '#{egrep_escaped_version}[,)]'"
120
+
121
+ if !server.run(has_gem_cmd) # doesn't have this exact version
122
+ puts "~> Installing engineyard-serverside on #{server.hostname}"
123
+
124
+ system(Escape.shell_command([
125
+ 'scp', '-i', "#{ENV['HOME']}/.ssh/internal",
126
+ "-o", "StrictHostKeyChecking=no",
127
+ local_gem_file,
128
+ "#{config.user}@#{server.hostname}:#{remote_gem_file}",
129
+ ]))
130
+ server.run("sudo #{gem_binary} install --no-rdoc --no-ri '#{remote_gem_file}'")
131
+ end
132
+ end
133
+ end))
134
+ end
135
+
136
+ private
137
+
138
+ def parse_instances(instance_strings)
139
+ instance_strings.map do |s|
140
+ tuple = s.split(/,/)
141
+ {:hostname => tuple[0], :role => tuple[1], :name => tuple[2]}
142
+ end
143
+ end
144
+
145
+ end
146
+ end
@@ -0,0 +1,130 @@
1
+ require 'json'
2
+ require 'thor'
3
+
4
+ module EY
5
+ class Deploy::Configuration
6
+ DEFAULT_CONFIG = Thor::CoreExt::HashWithIndifferentAccess.new({
7
+ "branch" => "master",
8
+ "strategy" => "Git",
9
+ })
10
+
11
+ attr_reader :configuration
12
+ alias :c :configuration
13
+
14
+ attr_writer :release_path
15
+
16
+ def initialize(opts={})
17
+ @release_path = opts[:release_path]
18
+ config = JSON.parse(opts["config"] || "{}")
19
+ @configuration = DEFAULT_CONFIG.merge(config).merge(opts)
20
+ end
21
+
22
+ # Delegate to the configuration objects
23
+ def method_missing(meth, *args, &blk)
24
+ c.key?(meth.to_s) ? c[meth.to_s] : super
25
+ end
26
+
27
+ def respond_to?(meth, include_private=false)
28
+ c.key?(meth.to_s) ? true : super
29
+ end
30
+
31
+ def [](key)
32
+ if respond_to?(key.to_sym)
33
+ send(key.to_sym)
34
+ else
35
+ c[key]
36
+ end
37
+ end
38
+
39
+ def has_key?(key)
40
+ if respond_to?(key.to_sym)
41
+ true
42
+ else
43
+ c.has_key?(key)
44
+ end
45
+ end
46
+
47
+ def node
48
+ EY.node
49
+ end
50
+
51
+ def revision
52
+ IO.read(File.join(latest_release, 'REVISION'))
53
+ end
54
+
55
+ def repository_cache
56
+ configuration['repository_cache'] || File.join(deploy_to, "/shared/cached-copy")
57
+ end
58
+
59
+ def deploy_to
60
+ configuration['deploy_to'] || "/data/#{app}"
61
+ end
62
+
63
+ def migrate?
64
+ !!configuration['migrate']
65
+ end
66
+
67
+ def migration_command
68
+ configuration['migrate'] == "migrate" ? DEFAULT_CONFIG["migrate"] : configuration['migrate']
69
+ end
70
+
71
+ def user
72
+ ENV['USER']
73
+ end
74
+ alias :group :user
75
+
76
+ def role
77
+ node['instance_role']
78
+ end
79
+
80
+ def copy_exclude
81
+ @copy_exclude ||= Array(configuration.fetch("copy_exclude", []))
82
+ end
83
+
84
+ def environment
85
+ configuration['framework_env']
86
+ end
87
+
88
+ def latest_release
89
+ all_releases.last
90
+ end
91
+
92
+ def previous_release(current=latest_release)
93
+ index = all_releases.index(current)
94
+ all_releases[index-1]
95
+ end
96
+
97
+ def oldest_release
98
+ all_releases.first
99
+ end
100
+
101
+ def all_releases
102
+ Dir.glob("#{release_dir}/*").sort
103
+ end
104
+
105
+ def framework_envs
106
+ "RAILS_ENV=#{environment} RACK_ENV=#{environment} MERB_ENV=#{environment}"
107
+ end
108
+
109
+ def current_path
110
+ File.join(deploy_to, "current")
111
+ end
112
+
113
+ def shared_path
114
+ File.join(deploy_to, "shared")
115
+ end
116
+
117
+ def release_dir
118
+ File.join(deploy_to, "releases")
119
+ end
120
+
121
+ def release_path
122
+ @release_path ||= File.join(release_dir, Time.now.utc.strftime("%Y%m%d%H%M%S"))
123
+ end
124
+
125
+ def exclusions
126
+ copy_exclude.map { |e| %|--exclude="#{e}"| }.join(' ')
127
+ end
128
+
129
+ end
130
+ end
@@ -0,0 +1,29 @@
1
+ <!DOCTYPE html >
2
+ <html>
3
+ <head>
4
+ <title>Undergoing Maintenance</title>
5
+
6
+ <style type="text/css">
7
+ body{font-size: 75%;font-family: Helvetica,Arial,sans-serif;color:#333;background:#FDFDFD;}
8
+ .container{font-size:1.1em;width:700px;text-align:center;margin:80px auto;}
9
+ .message{background:#FFF;border:1px solid #EEE;padding:30px;}
10
+ h1{margin:0 0 0.5em;font-weight:normal;}
11
+ p{margin:0;line-height:1.75em;}
12
+ .foot{color:#999;margin-top:30px}
13
+ .foot a{color:#666;text-decoration:none}
14
+ </style>
15
+ </head>
16
+
17
+ <body>
18
+ <div class="container">
19
+ <div class="message">
20
+ <h1>This site is currently undergoing some maintenance.</h1>
21
+ <p>Customize this maintenance page by updating the file located at: /public/maintenance.html</p>
22
+ </div>
23
+ <div class="foot">
24
+ Hosted by <a href="http://www.engineyard.com">Engine Yard</a>
25
+ </div>
26
+ </div>
27
+ </body>
28
+
29
+ </html>
@@ -0,0 +1,321 @@
1
+ # stolen wholesale from capistrano, thanks Jamis!
2
+ require 'base64'
3
+ require 'fileutils'
4
+ require 'json'
5
+
6
+ module EY
7
+ class DeployBase < Task
8
+ include LoggedOutput
9
+
10
+ # default task
11
+ def deploy
12
+ debug "Starting deploy at #{Time.now.asctime}"
13
+ update_repository_cache
14
+ require_custom_tasks
15
+ push_code
16
+
17
+ info "~> Starting full deploy"
18
+ copy_repository_cache
19
+
20
+ with_failed_release_cleanup do
21
+ create_revision_file
22
+ bundle
23
+ symlink_configs
24
+ conditionally_enable_maintenance_page
25
+ run_with_callbacks(:migrate)
26
+ callback(:before_symlink)
27
+ symlink
28
+ end
29
+
30
+ callback(:after_symlink)
31
+ run_with_callbacks(:restart)
32
+ disable_maintenance_page
33
+
34
+ cleanup_old_releases
35
+ debug "Finished deploy at #{Time.now.asctime}"
36
+ rescue Exception
37
+ debug "Finished failing to deploy at #{Time.now.asctime}"
38
+ puts_deploy_failure
39
+ raise
40
+ end
41
+
42
+ def enable_maintenance_page
43
+ maintenance_page_candidates = [
44
+ "public/maintenance.html.custom",
45
+ "public/maintenance.html.tmp",
46
+ "public/maintenance.html",
47
+ "public/system/maintenance.html.default",
48
+ ].map do |file|
49
+ File.join(c.latest_release, file)
50
+ end
51
+
52
+ # this one is guaranteed to exist
53
+ maintenance_page_candidates << File.expand_path(
54
+ "default_maintenance_page.html",
55
+ File.dirname(__FILE__)
56
+ )
57
+
58
+ # put in the maintenance page
59
+ maintenance_file = maintenance_page_candidates.detect do |file|
60
+ File.exists?(file)
61
+ end
62
+
63
+ @maintenance_up = true
64
+ roles :app_master, :app, :solo do
65
+ visible_maint_page = File.join(c.shared_path, "system", "maintenance.html")
66
+ run "cp '#{maintenance_file}' '#{visible_maint_page}'"
67
+ end
68
+ end
69
+
70
+ def conditionally_enable_maintenance_page
71
+ if c.migrate? || c.stack == "nginx_mongrel"
72
+ enable_maintenance_page
73
+ end
74
+ end
75
+
76
+ def disable_maintenance_page
77
+ @maintenance_up = false
78
+ roles :app_master, :app, :solo do
79
+ run "rm -f #{File.join(c.shared_path, "system", "maintenance.html")}"
80
+ end
81
+ end
82
+
83
+ def run_with_callbacks(task, *args)
84
+ callback(:"before_#{task}")
85
+ send(task, *args)
86
+ callback(:"after_#{task}")
87
+ end
88
+
89
+ # task
90
+ def push_code
91
+ info "~> Pushing code to all servers"
92
+ barrier *(EY::Server.all.map do |server|
93
+ need_later { server.push_code }
94
+ end)
95
+ end
96
+
97
+ # task
98
+ def restart
99
+ @restart_failed = true
100
+ info "~> Restarting app servers"
101
+ roles :app_master, :app, :solo do
102
+ restart_command = case c.stack
103
+ when "nginx_unicorn"
104
+ pidfile = "/var/run/engineyard/unicorn_#{c.app}.pid"
105
+ condition = "[ -e #{pidfile} ] && [ ! -d /proc/`cat #{pidfile}` ]"
106
+ run("if #{condition}; then rm -f #{pidfile}; fi")
107
+ run("/engineyard/bin/app_#{c.app} deploy")
108
+ when "nginx_mongrel"
109
+ sudo("monit restart all -g #{c.app}")
110
+ when "nginx_passenger"
111
+ run("touch #{c.current_path}/tmp/restart.txt")
112
+ else
113
+ raise "Unknown stack #{c.stack}; restart failed!"
114
+ end
115
+ end
116
+ @restart_failed = false
117
+ end
118
+
119
+ # task
120
+ def bundle
121
+ if File.exist?("#{c.release_path}/Gemfile")
122
+ info "~> Gemfile detected, bundling gems"
123
+ lockfile = File.join(c.release_path, "Gemfile.lock")
124
+
125
+ bundler_installer = if File.exist?(lockfile)
126
+ get_bundler_installer(lockfile)
127
+ else
128
+ warn_about_missing_lockfile
129
+ BundleInstaller.new(DEFAULT_09_BUNDLER, "--without=development --without=test")
130
+ end
131
+
132
+ sudo "#{$0} _#{VERSION}_ install_bundler #{bundler_installer.version}"
133
+
134
+ run "cd #{c.release_path} && bundle _#{bundler_installer.version}_ install #{bundler_installer.options}"
135
+ end
136
+ end
137
+
138
+ # task
139
+ def cleanup_old_releases
140
+ @cleanup_failed = true
141
+ info "~> Cleaning up old releases"
142
+ sudo "ls #{c.release_dir} | head -n -3 | xargs -I{} rm -rf #{c.release_dir}/{}"
143
+ @cleanup_failed = false
144
+ end
145
+
146
+ # task
147
+ def rollback
148
+ if c.all_releases.size > 1
149
+ c.release_path = c.previous_release
150
+
151
+ revision = File.read(File.join(c.release_path, 'REVISION')).strip
152
+ info "~> Rolling back to previous release: #{short_log_message(revision)}"
153
+
154
+ run_with_callbacks(:symlink, c.previous_release)
155
+ cleanup_current_release
156
+ bundle
157
+ info "~> Restarting with previous release"
158
+ with_maintenance_page { run_with_callbacks(:restart) }
159
+ else
160
+ info "~> Already at oldest release, nothing to roll back to"
161
+ exit(1)
162
+ end
163
+ end
164
+
165
+ # task
166
+ def migrate
167
+ return unless c.migrate?
168
+ @migrations_reached = true
169
+ roles :app_master, :solo do
170
+ cmd = "cd #{c.release_path} && #{c.framework_envs} #{c.migration_command}"
171
+ info "~> Migrating: #{cmd}"
172
+ run(cmd)
173
+ end
174
+ end
175
+
176
+ # task
177
+ def copy_repository_cache
178
+ info "~> Copying to #{c.release_path}"
179
+ run("mkdir -p #{c.release_path} && rsync -aq #{c.exclusions} #{c.repository_cache}/ #{c.release_path}")
180
+
181
+ info "~> Ensuring proper ownership"
182
+ sudo("chown -R #{c.user}:#{c.group} #{c.deploy_to}")
183
+ end
184
+
185
+ def create_revision_file
186
+ run create_revision_file_command
187
+ end
188
+
189
+ def symlink_configs(release_to_link=c.release_path)
190
+ info "~> Symlinking configs"
191
+ [ "chmod -R g+w #{release_to_link}",
192
+ "rm -rf #{release_to_link}/log #{release_to_link}/public/system #{release_to_link}/tmp/pids",
193
+ "mkdir -p #{release_to_link}/tmp",
194
+ "ln -nfs #{c.shared_path}/log #{release_to_link}/log",
195
+ "mkdir -p #{release_to_link}/public",
196
+ "mkdir -p #{release_to_link}/config",
197
+ "ln -nfs #{c.shared_path}/system #{release_to_link}/public/system",
198
+ "ln -nfs #{c.shared_path}/pids #{release_to_link}/tmp/pids",
199
+ "ln -nfs #{c.shared_path}/config/database.yml #{release_to_link}/config/database.yml",
200
+ "ln -nfs #{c.shared_path}/config/mongrel_cluster.yml #{release_to_link}/config/mongrel_cluster.yml",
201
+ ].each do |cmd|
202
+ run cmd
203
+ end
204
+
205
+ sudo "chown -R #{c.user}:#{c.group} #{release_to_link}"
206
+ run "if [ -f \"#{c.shared_path}/config/newrelic.yml\" ]; then ln -nfs #{c.shared_path}/config/newrelic.yml #{release_to_link}/config/newrelic.yml; fi"
207
+ end
208
+
209
+ # task
210
+ def symlink(release_to_link=c.release_path)
211
+ info "~> Symlinking code"
212
+ run "rm -f #{c.current_path} && ln -nfs #{release_to_link} #{c.current_path} && chown -R #{c.user}:#{c.group} #{c.current_path}"
213
+ @symlink_changed = true
214
+ rescue Exception
215
+ sudo "rm -f #{c.current_path} && ln -nfs #{c.previous_release(release_to_link)} #{c.current_path} && chown -R #{c.user}:#{c.group} #{c.current_path}"
216
+ @symlink_changed = false
217
+ raise
218
+ end
219
+
220
+ def callback(what)
221
+ @callbacks_reached ||= true
222
+ if File.exist?("#{c.release_path}/deploy/#{what}.rb")
223
+ eydeploy_path = $0 # invoke others just like we were invoked
224
+ run "#{eydeploy_path} _#{VERSION}_ hook '#{what}' --app '#{config.app}' --release-path #{config.release_path}" do |server, cmd|
225
+ cmd << " --framework-env '#{c.environment}'"
226
+ cmd << " --current-role '#{server.role}'"
227
+ cmd << " --current-name '#{server.name}'" if server.name
228
+ cmd << " --config '#{c[:config]}'" if c.has_key?(:config)
229
+ cmd
230
+ end
231
+ end
232
+ end
233
+
234
+ protected
235
+
236
+ def puts_deploy_failure
237
+ if @cleanup_failed
238
+ info "~> [Relax] Your site is running new code, but cleaning up old deploys failed"
239
+ elsif @maintenance_up
240
+ info "~> [Attention] Maintenance page still up, consider the following before removing:"
241
+ info " * any deploy hooks ran, be careful if they were destructive" if @callbacks_reached
242
+ info " * any migrations ran, be careful if they were destructive" if @migrations_reached
243
+ if @symlink_changed
244
+ info " * your new code is symlinked as current"
245
+ else
246
+ info " * your old code is still symlinked as current"
247
+ end
248
+ info " * application servers failed to restart" if @restart_failed
249
+ else
250
+ info "~> [Relax] Your site is still running old code and nothing destructive could have occurred"
251
+ end
252
+ end
253
+
254
+ def with_maintenance_page
255
+ conditionally_enable_maintenance_page
256
+ yield if block_given?
257
+ disable_maintenance_page
258
+ end
259
+
260
+ def with_failed_release_cleanup
261
+ yield
262
+ rescue Exception
263
+ cleanup_current_release
264
+ raise
265
+ end
266
+
267
+ def cleanup_current_release
268
+ sudo "rm -rf #{c.release_path}"
269
+ end
270
+
271
+ DEFAULT_09_BUNDLER = '0.9.26'
272
+ DEFAULT_10_BUNDLER = '1.0.0.rc.3'
273
+
274
+ def warn_about_missing_lockfile
275
+ info "!>"
276
+ info "!> WARNING: Gemfile.lock is missing!"
277
+ info "!> You can get different gems in production than what you tested with."
278
+ info "!> You can get different gems on every deployment even if your Gemfile hasn't changed."
279
+ info "!> Deploying may take a long time."
280
+ info "!>"
281
+ info "!> Fix this by running \"git add Gemfile.lock; git commit\" and deploying again."
282
+ info "!> If you don't have a Gemfile.lock, run \"bundle lock\" to create one."
283
+ info "!>"
284
+ info "!> This deployment will use bundler #{DEFAULT_09_BUNDLER} to run 'bundle install'."
285
+ info "!>"
286
+ end
287
+
288
+ def get_bundler_installer(lockfile)
289
+ parser = LockfileParser.new(File.read(lockfile))
290
+ case parser.lockfile_version
291
+ when :bundler09
292
+ BundleInstaller.new(
293
+ parser.bundler_version || DEFAULT_09_BUNDLER,
294
+ "--without=development --without=test")
295
+ when :bundler10
296
+ BundleInstaller.new(
297
+ parser.bundler_version || DEFAULT_10_BUNDLER,
298
+ "--deployment --path #{c.shared_path}/bundled_gems --without development test"
299
+ )
300
+ else
301
+ raise "Unknown lockfile version #{parser.lockfile_version}"
302
+ end
303
+ end
304
+ public :get_bundler_installer
305
+
306
+ end # DeployBase
307
+
308
+ class Deploy < DeployBase
309
+ def self.new(opts={})
310
+ # include the correct fetch strategy
311
+ include EY::Strategies.const_get(opts.strategy)::Helpers
312
+ super
313
+ end
314
+
315
+ def self.run(opts={})
316
+ conf = EY::Deploy::Configuration.new(opts)
317
+ EY::Server.config = conf
318
+ new(conf).send(opts["default_task"])
319
+ end
320
+ end
321
+ end