Module: Poise::Helpers::Subresources::Container

Includes:
Chef::DSL::Recipe, Poise::Helpers::SubcontextBlock
Defined in:
lib/poise/helpers/subresources/container.rb

Overview

A resource mixin for subresource containers.

Since:

  • 1.0.0

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#subcontextsObject (readonly)

Since:

  • 1.0.0



47
48
49
# File 'lib/poise/helpers/subresources/container.rb', line 47

def subcontexts
  @subcontexts
end

#subresourcesObject (readonly)

Since:

  • 1.0.0



46
47
48
# File 'lib/poise/helpers/subresources/container.rb', line 46

def subresources
  @subresources
end

Class Method Details

.container_defaultBoolean .container_default(val) ⇒ Boolean

Overloads:

  • .container_defaultBoolean

    Get the default mode for this resource. If false, this resource class will not be used for default container lookups. Defaults to true.

    Returns:

    • (Boolean)

    Since:

    • 2.3.0

  • .container_default(val) ⇒ Boolean

    Set the default mode for this resource.

    Parameters:

    • val (Boolean)

      Default mode to set.

    Returns:

    • (Boolean)

    Since:

    • 2.3.0

Since:

  • 1.0.0



207
208
209
210
211
212
213
214
215
# File 'lib/poise/helpers/subresources/container.rb', line 207

def container_default(val=nil)
  @container_default = val unless val.nil?
  if @container_default.nil?
    # Not set here, look at the superclass or true by default for backwards compat.
    Poise::Utils.ancestor_send(self, :container_default, default: true)
  else
    @container_default
  end
end

.container_namespace(val = nil) ⇒ Object

Since:

  • 1.0.0



186
187
188
189
190
191
192
193
194
# File 'lib/poise/helpers/subresources/container.rb', line 186

def container_namespace(val=nil)
  @container_namespace = val unless val.nil?
  if @container_namespace.nil?
    # Not set here, look at the superclass or true by default for backwards compat.
    Poise::Utils.ancestor_send(self, :container_namespace, default: true)
  else
    @container_namespace
  end
end

Instance Method Details

#after_createdObject

Since:

  • 1.0.0



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# 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) ⇒ Object

Since:

  • 1.0.0



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# 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

#initialize(*args) ⇒ Object

Since:

  • 1.0.0



49
50
51
52
53
# File 'lib/poise/helpers/subresources/container.rb', line 49

def initialize(*args)
  super
  @subresources = NoPrintingResourceCollection.new
  @subcontexts = []
end

#register_subresource(resource) ⇒ Boolean

Note:

Return value added in 2.4.0.

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.

Returns:

  • (Boolean)

Since:

  • 1.0.0



166
167
168
169
170
171
172
173
# 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