service/src/service.cr

222 lines
4.9 KiB
Crystal
Raw Normal View History

require "option_parser"
2019-06-09 16:59:05 +02:00
require "yaml"
require "colorize"
require "./config.cr"
# TODO:
# - Be more declarative about the definition of commands.
2019-06-09 16:59:05 +02:00
require "./service/*"
2019-06-09 16:59:05 +02:00
args = [] of String
2019-06-09 16:59:05 +02:00
parser = OptionParser.parse do |parser|
parser.banner = "usage: service <command> [options]\n" +
"options:\n"
2019-06-09 16:59:05 +02:00
parser.on "-h", "--help", "Prints this help message." do
puts parser
exit 0
2019-06-09 16:59:05 +02:00
end
parser.unknown_args do |x|
args = x
2019-06-09 16:59:05 +02:00
end
end
2019-06-09 16:59:05 +02:00
2019-10-24 20:31:38 +02:00
alias Command = Proc(Array(String), Nil)
alias CommandTuple = Tuple(String, String, Command)
class CommandsList
def initialize
@commands = Array(CommandTuple).new
end
2019-06-09 16:59:05 +02:00
2019-10-24 20:31:38 +02:00
def push(name : String, description : String, &proc : Command)
@commands << Tuple.new(name, description, proc)
end
2019-10-24 20:31:38 +02:00
def find(&block : Proc(CommandTuple, Bool))
@commands.find do |tuple|
if block.call tuple
next true
end
end
end
2019-10-24 20:31:38 +02:00
def to_s
"commands:\n\n"+ @commands.map do |tuple|
" %-32s %s" % [tuple[0], tuple[1]]
end.join "\n"
end
end
commands = CommandsList.new
2019-10-24 20:31:38 +02:00
commands.push "add", "Adds a service to an environment." do |args|
providers = Hash(String, String).new
2019-10-24 20:31:38 +02:00
environment, service = Service.parse_id args[0]
2019-10-24 20:31:38 +02:00
args.each_with_index do |arg, i|
next if i == 0
2019-10-24 20:31:38 +02:00
match = arg.match /(.*)=(.*)/
2019-10-24 20:31:38 +02:00
if match.nil?
raise ::Service::Exception.new "usage: service add <service> <token=provider>"
next
end
2019-10-24 20:31:38 +02:00
providers[match[1]] = match[2]
end
2019-10-24 20:31:38 +02:00
Service.new(service, environment).tap do |service|
service.consumes.each do |token|
provider = providers[token.token]?
2019-10-24 20:31:38 +02:00
if provider.nil?
provider = service.get_default_provider token.token
end
2019-10-24 20:31:38 +02:00
if provider.nil?
STDERR.puts "This service consumes a “#{token.token}” token, but you have not specified what other service is supposed to provide it."
STDERR.puts "Use the `service add #{args[1]} #{token.token}=<provider>` syntax to specify it."
exit 1
end
2019-06-09 16:59:05 +02:00
2019-10-24 20:31:38 +02:00
service.providers[token.token] = provider
2019-06-09 16:59:05 +02:00
end
2019-10-24 20:31:38 +02:00
pp! service.providers
end.write RC_DIRECTORY
end
2019-06-09 16:59:05 +02:00
2019-10-24 20:31:38 +02:00
commands.push "del", "Removes a service from an environment." do |args|
if args.size < 1
STDERR.puts "usage: service del <id> [id [...]]"
exit 1
end
args.each do |id|
Service.get_by_id(id).try &.remove RC_DIRECTORY
end
2019-10-24 20:31:38 +02:00
end
2019-06-09 16:59:05 +02:00
2019-10-24 20:31:38 +02:00
commands.push "start", "Starts a service." do
services = args.map do |arg|
service = Service.get_by_id(arg)
unless service
raise Service::Exception.new "Service '#{arg}' does not exist."
2019-06-09 16:59:05 +02:00
end
2019-10-24 20:31:38 +02:00
service
end
services.each do |service|
service.dependency_tree.flatten.reverse.each do |service|
next if service.running? PID_DIRECTORY
2019-06-09 16:59:05 +02:00
2019-10-24 20:31:38 +02:00
puts "starting #{service.to_s}"
service.start PID_DIRECTORY, LOG_DIRECTORY
2019-06-09 16:59:05 +02:00
end
2019-10-24 20:31:38 +02:00
end
end
2019-06-09 16:59:05 +02:00
2019-10-24 20:31:38 +02:00
commands.push "stop", "Stops a running service." do |args|
services = args.map do |arg|
service = Service.get_by_id(arg)
2019-06-09 16:59:05 +02:00
2019-10-24 20:31:38 +02:00
unless service
raise Service::Exception.new "Service '#{arg}' does not exist."
end
2019-10-24 20:31:38 +02:00
service
end
2019-06-09 16:59:05 +02:00
2019-10-24 20:31:38 +02:00
services.each do |service|
# FIXME: Build revdep tree and stop services started as dependencies?
next if ! service.running? PID_DIRECTORY
# FIXME: Should we remove duplicate services from the
# tree once flattened?
service.reverse_dependency_tree.flatten.reverse.each do |service|
next if ! service.running? PID_DIRECTORY
2019-06-09 16:59:05 +02:00
2019-10-24 20:31:38 +02:00
puts "stopping #{service.to_s}"
service.stop PID_DIRECTORY
2019-06-09 16:59:05 +02:00
end
2019-10-24 20:31:38 +02:00
end
end
commands.push "status", "Prints the status of services." do |args|
child = Process.run "#{OWN_LIBEXEC_DIR}/status", args,
output: Process::Redirect::Inherit,
error: Process::Redirect::Inherit
return_value = (child.exit_status / 256).to_i
# Errors not registered here should probably be verbose in `status`.
if return_value == 1
STDERR << "No such service.\n"
end
exit return_value
end
commands.push "show", "Shows a service's configuration and state." do |args|
if args.size < 1
STDERR << "usage: service show <id> [id [...]]\n"
next
end
args.each do |arg|
environment_name, service_name = Service.parse_id arg
2019-10-24 20:31:38 +02:00
service = Service.all.find do |service|
service.name == service_name &&
service.environment.name == environment_name
2019-06-09 16:59:05 +02:00
end
2019-10-24 20:31:38 +02:00
if service
puts service.summary
else
STDERR << "No such service is registered.\n"
exit 2
end
2019-06-09 16:59:05 +02:00
end
2019-10-24 20:31:38 +02:00
end
commands.push "add-environment", "Creates a new (empty) environment." do |arg|
Environment.new(args[9]).write ENVIRONMENTS_DIRECTORY
end
commands.push "list-environments", "Lists all currently defined environments.s", do |arg|
Environment.all.map do |env|
puts env.to_s
end
end
commands.push "help", "Prints this help message." do
puts parser
puts
puts commands.to_s
end
command = commands.find &.[0].==(args[0]?)
if command.nil?
STDERR << parser << "\n"
STDERR << "\n"
STDERR << commands.to_s << "\n"
exit 1
end
ServiceDefinition.load SERVICES_DIRECTORY
Environment.load ENVIRONMENTS_DIRECTORY
Service.load RC_DIRECTORY
begin
args.shift
command.[2].call(args)
rescue e : Service::Exception
STDERR << e.message << "\n"
exit 2
2019-06-09 16:59:05 +02:00
end