module Poise::Helpers::Subresources::Container

A resource mixin for subresource containers.

@since 1.0.0

Attributes

subcontexts[R]
subresources[R]

Public Class Methods

new(*args) click to toggle source
Calls superclass method
# File lib/poise/helpers/subresources/container.rb, line 49
def initialize(*args)
  super
  @subresources = NoPrintingResourceCollection.new
  @subcontexts = []
end

Public Instance Methods

after_created() click to toggle source
Calls superclass method
# File lib/poise/helpers/subresources/container.rb, line 55
def after_created
  super
  # Register as a default container if needed.
  Poise::Helpers::Subresources::DefaultContainers.register!(self, run_context) if self.class.container_default
  # Add all internal subresources to the resource collection.
  unless @subresources.empty?
    Chef::Log.debug("[#{self}] Adding subresources to collection:")
    # Because after_create is run before adding the container to the resource collection
    # we need to jump through some hoops to get it swapped into place.
    self_ = self
    order_fixer = Chef::Resource::RubyBlock.new('subresource_order_fixer', @run_context)
    # respond_to? is for <= 12.0.2, remove some day when I stop caring.
    order_fixer.declared_type = 'ruby_block' if order_fixer.respond_to?(:declared_type=)
    order_fixer.block do
      Chef::Log.debug("[#{self_}] Running order fixer")
      collection = self_.run_context.resource_collection
      # Delete the current container resource from its current position.
      collection.all_resources.delete(self_)
      # Replace the order fixer with the container so it runs before all
      # subresources.
      collection.all_resources[collection.iterator.position] = self_
      # Hack for Chef 11 to reset the resources_by_name position too.
      # @todo Remove this when I drop support for Chef 11.
      if resources_by_name = collection.instance_variable_get(:@resources_by_name)
        resources_by_name[self_.to_s] = collection.iterator.position
      end
      # Step back so we re-run the "current" resource, which is now the
      # container.
      collection.iterator.skip_back
      Chef::Log.debug("Collection: #{@run_context.resource_collection.map(&:to_s).join(', ')}")
    end
    @run_context.resource_collection.insert(order_fixer)
    @subcontexts.each do |ctx|
      # Copy all resources to the outer context.
      ctx.resource_collection.each do |r|
        Chef::Log.debug("   * #{r}")
        # Fix the subresource to use the outer run context.
        r.run_context = @run_context
        @run_context.resource_collection.insert(r)
      end
      # Copy all notifications to the outer context.
      %w{immediate delayed}.each do |notification_type|
        ctx.send(:"#{notification_type}_notification_collection").each do |key, notifications|
          notifications.each do |notification|
            parent_notifications = @run_context.send(:"#{notification_type}_notification_collection")[key]
            unless parent_notifications.any? { |existing_notification| existing_notification.duplicates?(notification) }
              parent_notifications << notification
            end
          end
        end
      end
    end
    Chef::Log.debug("Collection: #{@run_context.resource_collection.map(&:to_s).join(', ')}")
  end
end
declare_resource(type, name, created_at=nil, &block) click to toggle source
Calls superclass method
# File lib/poise/helpers/subresources/container.rb, line 111
def declare_resource(type, name, created_at=nil, &block)
  Chef::Log.debug("[#{self}] Creating subresource from #{type}(#{name})")
  self_ = self
  # Used to break block context, non-local return from subcontext_block.
  resource = []
  # Grab the caller so we can make the subresource look like it comes from
  # correct place.
  created_at ||= caller[0]
  # Run this inside a subcontext to avoid adding to the current resource collection.
  # It will end up added later, indirected via @subresources to ensure ordering.
  @subcontexts << subcontext_block do
    namespace = if self.class.container_namespace == true
      # If the value is true, use the name of the container resource.
      self.name
    elsif self.class.container_namespace.is_a?(Proc)
      instance_eval(&self.class.container_namespace)
    else
      self.class.container_namespace
    end
    sub_name = if name && !name.empty?
      if namespace
        "#{namespace}::#{name}"
      else
        name
      end
    else
      # If you pass in nil or '', you just get the namespace or parent name.
      namespace || self.name
    end
    resource << super(type, sub_name, created_at) do
      # Apply the correct parent before anything else so it is available
      # in after_created for the subresource. It might raise
      # NoMethodError is there isn't a real parent.
      begin
        parent(self_) if respond_to?(:parent)
      rescue NoMethodError
        # This space left intentionally blank.
      end
      # Run the resource block.
      instance_exec(&block) if block
    end
  end
  # Try and add to subresources. For normal subresources this is handled
  # in the after_created.
  register_subresource(resource.first) if resource.first
  # Return whatever we have
  resource.first
end
register_subresource(resource) click to toggle source

Register a resource as part of this container. Returns true if the resource was added to the collection and false if it was already known.

@note Return value added in 2.4.0. @return [Boolean]

# File lib/poise/helpers/subresources/container.rb, line 166
def register_subresource(resource)
  subresources.lookup(resource)
  false
rescue Chef::Exceptions::ResourceNotFound
  Chef::Log.debug("[#{self}] Adding #{resource} to subresources")
  subresources.insert(resource)
  true
end

Private Instance Methods

to_ary() click to toggle source

Thanks Array.flatten, big help you are. Specifically the method_missing in the recipe DSL will make a flatten on an array of resources fail, so make this safe.

# File lib/poise/helpers/subresources/container.rb, line 180
def to_ary
  nil
end