class Chef::Provider::Service::Upstart

Constants

UPSTART_STATE_FORMAT

Attributes

upstart_service_running[RW]

to maintain a local state of service across restart’s internal calls

Public Class Methods

new(new_resource, run_context) click to toggle source

Upstart does more than start or stop a service, creating multiple ‘states’ [1] that a service can be in. In chef, when we ask a service to start, we expect it to have started before performing the next step since we have top down dependencies. Which is to say we may follow with a resource next that requires that service to be running. According to [2] we can trust that sending a ‘goal’ such as start will not return until that ‘goal’ is reached, or some error has occurred.

1

upstart.ubuntu.com/wiki/JobStates

2

www.netsplit.com/2008/04/27/upstart-05-events/

Calls superclass method Chef::Provider::Service::new
# File lib/chef/provider/service/upstart.rb, line 47
def initialize(new_resource, run_context)
  # TODO: re-evaluate if this is needed after integrating cookbook fix
  raise ArgumentError, "run_context cannot be nil" unless run_context

  super

  run_context.node

  # dup so we can mutate @job
  @job = @new_resource.service_name.dup

  if @new_resource.parameters
    @new_resource.parameters.each do |key, value|
      @job << " #{key}=#{value}"
    end
  end

  @upstart_job_dir = "/etc/init"
  @upstart_conf_suffix = ".conf"
  @command_success = true # new_resource.status_command= false, means upstart used
  @config_file_found = true
  @upstart_command_success = true
end
supports?(resource, action) click to toggle source

Returns true if the configs for the service name has upstart variable

# File lib/chef/provider/service/upstart.rb, line 34
def self.supports?(resource, action)
  service_script_exist?(:upstart, resource.service_name)
end

Public Instance Methods

define_resource_requirements() click to toggle source
# File lib/chef/provider/service/upstart.rb, line 71
def define_resource_requirements
  # Do not call super, only call shared requirements
  shared_resource_requirements
  requirements.assert(:all_actions) do |a|
    unless @command_success
      whyrun_msg = if @new_resource.status_command
                     "Provided status command #{@new_resource.status_command} failed."
                   else
                     "Could not determine upstart state for service"
                   end
    end
    a.assertion { @command_success }
    # no failure here, just document the assumptions made.
    a.whyrun "#{whyrun_msg} Assuming service installed and not running."
  end

  requirements.assert(:all_actions) do |a|
    a.assertion { @config_file_found }
    # no failure here, just document the assumptions made.
    a.whyrun "Could not find #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}. Assuming service is disabled."
  end
end
disable_service() click to toggle source
# File lib/chef/provider/service/upstart.rb, line 225
def disable_service
  logger.trace("#{@new_resource} upstart lacks inherent support for disabling services, editing job config file")
  conf = Chef::Util::FileEdit.new("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}")
  conf.search_file_replace(/^start on/, "#start on")
  conf.write_file
end
enable_service() click to toggle source

bugs.launchpad.net/upstart/+bug/94065

# File lib/chef/provider/service/upstart.rb, line 218
def enable_service
  logger.trace("#{@new_resource} upstart lacks inherent support for enabling services, editing job config file")
  conf = Chef::Util::FileEdit.new("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}")
  conf.search_file_replace(/^#start on/, "start on")
  conf.write_file
end
load_current_resource() click to toggle source
# File lib/chef/provider/service/upstart.rb, line 94
def load_current_resource
  @current_resource = Chef::Resource::Service.new(@new_resource.name)
  @current_resource.service_name(@new_resource.service_name)

  # Get running/stopped state
  # We do not support searching for a service via ps when using upstart since status is a native
  # upstart function. We will however support status_command in case someone wants to do something special.
  if @new_resource.status_command
    logger.trace("#{@new_resource} you have specified a status command, running..")

    begin
      if shell_out!(@new_resource.status_command).exitstatus == 0
        @upstart_service_running = true
      end
    rescue
      @command_success = false
      @upstart_service_running = false
      nil
    end
  else
    begin
      if upstart_goal_state == "start"
        @upstart_service_running = true
      else
        @upstart_service_running = false
      end
    rescue Chef::Exceptions::Exec
      @command_success = false
      @upstart_service_running = false
      nil
    end
  end
  # Get enabled/disabled state by reading job configuration file
  if ::TargetIO::File.exist?("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}")
    logger.trace("#{@new_resource} found #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}")
    ::TargetIO::File.open("#{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}", "r") do |file|
      while line = file.gets
        case line
        when /^start on/
          logger.trace("#{@new_resource} enabled: #{line.chomp}")
          @current_resource.enabled true
          break
        when /^#start on/
          logger.trace("#{@new_resource} disabled: #{line.chomp}")
          @current_resource.enabled false
          break
        end
      end
    end
  else
    @config_file_found = false
    logger.trace("#{@new_resource} did not find #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}")
    @current_resource.enabled false
  end

  @current_resource.running @upstart_service_running
  @current_resource
end
reload_service() click to toggle source
# File lib/chef/provider/service/upstart.rb, line 205
def reload_service
  if @new_resource.reload_command
    super
  else
    # upstart >= 0.6.3-4 supports reload (HUP)
    shell_out!("/sbin/reload #{@job}", default_env: false)
  end

  @upstart_service_running = true
end
restart_service() click to toggle source
# File lib/chef/provider/service/upstart.rb, line 185
def restart_service
  if @new_resource.restart_command
    super
  # Upstart always provides restart functionality so we don't need to mimic it with stop/sleep/start.
  # Older versions of upstart would fail on restart if the service was currently stopped, check for that. LP:430883
  # But for safe working of latest upstart job config being loaded, 'restart' can't be used as per link
  # http://upstart.ubuntu.com/cookbook/#restart (it doesn't uses latest jon config from disk but retains old)
  else
    if @upstart_service_running
      stop_service
      sleep 1
      start_service
    else
      start_service
    end
  end

  @upstart_service_running = true
end
start_service() click to toggle source
# File lib/chef/provider/service/upstart.rb, line 153
def start_service
  # Calling start on a service that is already started will return 1
  # Our 'goal' when we call start is to ensure the service is started
  if @upstart_service_running
    logger.trace("#{@new_resource} already running, not starting")
  else
    if @new_resource.start_command
      super
    else
      shell_out!("/sbin/start #{@job}", default_env: false)
    end
  end

  @upstart_service_running = true
end
stop_service() click to toggle source
# File lib/chef/provider/service/upstart.rb, line 169
def stop_service
  # Calling stop on a service that is already stopped will return 1
  # Our 'goal' when we call stop is to ensure the service is stopped
  unless @upstart_service_running
    logger.trace("#{@new_resource} not running, not stopping")
  else
    if @new_resource.stop_command
      super
    else
      shell_out!("/sbin/stop #{@job}", default_env: false)
    end
  end

  @upstart_service_running = false
end
upstart_goal_state() click to toggle source
# File lib/chef/provider/service/upstart.rb, line 232
def upstart_goal_state
  command = "/sbin/status #{@job}"
  so = shell_out(command)
  so.stdout.each_line do |line|
    # service goal/state
    # OR
    # service (instance) goal/state
    # OR
    # service (goal) state
    line =~ UPSTART_STATE_FORMAT
    data = Regexp.last_match
    return data[1]
  end
end