Method: Chef::Provider#converge_if_changed

Defined in:
lib/chef/provider.rb

#converge_if_changed(*properties, &converge_block) ⇒ Boolean

Handle patchy convergence safely.

  • Does not call the block if the current_resource’s properties match the properties the user specified on the resource.

  • Calls the block if current_resource does not exist

  • Calls the block if the user has specified any properties in the resource whose values are different from current_resource.

  • Does not call the block if why-run is enabled (just prints out text).

  • Prints out automatic green text saying what properties have changed.

Parameters:

  • properties

    An optional list of property names (symbols). If not specified, new_resource.class.state_properties will be used.

  • converge_block

    The block to do the converging in.

Returns:

  • (Boolean)

    whether the block was executed.



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/chef/provider.rb', line 331

def converge_if_changed(*properties, &converge_block)
  unless converge_block
    raise ArgumentError, "converge_if_changed must be passed a block!"
  end

  properties =
    if properties.empty?
      new_resource.class.state_properties
    else
      properties.map { |property| new_resource.class.properties[property] }
    end

  if current_resource
    # Collect the list of modified properties
    specified_properties = properties.select { |property| property.is_set?(new_resource) || property.has_default? }
    specified_properties = specified_properties.map(&:name).map(&:to_sym)
    modified = specified_properties.select { |p| new_resource.send(p) != current_resource.send(p) }
    if modified.empty?
      properties_str = if new_resource.sensitive
                         specified_properties.join(", ")
                       else
                         specified_properties.map do |property|
                           "#{property}=" << if new_resource.class.properties[property].sensitive?
                                               "(suppressed sensitive property)"
                                             else
                                               new_resource.send(property).inspect
                                             end
                         end.join(", ")
                       end
      logger.debug("Skipping update of #{new_resource}: has not changed any of the specified properties #{properties_str}.")
      return false
    end

    # Print the pretty green text and run the block
    property_size = modified.map(&:size).max
    modified.map! do |p|
      properties_str = if new_resource.sensitive || new_resource.class.properties[p].sensitive?
                         "(suppressed sensitive property)"
                       else
                         "#{new_resource.send(p).inspect} (was #{current_resource.send(p).inspect})"
                       end
      "  set #{p.to_s.ljust(property_size)} to #{properties_str}"
    end
    converge_by([ "update #{current_resource.identity}" ] + modified, &converge_block)

  else
    # The resource doesn't exist. Mark that we are *creating* this, and
    # write down any properties we are setting.
    property_size = properties.map(&:name).map(&:to_sym).map(&:size).max
    created = properties.map do |property|
      default = " (default value)" unless property.is_set?(new_resource)
      properties_str = if new_resource.sensitive || property.sensitive?
                         "(suppressed sensitive property)"
                       else
                         new_resource.send(property.name.to_sym).inspect
                       end
      "  set #{property.name.to_sym.to_s.ljust(property_size)} to #{properties_str}#{default}"
    end

    converge_by([ "create #{new_resource.identity}" ] + created, &converge_block)
  end
  true
end