class PoiseService::Runit::Provider

Poise-service provider for [Runit](smarden.org/runit/index.html).

@since 1.0.0 @example

poise_service 'myapp' do
  command 'myapp --serve'
  provider :runit
end

Constants

RUNIT_SIGNALS

A mapping of signal names to sv subcommands.

Private Class Methods

name() click to toggle source

Lie about the name.

# File lib/poise_service/runit/provider.rb, line 133
def self.name
  superclass.name
end

Public Instance Methods

action_reload() click to toggle source

Reload action for the runit provider. Runs hup on the service resource because upstream’s reload action runs sv force-reload which is ~restart.

# File lib/poise_service/runit/provider.rb, line 52
def action_reload
  return if options['never_reload']
  notify_if_service do
    service_resource.run_action(:hup)
  end
end
pid() click to toggle source

Parse the PID from sv output.

@return [Integer]

# File lib/poise_service/runit/provider.rb, line 62
def pid
  cmd = shell_out(%w{sv status} + [new_resource.service_name])
  if !cmd.error? && md = cmd.stdout.match(/run: #{new_resource.service_name}: \(pid (\d+)\)/)
    md[1].to_i
  else
    nil
  end
end

Private Instance Methods

check_signals!() click to toggle source
# File lib/poise_service/runit/provider.rb, line 186
def check_signals!
  %w{reload_signal stop_signal}.each do |sig_type|
    signal = new_resource.send(sig_type)
    unless RUNIT_SIGNALS[signal]
      raise PoiseService::Error.new("Runit does not support sending #{signal}, please change the #{sig_type} on #{new_resource.to_s}")
    end
  end
end
create_service() click to toggle source

Set up secondary service files for Runit.

# File lib/poise_service/runit/provider.rb, line 86
def create_service
  # Check signals here to be nice and abort early if possible.
  check_signals!
  # Enable automatically creates the service with Runit.
  directory "/var/log/#{new_resource.service_name}" do
    owner 'root'
    group 'root'
    mode '700'
  end
end
destroy_service() click to toggle source

Tear down secondary service files for Runit.

# File lib/poise_service/runit/provider.rb, line 112
def destroy_service
  # Disable automatically destroys the service with Runit.
  directory "/var/log/#{new_resource.service_name}" do
    action :delete
    recursive true
  end
end
dummy_command() click to toggle source

Find the command to run run in dummy mode for testing inside docker. If this returns nil, no dummy service is started.

@return [String, nil]

# File lib/poise_service/runit/provider.rb, line 199
def dummy_command
  return options['dummy_command'] if options.include?('dummy_command')
  return nil unless node['virtualization'] && %w{docker lxc}.include?(node['virtualization']['system'])
  node.value_for_platform_family(debian: '/usr/sbin/runsvdir-start', rhel: '/sbin/runsvdir -P -H /etc/service')
end
enable_service() click to toggle source

Hack the enable action for the runit provider. This forces it to wait until runsv recognizes the new service. This is tracked upstream in github.com/hw-cookbooks/runit/issues/136

@api private @todo Remove once the upstream bug is fixed.

Calls superclass method
# File lib/poise_service/runit/provider.rb, line 103
def enable_service
  super
  sleep 1 until ::FileTest.pipe?("#{service_resource.service_dir}/#{service_resource.service_name}/supervise/ok")
  if service_resource.log
    sleep 1 until ::FileTest.pipe?("#{service_resource.service_dir}/#{service_resource.service_name}/log/supervise/ok")
  end
end
inside_docker?() click to toggle source
# File lib/poise_service/runit/provider.rb, line 137
def inside_docker?
  # We account for docker already so just lock it to false.
  false
end
recipes() click to toggle source

Recipes to include for Runit.

# File lib/poise_service/runit/provider.rb, line 74
def recipes
  ['runit', proc {
    begin
      if node['virtualization'] && %w{docker lxc}.include?(node['virtualization']['system'])
        resources('service[runsvdir-start]').action(:nothing)
      end
    rescue Chef::Exceptions::ResourceNotFound
    end
  }]
end
run_dummy!() click to toggle source

HAXX: Deal with starting runsvdir under Docker on Ubuntu/Debian/RHEL. System packages use Upstart which doesn’t run under Docker. Yo dawg.

@return [void]

# File lib/poise_service/runit/provider.rb, line 209
def run_dummy!
  if dummy_command
    Chef::Resource.resource_for_node(:poise_service, node).new('runsvdir', run_context).tap do |r|
      r.command(dummy_command)
      r.provider(:dummy)
      r.run_action(:enable)
    end
  end
end
service_provider() click to toggle source

Hack to subclass the upstream provider to override inside_docker?

@return [Class]

# File lib/poise_service/runit/provider.rb, line 123
def service_provider
  base_class = if defined?(Chef::Provider::RunitService)
    Chef::Provider::RunitService
  elsif defined?(Chef::Provider::Service::Runit)
    Chef::Provider::Service::Runit
  else
    raise PoiseService::Error.new('Unable to find runit_service provider class.')
  end
  Class.new(base_class) do
    # Lie about the name.
    def self.name
      superclass.name
    end

    def inside_docker?
      # We account for docker already so just lock it to false.
      false
    end
  end
end
service_resource() click to toggle source

Create the service resource for Runit.

@return [Chef::Resource]

# File lib/poise_service/runit/provider.rb, line 147
def service_resource
  # Sanity checking
  check_signals!
  run_dummy!
  # Set defaults for sv_bin and sv_dir so we can use them in templates.
  # This follows the same lookup as in resource_runit_service.rb.
  if node['runit']
    options['sv_bin'] ||= node['runit']['sv_bin']
    options['sv_dir'] ||= node['runit']['sv_dir']
  end
  options['sv_bin'] ||= '/usr/bin/sv'
  options['sv_dir'] ||= '/etc/sv'
  # Build the runit_service resource.
  @service_resource ||= Chef::Resource::RunitService.new(new_resource.name, run_context).tap do |r|
    r.provider service_provider
    r.service_name new_resource.service_name
    r.owner 'root'
    r.group 'root'
    r.sv_bin options['sv_bin']
    r.sv_dir options['sv_dir']
    r.sv_timeout options['timeout'] if options['timeout']
    r.options options.merge(new_resource: new_resource, runit_signals: RUNIT_SIGNALS)
    r.env Mash.new(options['environment'] || new_resource.environment)
    r.run_template_name 'template'
    r.log_template_name 'template'
    # Force h and t because those map to stop_signal and reload_signal.
    control = []
    control << 'h' if new_resource.reload_signal != 'HUP'
    control += %w{d t} if new_resource.stop_signal != 'TERM'
    control += options['control'].keys if options['control']
    control.uniq!
    r.control control
    r.control_template_names Hash.new { 'template-control' } # There is no name only Zuul.
    r.cookbook 'poise-service-runit'
    # Runit only supports the equivalent of our 'immediately' mode :-/
    r.restart_on_update new_resource.restart_on_update
  end
end