class Chef::Provider::DscScript

Public Class Methods

new(dsc_resource, run_context) click to toggle source
Calls superclass method Chef::Provider.new
# File lib/chef/provider/dsc_script.rb, line 30
def initialize(dsc_resource, run_context)
  super(dsc_resource, run_context)
  @dsc_resource = dsc_resource
  @resource_converged = false
  @operations = {
    :set => Proc.new do |config_manager, document, shellout_flags|
      config_manager.set_configuration(document, shellout_flags)
    end,
    :test => Proc.new do |config_manager, document, shellout_flags|
      config_manager.test_configuration(document, shellout_flags)
    end }
end

Public Instance Methods

action_run() click to toggle source
# File lib/chef/provider/dsc_script.rb, line 43
def action_run
  if ! @resource_converged
    converge_by(generate_description) do
      run_configuration(:set)
      logger.info("DSC resource configuration completed successfully")
    end
  end
end
define_resource_requirements() click to toggle source
# File lib/chef/provider/dsc_script.rb, line 61
def define_resource_requirements
  requirements.assert(:run) do |a|
    err = [
      "Could not find PowerShell DSC support on the system",
      powershell_info_str,
      "Powershell 4.0 or higher was not detected on your system and is required to use the dsc_script resource.",
    ]
    a.assertion { supports_dsc? }
    a.failure_message Chef::Exceptions::ProviderNotFound, err.join(" ")
    a.whyrun err + ["Assuming a previous resource installs Powershell 4.0 or higher."]
    a.block_action!
  end
end
load_current_resource() click to toggle source
# File lib/chef/provider/dsc_script.rb, line 52
def load_current_resource
  if supports_dsc?
    @dsc_resources_info = run_configuration(:test)
    @resource_converged = @dsc_resources_info.all? do |resource|
      !resource.changes_state?
    end
  end
end

Protected Instance Methods

configuration_friendly_name() click to toggle source
# File lib/chef/provider/dsc_script.rb, line 148
def configuration_friendly_name
  if @dsc_resource.code
    @dsc_resource.name
  else
    configuration_name
  end
end
configuration_name() click to toggle source
# File lib/chef/provider/dsc_script.rb, line 144
def configuration_name
  @dsc_resource.configuration_name || @dsc_resource.name
end
generate_configuration_document(config_directory, configuration_flags) click to toggle source
# File lib/chef/provider/dsc_script.rb, line 114
def generate_configuration_document(config_directory, configuration_flags)
  shellout_flags = {
    :cwd => @dsc_resource.cwd,
    :environment => @dsc_resource.environment,
    :timeout => @dsc_resource.timeout,
  }

  generator = Chef::Util::DSC::ConfigurationGenerator.new(@run_context.node, config_directory)

  if @dsc_resource.command
    generator.configuration_document_from_script_path(@dsc_resource.command, configuration_name, configuration_flags, shellout_flags)
  else
    # If code is also not provided, we mimic what the other script resources do (execute nothing)
    logger.warn("Neither code or command were provided for dsc_resource[#{@dsc_resource.name}].") unless @dsc_resource.code
    generator.configuration_document_from_script_code(@dsc_resource.code || "", configuration_flags, @dsc_resource.imports, shellout_flags)
  end
end
get_augmented_configuration_flags(configuration_data_path) click to toggle source
# File lib/chef/provider/dsc_script.rb, line 105
def get_augmented_configuration_flags(configuration_data_path)
  updated_flags = @dsc_resource.flags.nil? ? {} : @dsc_resource.flags.dup
  if configuration_data_path
    Chef::Util::PathHelper.validate_path(configuration_data_path)
    updated_flags[:configurationdata] = configuration_data_path
  end
  updated_flags
end
get_configuration_data_path(config_directory) click to toggle source
# File lib/chef/provider/dsc_script.rb, line 132
def get_configuration_data_path(config_directory)
  if @dsc_resource.configuration_data_script
    @dsc_resource.configuration_data_script
  elsif @dsc_resource.configuration_data
    configuration_data_path = "#{config_directory}/chef_dsc_config_data.psd1"
    ::File.open(configuration_data_path, "wt") do |script|
      script.write(@dsc_resource.configuration_data)
    end
    configuration_data_path
  end
end
run_configuration(operation) click to toggle source
# File lib/chef/provider/dsc_script.rb, line 81
def run_configuration(operation)
  config_directory = ::Dir.mktmpdir("chef-dsc-script")
  configuration_data_path = get_configuration_data_path(config_directory)
  configuration_flags = get_augmented_configuration_flags(configuration_data_path)

  config_manager = Chef::Util::DSC::LocalConfigurationManager.new(@run_context.node, config_directory)

  shellout_flags = {
    :cwd => @dsc_resource.cwd,
    :environment => @dsc_resource.environment,
    :timeout => @dsc_resource.timeout,
  }

  begin
    configuration_document = generate_configuration_document(config_directory, configuration_flags)
    @operations[operation].call(config_manager, configuration_document, shellout_flags)
  rescue Exception => e
    logger.error("DSC operation failed: #{e.message}")
    raise e
  ensure
    ::FileUtils.rm_rf(config_directory)
  end
end
supports_dsc?() click to toggle source
# File lib/chef/provider/dsc_script.rb, line 77
def supports_dsc?
  run_context && Chef::Platform.supports_dsc?(node)
end

Private Instance Methods

generate_description() click to toggle source
# File lib/chef/provider/dsc_script.rb, line 158
def generate_description
  ["converge DSC configuration '#{configuration_friendly_name}'"] +
    @dsc_resources_info.map do |resource|
      if resource.changes_state?
        # We ignore the last log message because it only contains the time it took, which looks weird
        cleaned_messages = resource.change_log[0..-2].map { |c| c.sub(/^#{Regexp.escape(resource.name)}/, "").strip }
        unless cleaned_messages.empty?
          "converge DSC resource #{resource.name} by #{cleaned_messages.find_all { |c| c != '' }.join("\n")}"
        else
          "converge DSC resource #{resource.name}"
        end
      else
        # This is needed because a dsc script can have resources that are both converged and not
        "converge DSC resource #{resource.name} by doing nothing because it is already converged"
      end
    end
end
powershell_info_str() click to toggle source
# File lib/chef/provider/dsc_script.rb, line 176
def powershell_info_str
  if run_context && run_context.node[:languages] && run_context.node[:languages][:powershell]
    install_info = "Powershell #{run_context.node[:languages][:powershell][:version]} was found on the system."
  else
    install_info = "Powershell was not found."
  end
end