# class Chef::Mixin::WhyRun::ResourceRequirements

## ResourceRequirements¶ ↑

ResourceRequirements provides a framework for making assertions about the host system's state. It also provides a mechanism for making assumptions about what the system's state might have been when running in why run mode.

For example, consider a recipe that consists of a package resource and a service resource. If the service’s init script is installed by the package, and Chef is running in why run mode, then the service resource would fail when attempting to run `/etc/init.d/software-name status`. In order to provide a more useful approximation of what would happen in a real chef run, we want to instead assume that the service was created but isn’t running. The logic would look like this:

    # Hypothetical service provider demonstrating why run assumption logic.
    # This isn't the actual API, it just shows the logic.
    class HypotheticalServiceProvider < Chef::Provider

      def load_current_resource
        # Make sure we have the init script available:
        if ::File.exist?("/etc/init.d/some-service"
          # If the init script exists, proceed as normal:
          status_cmd = shell_out("/etc/init.d/some-service status")
          if status_cmd.success?
            @current_resource.status(:running)
          else
            @current_resource.status(:stopped)
          end
        else
          if whyrun_mode?
            # If the init script is not available, and we're in why run mode,
            # assume that some previous action would've created it:
            log("warning: init script '/etc/init.d/some-service' is not available")
            log("warning: assuming that the init script would have been created, assuming the state of 'some-service' is 'stopped'")
            @current_resource.status(:stopped)
          else
            raise "expected init script /etc/init.d/some-service doesn't exist"
          end
        end
      end

    end

In short, the code above does the following:

- runs a test to determine if a requirement is met: `::File.exist?(“/etc/init.d/some-service”`

- raises an error if the requirement is not met, and we’re not in why run mode.

- if we are in why run mode, print a message explaining the situation, and run some code that makes an assumption about what the state of the system would be. In this case, we also skip the normal `load_current_resource` logic

- when the requirement is met, we run the normal `load_current_resource` logic

ResourceRequirements encapsulates the above logic in a more declarative API.

### Examples¶ ↑

Assertions and assumptions should be created through the WhyRun#assert method, which gets mixed in to providers. See that method’s documentation for examples.

### Public Class Methods

new(resource, run_context) click to toggle source

    # File lib/chef/mixin/why_run.rb, line 248
    def initialize(resource, run_context)
      @resource, @run_context = resource, run_context
      @assertions = Hash.new {|h,k| h[k] = [] }
      @blocked_actions = []
    end

### Public Instance Methods

action_blocked?(action) click to toggle source

Check to see if a given action is blocked by a failed assertion

Takes the action name to be verified.

    # File lib/chef/mixin/why_run.rb, line 261
    def action_blocked?(action)
      @blocked_actions.include?(action)
    end

assert(*actions) { |assertion| ... } click to toggle source

Define a new Assertion.

Takes a list of action names for which the assertion should be made.

#### Examples:¶ ↑

A File provider that requires the parent directory to exist:

    assert(:create, :create_if_missing) do |a|
      parent_dir = File.basename(@new_resource.path)
      a.assertion { ::File.directory?(parent_dir) }
      a.failure_message(Exceptions::ParentDirectoryDoesNotExist,
                        "Can't create file #{@new_resource.path}: parent directory #{parent_dir} doesn't exist")
      a.why_run("assuming parent directory #{parent_dir} would have been previously created"
    end

A service provider that requires the init script to exist:

    assert(:start, :restart) do |a|
      a.assertion { ::File.exist?(@new_resource.init_script) }
      a.failure_message(Exceptions::MissingInitScript,
                        "Can't check status of #{@new_resource}: init script #{@new_resource.init_script} is missing")
      a.why_run("Assuming init script would have been created and service is stopped") do
        @current_resource.status(:stopped)
      end
    end

A File provider that will error out if you don’t have permissions do delete the file, *even in why run mode*:

    assert(:delete) do |a|
      a.assertion { ::File.writable?(@new_resource.path) }
      a.failure_message(Exceptions::InsufficientPrivileges,
                        "You don't have sufficient privileges to delete #{@new_resource.path}")
    end

A Template provider that will prevent action execution but continue the run in whyrun mode if the template source is not available.

    assert(:create, :create_if_missing) do |a|
      a.assertion { File::exist?(@new_resource.source) }
      a.failure_message Chef::Exceptions::TemplateError, "Template #{@new_resource.source} could not be found exist."
      a.whyrun "Template source #{@new_resource.source} does not exist. Assuming it would have been created."
      a.block_action!
    end

    assert(:delete) do |a|
      a.assertion { ::File.writable?(@new_resource.path) }
      a.failure_message(Exceptions::InsufficientPrivileges,
                        "You don't have sufficient privileges to delete #{@new_resource.path}")
    end

    # File lib/chef/mixin/why_run.rb, line 313
    def assert(*actions)
      assertion = Assertion.new
      yield assertion
      actions.each {|action| @assertions[action] << assertion }
    end

events() click to toggle source

    # File lib/chef/mixin/why_run.rb, line 254
    def events
      @run_context.events
    end

run(action) click to toggle source

Run the assertion and assumption logic.

    # File lib/chef/mixin/why_run.rb, line 320
    def run(action)
      @assertions[action.to_sym].each do |a|
        a.run(action, events, @resource)
        if a.assertion_failed? and a.block_action?
          @blocked_actions << action
          return
        end
      end
    end