190 lines
5.4 KiB
Ruby
190 lines
5.4 KiB
Ruby
#
|
|
# Author:: Noah Kantrowitz <noah@opscode.com>
|
|
# Cookbook Name:: application
|
|
# Library:: default
|
|
#
|
|
# Copyright:: 2011-2012, Opscode, Inc <legal@opscode.com>
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
|
|
require "chef/mixin/from_file"
|
|
|
|
class Chef
|
|
class Resource
|
|
# Monkey-Patch the blacklists to prevent infinite recursion in #to_json and similar
|
|
# (this is global state,thus the set-union operator to change it idempotently + to not leak)
|
|
[ :@application, :@application_provider ].each do |ivar|
|
|
FORBIDDEN_IVARS << ivar unless FORBIDDEN_IVARS.include?(ivar)
|
|
HIDDEN_IVARS << ivar unless HIDDEN_IVARS.include?(ivar)
|
|
end
|
|
end
|
|
end
|
|
|
|
class ApplicationCookbook
|
|
|
|
module OptionsCollector
|
|
def options
|
|
@options ||= {}
|
|
end
|
|
|
|
def method_missing(method_sym, value=nil, &block)
|
|
super
|
|
rescue NameError
|
|
value ||= block
|
|
method_sym = method_sym.to_s.chomp('=').to_sym
|
|
options[method_sym] = value if value
|
|
options[method_sym] ||= nil
|
|
end
|
|
end
|
|
|
|
module ResourceBase
|
|
def self.included(klass)
|
|
klass.actions :before_compile, :before_deploy, :before_migrate, :before_symlink, :before_restart, :after_restart
|
|
klass.attribute :id, :kind_of => String, :name_attribute => true
|
|
klass.attribute :environment, :kind_of => Hash, :default => {}
|
|
klass.attribute :purge_before_symlink, :kind_of => Array, :default => []
|
|
klass.attribute :create_dirs_before_symlink, :kind_of => Array, :default => []
|
|
klass.attribute :symlinks, :kind_of => Hash, :default => {}
|
|
klass.attribute :symlink_before_migrate, :kind_of => Hash, :default => {}
|
|
klass.attribute :migration_command, :kind_of => [String, NilClass], :default => nil
|
|
klass.attribute :application
|
|
klass.attribute :application_provider
|
|
klass.attribute :type
|
|
end
|
|
|
|
def restart_command(arg=nil, &block)
|
|
arg ||= block
|
|
raise "Invalid restart command" unless !arg || arg.is_a?(String) || arg.is_a?(Proc)
|
|
@restart_command = arg if arg
|
|
@restart_command
|
|
end
|
|
|
|
def method_missing(name, *args)
|
|
if application.respond_to? name
|
|
application.send(name, *args)
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
class OptionsBlock
|
|
include ApplicationCookbook::OptionsCollector
|
|
end
|
|
|
|
def options_block(options=nil, &block)
|
|
options ||= {}
|
|
if block
|
|
collector = OptionsBlock.new
|
|
collector.instance_eval(&block)
|
|
options.update(collector.options)
|
|
end
|
|
options
|
|
end
|
|
|
|
def find_matching_role(role, single=true, &block)
|
|
return nil if !role
|
|
nodes = []
|
|
if node['roles'].include? role
|
|
nodes << node
|
|
end
|
|
if !single || nodes.empty?
|
|
search(:node, "role:#{role} AND chef_environment:#{node.chef_environment}") do |n|
|
|
nodes << n
|
|
end
|
|
end
|
|
if block
|
|
nodes.each do |n|
|
|
yield n
|
|
end
|
|
else
|
|
if single
|
|
nodes.first
|
|
else
|
|
nodes
|
|
end
|
|
end
|
|
end
|
|
|
|
def find_database_server(role)
|
|
dbm = find_matching_role(role)
|
|
Chef::Log.warn("No node with role #{role}") if role && !dbm
|
|
|
|
if respond_to?(:database) && database.has_key?('host')
|
|
database['host']
|
|
elsif dbm && dbm.attribute?('cloud')
|
|
dbm['cloud']['local_ipv4']
|
|
elsif dbm
|
|
dbm['ipaddress']
|
|
end
|
|
end
|
|
end
|
|
|
|
module ProviderBase
|
|
|
|
def self.included(klass)
|
|
klass.send(:include, Chef::Mixin::FromFile)
|
|
end
|
|
|
|
def deploy_provider
|
|
@deploy_provider ||= begin
|
|
provider = @deploy_resource.provider_for_action(:nothing)
|
|
provider.load_current_resource
|
|
provider
|
|
end
|
|
end
|
|
|
|
def release_path
|
|
deploy_provider.release_path
|
|
end
|
|
|
|
def shared_path
|
|
@deploy_resource.shared_path
|
|
end
|
|
|
|
def callback(what, callback_code=nil)
|
|
Chef::Log.debug("Got callback #{what}: #{callback_code.inspect}")
|
|
@collection = Chef::ResourceCollection.new
|
|
case callback_code
|
|
when Proc
|
|
Chef::Log.info "#{@new_resource} running callback #{what}"
|
|
safe_recipe_eval(&callback_code)
|
|
when String
|
|
callback_file = "#{release_path}/#{callback_code}"
|
|
unless ::File.exist?(callback_file)
|
|
raise RuntimeError, "Can't find your callback file #{callback_file}"
|
|
end
|
|
run_callback_from_file(callback_file)
|
|
when nil
|
|
nil
|
|
else
|
|
raise RuntimeError, "You gave me a callback I don't know what to do with: #{callback_code.inspect}"
|
|
end
|
|
end
|
|
|
|
def run_callback_from_file(callback_file)
|
|
if ::File.exist?(callback_file)
|
|
Dir.chdir(release_path) do
|
|
Chef::Log.info "#{@new_resource} running deploy hook #{callback_file}"
|
|
safe_recipe_eval { from_file(callback_file) }
|
|
end
|
|
end
|
|
end
|
|
|
|
def safe_recipe_eval(&callback_code)
|
|
recipe_eval(&callback_code)
|
|
converge if respond_to?(:converge)
|
|
end
|
|
end
|
|
end
|