Grooming, `service reload`, `Service#reload`.
`reload-command:` can be defined in service definition `.spec` files.master
parent
77290392b2
commit
d3fe317665
|
@ -1,6 +1,7 @@
|
||||||
command: nginx -c nginx.conf
|
command: nginx -c ${SERVICE_ROOT}/nginx.conf
|
||||||
consumes: http?
|
consumes: http?
|
||||||
provides: www, http
|
provides: www, http
|
||||||
ports: http=80, https=443
|
ports: http=80, https=443
|
||||||
|
reload-command: kill -HUP ${SERVICE_PID}
|
||||||
|
|
||||||
%configuration nginx.conf
|
%configuration nginx.conf
|
||||||
|
|
|
@ -67,9 +67,8 @@ class GenConfig::Context
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate(template, target : String, options : Hash(String, Variables))
|
def generate(template, target : String, options : Hash(String, Variables))
|
||||||
Environment.load ENVIRONMENTS_DIRECTORY
|
context = Service::Context.new
|
||||||
ServiceDefinition.load SERVICES_DIRECTORY
|
context.load
|
||||||
Service.load RC_DIRECTORY
|
|
||||||
|
|
||||||
target_file = File.open target, "w"
|
target_file = File.open target, "w"
|
||||||
|
|
||||||
|
@ -95,13 +94,13 @@ class GenConfig::Context
|
||||||
end
|
end
|
||||||
|
|
||||||
if service_id = ENV["SERVICE_ID"]?
|
if service_id = ENV["SERVICE_ID"]?
|
||||||
if service = Service.get_by_id service_id
|
if service = context.get_service_by_id service_id
|
||||||
environment = service.environment
|
environment = service.environment
|
||||||
|
|
||||||
options["service"] = service.to_genconfig
|
options["service"] = service.to_genconfig
|
||||||
|
|
||||||
options["providers"] = service.providers.compact_map do |token, provider|
|
options["providers"] = service.providers.compact_map do |token, provider|
|
||||||
provider = Service.get_by_id provider
|
provider = context.get_service_by_id provider
|
||||||
|
|
||||||
next unless provider
|
next unless provider
|
||||||
|
|
||||||
|
@ -127,7 +126,7 @@ class GenConfig::Context
|
||||||
id = (arguments.varargs[0]? || options["id"]).to_s
|
id = (arguments.varargs[0]? || options["id"]).to_s
|
||||||
password_id = arguments.varargs[1]? || "main"
|
password_id = arguments.varargs[1]? || "main"
|
||||||
|
|
||||||
_service = Service.get_by_id(id).not_nil!
|
_service = context.get_service_by_id(id).not_nil!
|
||||||
|
|
||||||
# FIXME: hardcoded path
|
# FIXME: hardcoded path
|
||||||
password_file = "#{_service.root}/password_#{password_id}"
|
password_file = "#{_service.root}/password_#{password_id}"
|
||||||
|
|
|
@ -4,9 +4,8 @@ require "./service/environment.cr"
|
||||||
require "./service/service_definition.cr"
|
require "./service/service_definition.cr"
|
||||||
require "./service/service.cr"
|
require "./service/service.cr"
|
||||||
|
|
||||||
Environment.load ENVIRONMENTS_DIRECTORY
|
context = Service::Context.new
|
||||||
ServiceDefinition.load SERVICES_DIRECTORY
|
context.load
|
||||||
Service.load RC_DIRECTORY
|
|
||||||
|
|
||||||
if ARGV.size != 2
|
if ARGV.size != 2
|
||||||
STDERR.puts "usage: get-port <service-id> <port-id>"
|
STDERR.puts "usage: get-port <service-id> <port-id>"
|
||||||
|
@ -15,5 +14,5 @@ end
|
||||||
|
|
||||||
service_id, port_id = ARGV
|
service_id, port_id = ARGV
|
||||||
|
|
||||||
puts Service.get_by_id(service_id).not_nil!.ports[port_id]
|
puts context.get_service_by_id(service_id).not_nil!.ports[port_id]
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@ require "option_parser"
|
||||||
require "yaml"
|
require "yaml"
|
||||||
require "colorize"
|
require "colorize"
|
||||||
|
|
||||||
require "weird-crystal-base"
|
|
||||||
|
|
||||||
require "./config.cr"
|
require "./config.cr"
|
||||||
|
|
||||||
require "./service/*"
|
require "./service/*"
|
||||||
|
@ -15,12 +13,6 @@ args = [] of String
|
||||||
force = false
|
force = false
|
||||||
verbose = false
|
verbose = false
|
||||||
|
|
||||||
class Service::Context < Weird::Base
|
|
||||||
property pid_directory = PID_DIRECTORY
|
|
||||||
property log_directory = LOG_DIRECTORY
|
|
||||||
property services_directory = RC_DIRECTORY
|
|
||||||
end
|
|
||||||
|
|
||||||
alias Command = Proc(Service::Context, Array(String), Nil)
|
alias Command = Proc(Service::Context, Array(String), Nil)
|
||||||
alias CommandTuple = Tuple(String, String, Command)
|
alias CommandTuple = Tuple(String, String, Command)
|
||||||
class CommandsList
|
class CommandsList
|
||||||
|
@ -53,7 +45,7 @@ commands.push "add", "Adds a service to an environment." do |context, args|
|
||||||
domain = nil
|
domain = nil
|
||||||
ports = Hash(String, Int32).new
|
ports = Hash(String, Int32).new
|
||||||
|
|
||||||
if Service.get_by_id args[0]
|
if context.get_service_by_id args[0]
|
||||||
raise ::Service::Exception.new "'#{args[0]}' already exists. You have to remove it before re-adding it."
|
raise ::Service::Exception.new "'#{args[0]}' already exists. You have to remove it before re-adding it."
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
@ -85,7 +77,7 @@ commands.push "add", "Adds a service to an environment." do |context, args|
|
||||||
end
|
end
|
||||||
|
|
||||||
# FIXME: Some of that code is ugly and should not even be here.
|
# FIXME: Some of that code is ugly and should not even be here.
|
||||||
Service.new(service, environment).tap do |service|
|
Service.new(context, service, environment).tap do |service|
|
||||||
if domain
|
if domain
|
||||||
service.domain = domain
|
service.domain = domain
|
||||||
end
|
end
|
||||||
|
@ -119,17 +111,17 @@ commands.push "add", "Adds a service to an environment." do |context, args|
|
||||||
if number.nil?
|
if number.nil?
|
||||||
default_port = definition.default_value
|
default_port = definition.default_value
|
||||||
|
|
||||||
if default_port && ! Service.is_port_used default_port, ports.map { |k, v| v }
|
if default_port && ! context.is_port_used default_port, ports.map { |k, v| v }
|
||||||
number = default_port
|
number = default_port
|
||||||
ports[name] = number
|
ports[name] = number
|
||||||
end
|
end
|
||||||
elsif Service.is_port_used number
|
elsif context.is_port_used number
|
||||||
raise Service::Exception.new "Port #{number} is already reserved by another service."
|
raise Service::Exception.new "Port #{number} is already reserved by another service."
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
if number.nil?
|
if number.nil?
|
||||||
number = Service.get_free_port ports.map { |k, v| v }
|
number = context.get_free_port ports.map { |k, v| v }
|
||||||
ports[name] = number
|
ports[name] = number
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -168,7 +160,7 @@ commands.push "del", "Removes a service from an environment." do |context, args|
|
||||||
|
|
||||||
rvalue = 0
|
rvalue = 0
|
||||||
args.each do |id|
|
args.each do |id|
|
||||||
service = Service.get_by_id(id)
|
service = context.get_service_by_id(id)
|
||||||
|
|
||||||
if service.nil?
|
if service.nil?
|
||||||
context.error "#{id}: no such service"
|
context.error "#{id}: no such service"
|
||||||
|
@ -200,7 +192,7 @@ end
|
||||||
|
|
||||||
commands.push "start", "Starts a service." do |context, args|
|
commands.push "start", "Starts a service." do |context, args|
|
||||||
services = args.map do |arg|
|
services = args.map do |arg|
|
||||||
service = Service.get_by_id(arg)
|
service = context.get_service_by_id(arg)
|
||||||
|
|
||||||
unless service
|
unless service
|
||||||
raise Service::Exception.new "Service '#{arg}' does not exist."
|
raise Service::Exception.new "Service '#{arg}' does not exist."
|
||||||
|
@ -218,7 +210,7 @@ end
|
||||||
|
|
||||||
commands.push "stop", "Stops a running service." do |context, args|
|
commands.push "stop", "Stops a running service." do |context, args|
|
||||||
services = args.map do |arg|
|
services = args.map do |arg|
|
||||||
service = Service.get_by_id(arg)
|
service = context.get_service_by_id(arg)
|
||||||
|
|
||||||
unless service
|
unless service
|
||||||
raise Service::Exception.new "Service '#{arg}' does not exist."
|
raise Service::Exception.new "Service '#{arg}' does not exist."
|
||||||
|
@ -238,6 +230,27 @@ commands.push "stop", "Stops a running service." do |context, args|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
commands.push "reload", "Updates configuration and reloads services." do |context, args|
|
||||||
|
services = args.map do |arg|
|
||||||
|
service = context.get_service_by_id(arg)
|
||||||
|
|
||||||
|
unless service
|
||||||
|
raise Service::Exception.new "Service '#{arg}' does not exist."
|
||||||
|
end
|
||||||
|
|
||||||
|
service
|
||||||
|
end
|
||||||
|
|
||||||
|
services.each do |service|
|
||||||
|
if ! service.running? PID_DIRECTORY
|
||||||
|
context.warning "#{service.to_s} is not currently running."
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
service.reload context
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
commands.push "status", "Prints the status of services." do |context, args|
|
commands.push "status", "Prints the status of services." do |context, args|
|
||||||
ENV["SERVICE_VERBOSE"] = verbose.to_s
|
ENV["SERVICE_VERBOSE"] = verbose.to_s
|
||||||
|
|
||||||
|
@ -263,7 +276,7 @@ commands.push "show", "Shows a service's configuration and state." do |context,
|
||||||
args.each do |arg|
|
args.each do |arg|
|
||||||
environment_name, service_name = Service.parse_id arg
|
environment_name, service_name = Service.parse_id arg
|
||||||
|
|
||||||
service = Service.all.find do |service|
|
service = context.services.find do |service|
|
||||||
service.name == service_name &&
|
service.name == service_name &&
|
||||||
service.environment.name == environment_name
|
service.environment.name == environment_name
|
||||||
end
|
end
|
||||||
|
@ -283,11 +296,11 @@ commands.push "add-environment", "Creates a new (empty) environment." do |contex
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
|
|
||||||
Environment.new(args[0]).write ENVIRONMENTS_DIRECTORY
|
Environment.new(context, args[0]).write ENVIRONMENTS_DIRECTORY
|
||||||
end
|
end
|
||||||
|
|
||||||
commands.push "list-environments", "Lists all currently defined environments.s", do |context, args|
|
commands.push "list-environments", "Lists all currently defined environments.s", do |context, args|
|
||||||
Environment.all.map do |env|
|
context.environments.map do |env|
|
||||||
puts env.to_s
|
puts env.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -296,7 +309,7 @@ commands.push "del-environment", "Removes an empty environment." do |context, ar
|
||||||
rvalue = 0
|
rvalue = 0
|
||||||
|
|
||||||
args.each do |arg|
|
args.each do |arg|
|
||||||
environment = Environment.all.find &.name.==(arg)
|
environment = context.environments.find &.name.==(arg)
|
||||||
|
|
||||||
if environment.nil?
|
if environment.nil?
|
||||||
STDERR.puts "#{arg}: no such environment"
|
STDERR.puts "#{arg}: no such environment"
|
||||||
|
@ -304,7 +317,7 @@ commands.push "del-environment", "Removes an empty environment." do |context, ar
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
if Service.all.select(&.environment.name.==(environment.name)).size > 0
|
if context.services.select(&.environment.name.==(environment.name)).size > 0
|
||||||
STDERR.puts "#{arg}: is not empty"
|
STDERR.puts "#{arg}: is not empty"
|
||||||
rvalue = 1
|
rvalue = 1
|
||||||
next
|
next
|
||||||
|
@ -352,11 +365,8 @@ if command.nil?
|
||||||
exit 1
|
exit 1
|
||||||
end
|
end
|
||||||
|
|
||||||
ServiceDefinition.load SERVICES_DIRECTORY
|
|
||||||
Environment.load ENVIRONMENTS_DIRECTORY
|
|
||||||
Service.load RC_DIRECTORY
|
|
||||||
|
|
||||||
context = Service::Context.new
|
context = Service::Context.new
|
||||||
|
context.load
|
||||||
|
|
||||||
begin
|
begin
|
||||||
args.shift
|
args.shift
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
require "weird-crystal-base"
|
||||||
|
|
||||||
|
class Service
|
||||||
|
end
|
||||||
|
|
||||||
|
class Service::Context < Weird::Base
|
||||||
|
property pid_directory = PID_DIRECTORY
|
||||||
|
property log_directory = LOG_DIRECTORY
|
||||||
|
property services_directory = RC_DIRECTORY
|
||||||
|
property service_definitions_directory = SERVICES_DIRECTORY
|
||||||
|
property environments_directory = ENVIRONMENTS_DIRECTORY
|
||||||
|
|
||||||
|
# FIXME: Namespaces. 😬
|
||||||
|
getter services = [] of Service
|
||||||
|
getter service_definitions = [] of ServiceDefinition
|
||||||
|
getter environments = [] of Environment
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@environments = [Environment.new self]
|
||||||
|
end
|
||||||
|
def root_environment
|
||||||
|
@environments[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_services
|
||||||
|
path = services_directory
|
||||||
|
|
||||||
|
return unless Dir.exists? path
|
||||||
|
|
||||||
|
Dir.each_child path do |child|
|
||||||
|
unless child.match /\.spec$/
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
specs = SpecParser.parse(File.read "#{path}/#{child}").not_nil!
|
||||||
|
rescue
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
@services << Service.new self, specs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_environments
|
||||||
|
path = environments_directory
|
||||||
|
|
||||||
|
return unless Dir.exists? path
|
||||||
|
|
||||||
|
Dir.each_child path do |child|
|
||||||
|
unless child.match /\.spec$/
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
file_path = "#{path}/#{child}"
|
||||||
|
|
||||||
|
begin
|
||||||
|
name = File.basename(child, ".spec")
|
||||||
|
specs = SpecParser.parse File.read(file_path)
|
||||||
|
|
||||||
|
environment = Environment.new self, name, specs
|
||||||
|
rescue e
|
||||||
|
STDERR << "error loading #{file_path}: " << e << "\n"
|
||||||
|
# FIXME: Print stacktrace? Debug mode?
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
@environments << environment
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_service_definitions
|
||||||
|
path = service_definitions_directory
|
||||||
|
|
||||||
|
Dir.each_child path do |child|
|
||||||
|
if child.match /\.spec$/
|
||||||
|
name = File.basename(child, ".spec")
|
||||||
|
specs = SpecParser.parse File.read "#{path}/#{child}"
|
||||||
|
|
||||||
|
@service_definitions << ServiceDefinition.new name, specs
|
||||||
|
else
|
||||||
|
next
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def load
|
||||||
|
load_service_definitions
|
||||||
|
load_environments
|
||||||
|
load_services
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_service_by_id(id)
|
||||||
|
matches = id.match /[^\/]*/
|
||||||
|
unless matches # Should not happen, above regex would always match.
|
||||||
|
raise Exception.new "FIXME"
|
||||||
|
end
|
||||||
|
environment_name, service_name = Service.parse_id id
|
||||||
|
|
||||||
|
@services.find do |service|
|
||||||
|
service.name == service_name && service.environment.name == environment_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_environment_by_name(name)
|
||||||
|
_def = @environments.find &.name.==(name)
|
||||||
|
|
||||||
|
if _def.nil?
|
||||||
|
raise ::Service::Exception.new "Environment '#{name}' does not exist."
|
||||||
|
end
|
||||||
|
|
||||||
|
_def
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_used_ports(other_reservations = Array(Int32).new)
|
||||||
|
services.map(&.ports.to_a)
|
||||||
|
.flatten
|
||||||
|
.map { |k, v| v }
|
||||||
|
.+(other_reservations)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_free_port(other_reservations = Array(Int32).new)
|
||||||
|
port = 49152
|
||||||
|
|
||||||
|
used_ports = get_used_ports other_reservations
|
||||||
|
|
||||||
|
while used_ports.any? &.==(port)
|
||||||
|
port = port + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
port
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_service_definition_by_name(name)
|
||||||
|
_def = @service_definitions.find &.name.==(name)
|
||||||
|
|
||||||
|
if _def.nil?
|
||||||
|
raise Exception.new "Service '#{name}' does not exist."
|
||||||
|
end
|
||||||
|
|
||||||
|
_def
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_port_used(port, other_reservations = Array(Int32).new)
|
||||||
|
used_ports = get_used_ports other_reservations
|
||||||
|
|
||||||
|
used_ports.any? &.==(port)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
require "specparser"
|
require "specparser"
|
||||||
|
|
||||||
|
require "./context.cr"
|
||||||
|
|
||||||
class Environment
|
class Environment
|
||||||
enum Type
|
enum Type
|
||||||
Prefix
|
Prefix
|
||||||
|
@ -13,17 +15,19 @@ class Environment
|
||||||
# The place we’ll put services’ data and configuration.
|
# The place we’ll put services’ data and configuration.
|
||||||
@root : String?
|
@root : String?
|
||||||
|
|
||||||
def initialize()
|
@context : Service::Context
|
||||||
initialize "root"
|
|
||||||
|
def initialize(context)
|
||||||
|
initialize context, "root"
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(@name, type = "prefix")
|
def initialize(@context, @name, type = "prefix")
|
||||||
@type = Type.parse type
|
@type = Type.parse type
|
||||||
|
|
||||||
@files = Array(ServiceDefinition::FileDefinition).new
|
@files = Array(ServiceDefinition::FileDefinition).new
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(@name, specs : SpecParser)
|
def initialize(@context, @name, specs : SpecParser)
|
||||||
assignments = specs.assignments
|
assignments = specs.assignments
|
||||||
|
|
||||||
assignments["type"].try &.as_s.tap do |type|
|
assignments["type"].try &.as_s.tap do |type|
|
||||||
|
@ -39,34 +43,6 @@ class Environment
|
||||||
@root || "#{SERVED_DATA_DIRECTORY}/#{@name}"
|
@root || "#{SERVED_DATA_DIRECTORY}/#{@name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
class_getter root = Environment.new
|
|
||||||
class_getter all = [@@root] of Environment
|
|
||||||
|
|
||||||
def self.load(path)
|
|
||||||
return unless Dir.exists? path
|
|
||||||
|
|
||||||
Dir.each_child path do |child|
|
|
||||||
unless child.match /\.spec$/
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
file_path = "#{path}/#{child}"
|
|
||||||
|
|
||||||
begin
|
|
||||||
name = File.basename(child, ".spec")
|
|
||||||
specs = SpecParser.parse File.read(file_path)
|
|
||||||
|
|
||||||
environment = Environment.new name, specs
|
|
||||||
rescue e
|
|
||||||
STDERR << "error loading #{file_path}: " << e << "\n"
|
|
||||||
# FIXME: Print stacktrace? Debug mode?
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
@@all << environment
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def write(dir : String)
|
def write(dir : String)
|
||||||
File.write "#{dir}/#{@name}.spec", to_spec
|
File.write "#{dir}/#{@name}.spec", to_spec
|
||||||
end
|
end
|
||||||
|
@ -81,18 +57,8 @@ class Environment
|
||||||
].join("\n") + "\n"
|
].join("\n") + "\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get(name)
|
|
||||||
_def = @@all.find &.name.==(name)
|
|
||||||
|
|
||||||
if _def.nil?
|
|
||||||
raise ::Service::Exception.new "Environment '#{name}' does not exist."
|
|
||||||
end
|
|
||||||
|
|
||||||
_def
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_provider(token)
|
def get_provider(token)
|
||||||
Service.all.find do |service|
|
@context.services.find do |service|
|
||||||
service.environment == self && service.provides? token
|
service.environment == self && service.provides? token
|
||||||
end.try &.id
|
end.try &.id
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,7 @@ require "yaml"
|
||||||
require "colorize"
|
require "colorize"
|
||||||
require "file_utils"
|
require "file_utils"
|
||||||
|
|
||||||
|
require "./context.cr"
|
||||||
require "./service_definition.cr"
|
require "./service_definition.cr"
|
||||||
require "./environment.cr"
|
require "./environment.cr"
|
||||||
require "./libc.cr"
|
require "./libc.cr"
|
||||||
|
@ -30,7 +31,7 @@ end
|
||||||
|
|
||||||
class Service
|
class Service
|
||||||
getter environment : Environment
|
getter environment : Environment
|
||||||
getter providers = ProvidersList.new
|
getter providers : ProvidersList
|
||||||
|
|
||||||
setter name : String?
|
setter name : String?
|
||||||
property domain : String?
|
property domain : String?
|
||||||
|
@ -39,12 +40,19 @@ class Service
|
||||||
# The place we’ll store configuration and data.
|
# The place we’ll store configuration and data.
|
||||||
@root : String?
|
@root : String?
|
||||||
|
|
||||||
|
@context : Context
|
||||||
|
|
||||||
class Exception < ::Exception
|
class Exception < ::Exception
|
||||||
end
|
end
|
||||||
|
|
||||||
class ProvidersList < Hash(String, String)
|
class ProvidersList < Hash(String, String)
|
||||||
|
@context : Service::Context
|
||||||
|
def initialize(@context)
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
def []?(name)
|
def []?(name)
|
||||||
super(name).try { |x| Service.get_by_id x}
|
super(name).try { |x| @context.get_service_by_id x}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -55,16 +63,18 @@ class Service
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(name, environment_name : String?)
|
def initialize(@context : Context, name, environment_name : String?)
|
||||||
|
@providers = ProvidersList.new @context
|
||||||
@reference = ServiceDefinition.get name
|
@reference = ServiceDefinition.get name
|
||||||
@environment = if environment_name.nil? || environment_name == ""
|
@environment = if environment_name.nil? || environment_name == ""
|
||||||
Environment.root
|
@context.root_environment
|
||||||
else
|
else
|
||||||
Environment.get environment_name
|
@context.get_environment_by_name environment_name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(specs : SpecParser)
|
def initialize(@context : Context, specs : SpecParser)
|
||||||
|
@providers = ProvidersList.new @context
|
||||||
assignments = specs.assignments
|
assignments = specs.assignments
|
||||||
|
|
||||||
# Complicated because of compat with when services had no dedicated
|
# Complicated because of compat with when services had no dedicated
|
||||||
|
@ -77,9 +87,9 @@ class Service
|
||||||
|
|
||||||
env = assignments["environment"]?.try &.as_s
|
env = assignments["environment"]?.try &.as_s
|
||||||
@environment = if env.nil? || env == ""
|
@environment = if env.nil? || env == ""
|
||||||
Environment.root
|
@context.root_environment
|
||||||
else
|
else
|
||||||
Environment.get env
|
@context.get_environment_by_name env
|
||||||
end
|
end
|
||||||
|
|
||||||
@root = assignments["root"]?.try &.as_s
|
@root = assignments["root"]?.try &.as_s
|
||||||
|
@ -164,6 +174,9 @@ class Service
|
||||||
def stop_command
|
def stop_command
|
||||||
@reference.stop_command
|
@reference.stop_command
|
||||||
end
|
end
|
||||||
|
def reload_command
|
||||||
|
@reference.reload_command
|
||||||
|
end
|
||||||
def provides
|
def provides
|
||||||
@reference.provides
|
@reference.provides
|
||||||
end
|
end
|
||||||
|
@ -197,11 +210,16 @@ class Service
|
||||||
env["SERVICE_NAME"] = name
|
env["SERVICE_NAME"] = name
|
||||||
env["SERVICE_ROOT"] = root
|
env["SERVICE_ROOT"] = root
|
||||||
env["SERVICE_ID"] = full_id
|
env["SERVICE_ID"] = full_id
|
||||||
|
if _pid = pid @context.pid_directory
|
||||||
|
env["SERVICE_PID"] = _pid.to_s
|
||||||
|
end
|
||||||
|
|
||||||
env["ENVIRONMENT"] = @environment.name
|
env["ENVIRONMENT"] = @environment.name
|
||||||
env["ENVIRONMENT_TYPE"] = @environment.type.to_s
|
env["ENVIRONMENT_TYPE"] = @environment.type.to_s
|
||||||
|
|
||||||
|
|
||||||
@providers.each do |token, provider|
|
@providers.each do |token, provider|
|
||||||
service_provider = Service.get_by_id provider
|
service_provider = @context.get_service_by_id provider
|
||||||
|
|
||||||
# FIXME: Warning?
|
# FIXME: Warning?
|
||||||
next if service_provider.nil?
|
next if service_provider.nil?
|
||||||
|
@ -248,17 +266,7 @@ class Service
|
||||||
@environment.files + @reference.files
|
@environment.files + @reference.files
|
||||||
end
|
end
|
||||||
|
|
||||||
def start(context : Context)
|
def build_files!(context : Context)
|
||||||
return if running? context.pid_directory
|
|
||||||
|
|
||||||
if non_runnable
|
|
||||||
context.title "Setting up #{to_s}"
|
|
||||||
else
|
|
||||||
context.title "Starting #{to_s}"
|
|
||||||
end
|
|
||||||
|
|
||||||
FileUtils.mkdir_p root
|
|
||||||
|
|
||||||
files.each do |file|
|
files.each do |file|
|
||||||
run_hook = false
|
run_hook = false
|
||||||
|
|
||||||
|
@ -289,6 +297,20 @@ class Service
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def start(context : Context)
|
||||||
|
return if running? context.pid_directory
|
||||||
|
|
||||||
|
if non_runnable
|
||||||
|
context.title "Setting up #{to_s}"
|
||||||
|
else
|
||||||
|
context.title "Starting #{to_s}"
|
||||||
|
end
|
||||||
|
|
||||||
|
FileUtils.mkdir_p root
|
||||||
|
|
||||||
|
build_files! context
|
||||||
|
|
||||||
return if non_runnable
|
return if non_runnable
|
||||||
|
|
||||||
|
@ -347,6 +369,28 @@ class Service
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reloadable?
|
||||||
|
!@reload_command.nil?
|
||||||
|
end
|
||||||
|
def reload(context : Context)
|
||||||
|
build_files! context
|
||||||
|
|
||||||
|
command = reload_command
|
||||||
|
|
||||||
|
unless command
|
||||||
|
raise Exception.new "This service cannot be reloaded!"
|
||||||
|
end
|
||||||
|
|
||||||
|
Process.fork do
|
||||||
|
Dir.cd root
|
||||||
|
|
||||||
|
Process.exec "sh", ["-c", command],
|
||||||
|
output: Process::Redirect::Inherit,
|
||||||
|
error: Process::Redirect::Inherit,
|
||||||
|
env: commands_environment
|
||||||
|
end.wait
|
||||||
|
end
|
||||||
|
|
||||||
def get_pid_file(pid_dir)
|
def get_pid_file(pid_dir)
|
||||||
"#{pid_dir}/#{name}.#{environment.name}.pid"
|
"#{pid_dir}/#{name}.#{environment.name}.pid"
|
||||||
end
|
end
|
||||||
|
@ -445,25 +489,6 @@ class Service
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
class_getter all = [] of Service
|
|
||||||
def self.load(path)
|
|
||||||
return unless Dir.exists? path
|
|
||||||
|
|
||||||
Dir.each_child path do |child|
|
|
||||||
unless child.match /\.spec$/
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
specs = SpecParser.parse(File.read "#{path}/#{child}").not_nil!
|
|
||||||
rescue
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
@@all << Service.new specs
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def write(path)
|
def write(path)
|
||||||
FileUtils.mkdir_p "#{path}"
|
FileUtils.mkdir_p "#{path}"
|
||||||
File.write "#{path}/#{name}.#{@environment.name}.spec", to_spec
|
File.write "#{path}/#{name}.#{@environment.name}.spec", to_spec
|
||||||
|
@ -502,17 +527,6 @@ class Service
|
||||||
File.delete "#{context.services_directory}/#{name}.#{@environment.name}.spec"
|
File.delete "#{context.services_directory}/#{name}.#{@environment.name}.spec"
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get_by_id(id)
|
|
||||||
matches = id.match /[^\/]*/
|
|
||||||
unless matches # Should not happen, above regex would always match.
|
|
||||||
raise Exception.new "FIXME"
|
|
||||||
end
|
|
||||||
environment_name, service_name = Service.parse_id id
|
|
||||||
|
|
||||||
@@all.find do |service|
|
|
||||||
service.name == service_name && service.environment.name == environment_name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
def is_id?(id)
|
def is_id?(id)
|
||||||
id == self.id || (@environment.name == "root" && id == "root/#{name}")
|
id == self.id || (@environment.name == "root" && id == "root/#{name}")
|
||||||
end
|
end
|
||||||
|
@ -531,31 +545,6 @@ class Service
|
||||||
{environment, service}
|
{environment, service}
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get_used_ports(other_reservations = Array(Int32).new)
|
|
||||||
Service.all.map(&.ports.to_a)
|
|
||||||
.flatten
|
|
||||||
.map { |k, v| v }
|
|
||||||
.+(other_reservations)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.get_free_port(other_reservations = Array(Int32).new)
|
|
||||||
port = 49152
|
|
||||||
|
|
||||||
used_ports = Service.get_used_ports other_reservations
|
|
||||||
|
|
||||||
while used_ports.any? &.==(port)
|
|
||||||
port = port + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
port
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.is_port_used(port, other_reservations = Array(Int32).new)
|
|
||||||
used_ports = Service.get_used_ports other_reservations
|
|
||||||
|
|
||||||
used_ports.any? &.==(port)
|
|
||||||
end
|
|
||||||
|
|
||||||
alias ServiceTree = Array(ServiceTree) | Service
|
alias ServiceTree = Array(ServiceTree) | Service
|
||||||
|
|
||||||
# Returns a dependency tree.
|
# Returns a dependency tree.
|
||||||
|
@ -564,7 +553,7 @@ class Service
|
||||||
tree = [self] of ServiceTree
|
tree = [self] of ServiceTree
|
||||||
|
|
||||||
@providers.each do |token, provider_id|
|
@providers.each do |token, provider_id|
|
||||||
service = Service.get_by_id provider_id
|
service = @context.get_service_by_id provider_id
|
||||||
|
|
||||||
unless service
|
unless service
|
||||||
# FIXME: Does it make the dep tree invalid?
|
# FIXME: Does it make the dep tree invalid?
|
||||||
|
@ -585,7 +574,7 @@ class Service
|
||||||
while i < rdeps.size
|
while i < rdeps.size
|
||||||
item = rdeps[i]
|
item = rdeps[i]
|
||||||
|
|
||||||
@@all.each do |service|
|
@context.services.each do |service|
|
||||||
service.providers.any? do |token, id|
|
service.providers.any? do |token, id|
|
||||||
if item.is_id?(id) && ! rdeps.any? service
|
if item.is_id?(id) && ! rdeps.any? service
|
||||||
rdeps << service
|
rdeps << service
|
||||||
|
@ -600,7 +589,7 @@ class Service
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_default_provider(token) : String?
|
def get_default_provider(token) : String?
|
||||||
@environment.get_provider(token) || Environment.root.get_provider(token)
|
@environment.get_provider(token) || @context.root_environment.get_provider(token)
|
||||||
end
|
end
|
||||||
|
|
||||||
def consumes?(token, origin)
|
def consumes?(token, origin)
|
||||||
|
@ -610,7 +599,7 @@ class Service
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_consumers(token)
|
def get_consumers(token)
|
||||||
Service.all.select(&.consumes?(token, self))
|
@context.services.select(&.consumes?(token, self))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ class ServiceDefinition
|
||||||
getter name : String
|
getter name : String
|
||||||
getter command : String
|
getter command : String
|
||||||
getter stop_command : String?
|
getter stop_command : String?
|
||||||
|
getter reload_command : String?
|
||||||
getter directory : String?
|
getter directory : String?
|
||||||
getter user : String?
|
getter user : String?
|
||||||
getter provides : String?
|
getter provides : String?
|
||||||
|
@ -91,6 +92,7 @@ class ServiceDefinition
|
||||||
@command = specs["command"].as_s
|
@command = specs["command"].as_s
|
||||||
@non_runnable = (@command == "none")
|
@non_runnable = (@command == "none")
|
||||||
@stop_command = specs["stop-command"]?.try &.as_s
|
@stop_command = specs["stop-command"]?.try &.as_s
|
||||||
|
@reload_command = specs["reload-command"]?.try &.as_s
|
||||||
@directory = specs["directory"]?.try &.as_s
|
@directory = specs["directory"]?.try &.as_s
|
||||||
@user = specs["user"]?.try &.as_s
|
@user = specs["user"]?.try &.as_s
|
||||||
@provides = specs["provides"]?.try &.as_a_or_s.map { |x| Provides.new x } || Array(Provides).new
|
@provides = specs["provides"]?.try &.as_a_or_s.map { |x| Provides.new x } || Array(Provides).new
|
||||||
|
@ -148,19 +150,6 @@ class ServiceDefinition
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.load(path)
|
|
||||||
Dir.each_child path do |child|
|
|
||||||
if child.match /\.spec$/
|
|
||||||
name = File.basename(child, ".spec")
|
|
||||||
specs = SpecParser.parse File.read "#{path}/#{child}"
|
|
||||||
|
|
||||||
@@all << ServiceDefinition.new name, specs
|
|
||||||
else
|
|
||||||
next
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.get(name) : ServiceDefinition
|
def self.get(name) : ServiceDefinition
|
||||||
_def = @@all.find &.name.==(name)
|
_def = @@all.find &.name.==(name)
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@ require "./service/service.cr"
|
||||||
|
|
||||||
require "./config.cr"
|
require "./config.cr"
|
||||||
|
|
||||||
ServiceDefinition.load SERVICES_DIRECTORY
|
context = Service::Context.new
|
||||||
Environment.load ENVIRONMENTS_DIRECTORY
|
|
||||||
Service.load RC_DIRECTORY
|
context.load
|
||||||
|
|
||||||
LibC.setuid 0
|
LibC.setuid 0
|
||||||
LibC.setgid 0
|
LibC.setgid 0
|
||||||
|
@ -16,10 +16,10 @@ list_status = false
|
||||||
services = ARGV
|
services = ARGV
|
||||||
if services.size == 0
|
if services.size == 0
|
||||||
list_status = true
|
list_status = true
|
||||||
services = Service.all
|
services = context.services
|
||||||
else
|
else
|
||||||
services = services.map do |id|
|
services = services.map do |id|
|
||||||
Service.get_by_id id
|
context.get_service_by_id id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue