default.rb 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #
  2. # Author:: Noah Kantrowitz <noah@opscode.com>
  3. # Cookbook Name:: application
  4. # Library:: default
  5. #
  6. # Copyright:: 2011-2012, Opscode, Inc <legal@opscode.com>
  7. #
  8. # Licensed under the Apache License, Version 2.0 (the "License");
  9. # you may not use this file except in compliance with the License.
  10. # You may obtain a copy of the License at
  11. #
  12. # http://www.apache.org/licenses/LICENSE-2.0
  13. #
  14. # Unless required by applicable law or agreed to in writing, software
  15. # distributed under the License is distributed on an "AS IS" BASIS,
  16. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. # See the License for the specific language governing permissions and
  18. # limitations under the License.
  19. #
  20. require "chef/mixin/from_file"
  21. class Chef
  22. class Resource
  23. # Globally update the blocklists to prevent infinite recursion in #to_json and similar
  24. FORBIDDEN_IVARS.concat [:@application, :@application_provider]
  25. HIDDEN_IVARS.concat [:@application, :@application_provider]
  26. class Application
  27. module OptionsCollector
  28. def options
  29. @options ||= {}
  30. end
  31. def method_missing(method_sym, value=nil, &block)
  32. super
  33. rescue NameError
  34. value ||= block
  35. method_sym = method_sym.to_s.chomp('=').to_sym
  36. options[method_sym] = value if value
  37. options[method_sym] ||= nil
  38. end
  39. end
  40. end
  41. module ApplicationBase
  42. def self.included(klass)
  43. klass.actions :before_compile, :before_deploy, :before_migrate, :before_symlink, :before_restart, :after_restart
  44. klass.attribute :id, :kind_of => String, :name_attribute => true
  45. klass.attribute :environment, :kind_of => Hash, :default => {}
  46. klass.attribute :purge_before_symlink, :kind_of => Array, :default => []
  47. klass.attribute :create_dirs_before_symlink, :kind_of => Array, :default => []
  48. klass.attribute :symlinks, :kind_of => Hash, :default => {}
  49. klass.attribute :symlink_before_migrate, :kind_of => Hash, :default => {}
  50. klass.attribute :migration_command, :kind_of => [String, NilClass], :default => nil
  51. klass.attribute :application
  52. klass.attribute :application_provider
  53. klass.attribute :type
  54. end
  55. def restart_command(arg=nil, &block)
  56. arg ||= block
  57. raise "Invalid restart command" unless !arg || arg.is_a?(String) || arg.is_a?(Proc)
  58. @restart_command = arg if arg
  59. @restart_command
  60. end
  61. def method_missing(name, *args)
  62. if application.respond_to? name
  63. application.send(name, *args)
  64. else
  65. super
  66. end
  67. end
  68. class OptionsBlock
  69. include Chef::Resource::Application::OptionsCollector
  70. end
  71. def options_block(options=nil, &block)
  72. options ||= {}
  73. if block
  74. collector = OptionsBlock.new
  75. collector.instance_eval(&block)
  76. options.update(collector.options)
  77. end
  78. options
  79. end
  80. def find_matching_role(role, single=true, &block)
  81. return nil if !role
  82. nodes = []
  83. if node['roles'].include? role
  84. nodes << node
  85. end
  86. if !single || nodes.empty?
  87. search(:node, "role:#{role} AND chef_environment:#{node.chef_environment}") do |n|
  88. nodes << n
  89. end
  90. end
  91. if block
  92. nodes.each do |n|
  93. yield n
  94. end
  95. else
  96. if single
  97. nodes.first
  98. else
  99. nodes
  100. end
  101. end
  102. end
  103. def find_database_server(role)
  104. dbm = find_matching_role(role)
  105. Chef::Log.warn("No node with role #{role}") if role && !dbm
  106. if respond_to?(:database) && database.has_key?('host')
  107. database['host']
  108. elsif dbm && dbm.attribute?('cloud')
  109. dbm['cloud']['local_ipv4']
  110. elsif dbm
  111. dbm['ipaddress']
  112. end
  113. end
  114. end
  115. end
  116. class Provider
  117. module ApplicationBase
  118. def self.included(klass)
  119. klass.send(:include, Chef::Mixin::FromFile)
  120. end
  121. def deploy_provider
  122. @deploy_provider ||= begin
  123. version = Chef::Version.new(Chef::VERSION)
  124. deploy_provider = if version.major > 10 || version.minor >= 14
  125. Chef::Platform.provider_for_resource(@deploy_resource, :nothing)
  126. else
  127. Chef::Platform.provider_for_resource(@deploy_resource)
  128. end
  129. deploy_provider.load_current_resource
  130. deploy_provider
  131. end
  132. end
  133. def release_path
  134. deploy_provider.release_path
  135. end
  136. def shared_path
  137. @deploy_resource.shared_path
  138. end
  139. def callback(what, callback_code=nil)
  140. Chef::Log.debug("Got callback #{what}: #{callback_code.inspect}")
  141. @collection = Chef::ResourceCollection.new
  142. case callback_code
  143. when Proc
  144. Chef::Log.info "#{@new_resource} running callback #{what}"
  145. safe_recipe_eval(&callback_code)
  146. when String
  147. callback_file = "#{release_path}/#{callback_code}"
  148. unless ::File.exist?(callback_file)
  149. raise RuntimeError, "Can't find your callback file #{callback_file}"
  150. end
  151. run_callback_from_file(callback_file)
  152. when nil
  153. nil
  154. else
  155. raise RuntimeError, "You gave me a callback I don't know what to do with: #{callback_code.inspect}"
  156. end
  157. end
  158. def run_callback_from_file(callback_file)
  159. if ::File.exist?(callback_file)
  160. Dir.chdir(release_path) do
  161. Chef::Log.info "#{@new_resource} running deploy hook #{callback_file}"
  162. safe_recipe_eval { from_file(callback_file) }
  163. end
  164. end
  165. end
  166. def safe_recipe_eval(&callback_code)
  167. recipe_eval(&callback_code)
  168. version = Chef::Version.new(Chef::VERSION)
  169. if version.major >= 10 && version.minor >= 14
  170. converge
  171. end
  172. end
  173. end
  174. end
  175. end