class Itamae::Resource::Base

Attributes

defined_attributes[R]
supported_oses[R]
attributes[R]
current[R]
current_attributes[R]
notifications[R]
recipe[R]
resource_name[R]
subscriptions[R]
updated[R]

Public Class Methods

define_attribute(name, options) click to toggle source
# File lib/itamae/resource/base.rb, line 85
def define_attribute(name, options)
  current = @defined_attributes[name.to_sym] || {}
  @defined_attributes[name.to_sym] = current.merge(options)
end
inherited(subclass) click to toggle source
# File lib/itamae/resource/base.rb, line 78
def inherited(subclass)
  subclass.instance_variable_set(
    :@defined_attributes,
    self.defined_attributes.dup
  )
end
new(recipe, resource_name, &block) click to toggle source
# File lib/itamae/resource/base.rb, line 103
def initialize(recipe, resource_name, &block)
  clear_current_attributes
  @recipe = recipe
  @resource_name = resource_name
  @updated = false

  EvalContext.new(self).tap do |context|
    context.instance_eval(&block) if block
    @attributes = context.attributes
    @notifications = context.notifications
    @subscriptions = context.subscriptions
    @only_if_command = context.only_if_command
    @not_if_command = context.not_if_command
    @verify_commands = context.verify_commands
  end

  process_attributes
end

Public Instance Methods

action_nothing() click to toggle source
# File lib/itamae/resource/base.rb, line 154
def action_nothing
  # do nothing
end
do_not_run_because_of_not_if?() click to toggle source
# File lib/itamae/resource/base.rb, line 167
def do_not_run_because_of_not_if?
  @not_if_command &&
    run_command(@not_if_command, error: false).exit_status == 0
end
do_not_run_because_of_only_if?() click to toggle source
# File lib/itamae/resource/base.rb, line 162
def do_not_run_because_of_only_if?
  @only_if_command &&
    run_command(@only_if_command, error: false).exit_status != 0
end
resource_type() click to toggle source
# File lib/itamae/resource/base.rb, line 158
def resource_type
  self.class.name.split("::").last.scan(/[A-Z][^A-Z]+/).map(&:downcase).join('_')
end
run(specific_action = nil) click to toggle source
# File lib/itamae/resource/base.rb, line 122
def run(specific_action = nil)
  runner.handler.event(:resource, resource_type: resource_type, resource_name: resource_name) do
    Itamae.logger.debug "#{resource_type}[#{resource_name}]"

    Itamae.logger.with_indent_if(Itamae.logger.debug?) do
      if do_not_run_because_of_only_if?
        Itamae.logger.debug "#{resource_type}[#{resource_name}] Execution skipped because of only_if attribute"
        return
      elsif do_not_run_because_of_not_if?
        Itamae.logger.debug "#{resource_type}[#{resource_name}] Execution skipped because of not_if attribute"
        return
      end

      [specific_action || attributes.action].flatten.each do |action|
        run_action(action)
      end

      verify unless runner.dry_run?
      if updated?
        runner.diff_found!
        notify
        runner.handler.event(:resource_updated)
      end
    end

    @updated = false
  end
rescue Backend::CommandExecutionError
  Itamae.logger.error "#{resource_type}[#{resource_name}] Failed."
  exit 2
end

Private Instance Methods

backend() click to toggle source
# File lib/itamae/resource/base.rb, line 283
def backend
  runner.backend
end
check_command(*args) click to toggle source
# File lib/itamae/resource/base.rb, line 306
def check_command(*args)
  unless args.last.is_a?(Hash)
    args << {}
  end

  args.last[:error] = false

  run_command(*args).exit_status == 0
end
clear_current_attributes() click to toggle source
# File lib/itamae/resource/base.rb, line 224
def clear_current_attributes
  @current_attributes = Itamae::Mash.new
end
different?() click to toggle source
# File lib/itamae/resource/base.rb, line 236
def different?
  @current_attributes.each_pair.any? do |key, current_value|
    !current_value.nil? &&
      !@attributes[key].nil? &&
      current_value != @attributes[key]
  end
end
node() click to toggle source
# File lib/itamae/resource/base.rb, line 291
def node
  runner.node
end
notify() click to toggle source
# File lib/itamae/resource/base.rb, line 339
def notify
  (notifications + runner.children.subscribing(self)).each do |notification|
    message = "Notifying #{notification.action} to #{notification.action_resource.resource_type} resource '#{notification.action_resource.resource_name}'"

    if notification.delayed?
      message << " (delayed)"
    elsif notification.immediately?
      message << " (immediately)"
    end

    Itamae.logger.info message

    if notification.instance_of?(Subscription)
      Itamae.logger.info "(because it subscribes this resource)"
    end

    if notification.delayed?
      @recipe.delayed_notifications << notification
    elsif notification.immediately?
      notification.run
    end
  end
end
pre_action() click to toggle source
# File lib/itamae/resource/base.rb, line 228
def pre_action
  # do nothing
end
process_attributes() click to toggle source
# File lib/itamae/resource/base.rb, line 263
def process_attributes
  self.class.defined_attributes.each_pair do |key, details|
    @attributes[key] ||= @resource_name if details[:default_name]
    @attributes[key] = details[:default] if details.has_key?(:default) && !@attributes.has_key?(key)

    if details[:required] && !@attributes[key]
      raise Resource::AttributeMissingError, "'#{key}' attribute is required but it is not set."
    end

    if @attributes[key] && details[:type]
      valid_type = [details[:type]].flatten.any? do |type|
        @attributes[key].is_a?(type)
      end
      unless valid_type
        raise Resource::InvalidTypeError, "#{key} attribute should be #{details[:type]}."
      end
    end
  end
end
run_action(action) click to toggle source
# File lib/itamae/resource/base.rb, line 176
def run_action(action)
  runner.handler.event(:action, action: action) do
    original_attributes = @attributes # preserve and restore later
    @current_action = action

    clear_current_attributes

    Itamae.logger.debug "#{resource_type}[#{resource_name}] action: #{action}"

    return if action == :nothing

    Itamae.logger.with_indent_if(Itamae.logger.debug?) do
      Itamae.logger.debug "(in pre_action)"
      pre_action

      Itamae.logger.debug "(in set_current_attributes)"
      set_current_attributes

      Itamae.logger.debug "(in show_differences)"
      show_differences

      method_name = "action_#{action}"
      Itamae.logger.debug "(in #{method_name})"
      if runner.dry_run?
        unless respond_to?(method_name)
          Itamae.logger.error "action #{action.inspect} is unavailable"
        end
      else
        args = [method_name]
        if method(method_name).arity == 1
          # for plugin compatibility
          args << runner.options
        end

        public_send(*args)
      end

      if different?
        updated!
        runner.handler.event(:attribute_changed, from: @current_attributes, to: @attributes)
      end
    end

    @current_action = nil
    @attributes = original_attributes
  end
end
run_command(*args) click to toggle source
# File lib/itamae/resource/base.rb, line 295
def run_command(*args)
  unless args.last.is_a?(Hash)
    args << {}
  end

  args.last[:user] ||= attributes.user
  args.last[:cwd]  ||= attributes.cwd

  backend.run_command(*args)
end
run_specinfra(type, *args) click to toggle source
# File lib/itamae/resource/base.rb, line 316
def run_specinfra(type, *args)
  command = backend.get_command(type, *args)

  if type.to_s.start_with?("check_")
    check_command(command)
  else
    run_command(command)
  end
end
runner() click to toggle source
# File lib/itamae/resource/base.rb, line 287
def runner
  recipe.runner
end
set_current_attributes() click to toggle source
# File lib/itamae/resource/base.rb, line 232
def set_current_attributes
  # do nothing
end
shell_escape(str) click to toggle source
# File lib/itamae/resource/base.rb, line 326
def shell_escape(str)
  str.shellescape
end
show_differences() click to toggle source
# File lib/itamae/resource/base.rb, line 244
def show_differences
  @current_attributes.each_pair do |key, current_value|
    value = @attributes[key]
    if current_value.nil? && value.nil?
      # ignore
    elsif current_value.nil? && !value.nil?
      Itamae.logger.color :green do
        Itamae.logger.info "#{resource_type}[#{resource_name}] #{key} will be '#{value}'"
      end
    elsif current_value == value || value.nil?
      Itamae.logger.debug "#{resource_type}[#{resource_name}] #{key} will not change (current value is '#{current_value}')"
    else
      Itamae.logger.color :green do
        Itamae.logger.info "#{resource_type}[#{resource_name}] #{key} will change from '#{current_value}' to '#{value}'"
      end
    end
  end
end
updated!() click to toggle source
# File lib/itamae/resource/base.rb, line 330
def updated!
  Itamae.logger.debug "This resource is updated."
  @updated = true
end
updated?() click to toggle source
# File lib/itamae/resource/base.rb, line 335
def updated?
  @updated
end
verify() click to toggle source
# File lib/itamae/resource/base.rb, line 363
def verify
  return if @verify_commands.empty?

  Itamae.logger.info "Verifying..."
  Itamae.logger.with_indent do
    @verify_commands.each do |command|
      run_command(command)
    end
  end
end