#!/usr/bin/env ruby

require 'optparse'

ACTIONS = ['restart', 'stop', 'start', 'status', 'list']
COMMAND = '/usr/sbin/service-wait'
SERVICES = {
  'mongod'                   => 5,
  'postgresql'               => 5,
  'qpidd'                    => 10,
  'qdrouterd'                => 10,
  'squid'                    => 10,
  'tomcat'                   => 20,
  'tomcat6'                  => 20,
  'pulp_workers'             => 20,
  'pulp_celerybeat'          => 20,
  'pulp_resource_manager'    => 20,
  'pulp_streamer'            => 20,
  'foreman-proxy'            => 20,
  'smart_proxy_dynflow_core' => 20,
  'httpd'                    => 30,
  'foreman-tasks'            => 30
}

@options = {:excluded => []}

OptionParser.new do |opts|
  opts.banner = "Usage: katello-service [options] [#{ACTIONS.join('|')}]"

  opts.on("--exclude [SERVICES]", Array, "A comma-separated list of services to skip") do |exclude|
    @options[:excluded] = exclude
  end

  opts.on("--only [SERVICES]", Array, "A comma-separated list of services to include") do |only|
    @options[:only] = only
  end

  opts.parse!

  if ARGV.length == 0 || ARGV.length != 1
    puts opts
    exit
  else
    opts.abort("Received unsupported arguments: #{ARGV[0]}") unless ACTIONS.include?(ARGV[0])
  end

  @options[:action] = ARGV[0]
end

def service_exists?(service)
  upstart = File.exist?("/etc/init.d/#{service}")
  systemd = `systemctl is-enabled #{service} 2>&1` && $?.success?
  upstart || systemd
end

def services_by_priority(descending = false)
  services = if @options.include?(:only)
               SERVICES.sort_by { |_, value| value }.map { |service| service[0] } & @options[:only]
             else
               SERVICES.sort_by { |_, value| value }.map { |service| service[0] } - @options[:excluded]
             end
  descending ? services.reverse : services
end

def list_services
  if `which systemctl 2>&1` && $?.success?
    regex = services_by_priority.map { |service| "^#{service}.service" }.join('\|')
    puts `systemctl list-unit-files | grep '#{regex}'`
  end

  regex = services_by_priority.map { |service| "^#{service} " }.join('\|')
  puts `chkconfig --list 2>&1 | grep '#{regex}'`
end

def manage_services(action)
  failures = []

  services_by_priority(action == 'stop').each do |service|
    if service_exists?(service)
      puts `#{COMMAND} #{service} #{action}`
      failures << service unless $?.success?
    end
  end

  if failures.empty?
    puts "Success!"
  else
    puts "Some services failed to #{action}: #{failures.join(',')}"
    exit 1
  end
end

case @options[:action]
when 'list'
  list_services
when 'restart'
  %w(stop start).each { |action| manage_services action }
else
  manage_services @options[:action]
end
