Skip to content

Commit

Permalink
Enhance service creation
Browse files Browse the repository at this point in the history
  • Loading branch information
j8r committed Jan 25, 2020
1 parent cc6088d commit e2a70c9
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 133 deletions.
22 changes: 13 additions & 9 deletions spec/service_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,31 @@ module Service
class Systemd
def self.version=(@@version)
end

# systemctl may not exist
private def daemon_reload
end
end
end

def spec_with_service_app(service, &block)
Service.init = service
struct DPPM::Prefix::App
def service=(@service)
end
end

def spec_with_service_app(service, &block)
spec_with_tempdir do |path|
test_prefix = DPPM::Prefix.new path
test_prefix.create
test_prefix.ensure_app_dir
test_app = test_prefix.new_app(TEST_APP_PACKAGE_NAME)
FileUtils.cp_r Path[SAMPLES_DIR, TEST_APP_PACKAGE_NAME].to_s, test_app.path.to_s

test_app.service.file = test_app.service_file
test_app.service = service.new test_app.name
test_app.service.file = test_app.service_path / "test_service"
test_app.service_create.config

begin
yield test_app
ensure
Service.init = nil
end
yield test_app
end
end

Expand Down Expand Up @@ -69,7 +73,7 @@ def assert_service(service, file = __FILE__, line = __LINE__)
it "creates a service file building", file, line do
spec_with_service_app service do |app|
service_config = String.build do |str|
app.service.config_build str
app.service.config.build str
end
File.read(app.service_file).should eq service_config
end
Expand Down
4 changes: 1 addition & 3 deletions spec/spec_helper.cr
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,4 @@ def spec_with_tempdir(directory : String = spec_temp_prefix, &block)
end
end

Spec.before_each do
DPPM::Logger.output = DPPM::Logger.error = File.open File::NULL, "w"
end
DPPM::Logger.output = DPPM::Logger.error = File.open File::NULL, "w"
2 changes: 1 addition & 1 deletion src/cli/app.cr
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ module DPPM::CLI::App
custom_vars.each do |arg|
case arg
when .includes? '='
key, value = arg.split '=', 2
key, _, value = arg.partition '='
raise "Only `a-z`, `A-Z`, `0-9` and `_` are allowed as variable name: " + arg if !Utils.ascii_alphanumeric_underscore? key
vars[key] = value
else
Expand Down
4 changes: 3 additions & 1 deletion src/cli/service.cr
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ module DPPM::CLI::Service

def app_status(prefix : String = PREFIX, &block)
Prefix.new(prefix).each_app do |app|
yield app.service
if service = app.service?
yield service
end
end
end
end
73 changes: 32 additions & 41 deletions src/prefix/app.cr
Original file line number Diff line number Diff line change
Expand Up @@ -51,37 +51,40 @@ struct DPPM::Prefix::App
exec || raise "No `exec` key present in #{pkg_file.path}"
end

@service_intialized = false
# Service directory.
getter service_path : Path { conf_path / "init" }

# Default service file location.
getter service_default_file : Path { service_path / service.type }

# Service file location.
getter service_file : Path { service_path / "service" }

# Returns the system service, if available.
def service? : Service::OpenRC | Service::Systemd | Nil
if !@service_intialized
if service = Service.init?
@service = service.new @name
getter? service : Service::OpenRC | Service::Systemd | Nil do
if service_init = Service.init?
service_symlink = service_file.to_s
service = service_init.new @name
if File.exists?(service_symlink) && service.exists? && File.real_path(service_symlink) == service.file.to_s
service
end
@service_intialized = true
end
@service
end

# Returns the system service of the application. Raise if not present.
getter service : Service::OpenRC | Service::Systemd do
service? || raise "Service not available"
end

# Service directory.
getter service_path : Path do
conf_path / "init"
end

# Service file location.
getter service_file : Path do
service_path / service.type
end

# Creates a new system service
def service_create(database_name : String? = nil) : Service::OpenRC | Service::Systemd
def service_create(service_dependency : String? = nil) : Service::OpenRC | Service::Systemd
@service ||= Service.init.new @name
Logger.info "Creating system service", service.name

Dir.mkdir_p service_path.to_s
if File.exists? service_default_file
FileUtils.cp service_default_file.to_s, service.file.to_s
end

# Set service options
service.config.user = owner.user.name
Expand All @@ -91,7 +94,7 @@ struct DPPM::Prefix::App
service.config.log_output = log_file_output.to_s
service.config.log_error = log_file_error.to_s
service.config.command = (path / exec["start"]).to_s
service.config.after << database_name if database_name
service.config.after << service_dependency if service_dependency

# add a reload directive if available
if exec_reload = exec["reload"]?
Expand All @@ -105,15 +108,12 @@ struct DPPM::Prefix::App
if pkg_env = pkg_file.env
service.config.env_vars.merge! pkg_env
end
File.open service_file, "w" do |io|
service.config_build io
end
service
end

# Enable system service by creating a symlink.
def service_enable
service.link service_file.to_s
service.write_config
File.symlink service.file.to_s, service_file.to_s
Logger.info service.type + " system service added", service.name

service
end

# Creates a new database for this application.
Expand Down Expand Up @@ -744,10 +744,7 @@ struct DPPM::Prefix::App
if database_app
database_name = database_app.name
end
Logger.info "creating system service", service.name
service_create database_name
service_enable
Logger.info service.type + " system service added", service.name
service_create service_dependency: database_name
end
Utils.chown_r @path.to_s, uid, gid
end
Expand Down Expand Up @@ -821,12 +818,8 @@ struct DPPM::Prefix::App

# Checks
if service?
if service.exists?
Logger.info "a system service is found", @name
service.check_delete
else
Logger.warn "no system service found", @name
end
Logger.info "a system service is found", @name
service.check_delete
end

if confirmation
Expand All @@ -846,10 +839,8 @@ struct DPPM::Prefix::App
Logger.info "deleting", @path.to_s

if service = service?
if service.exists?
Logger.info "deleting system service", service.name
service.delete
end
Logger.info "deleting system service", service.name
service.delete
end

begin
Expand Down
6 changes: 3 additions & 3 deletions src/service/config.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Service::Config
abstract class Service::Config
property user : String? = nil,
group : String? = nil,
directory : String? = nil,
Expand All @@ -9,11 +9,11 @@ class Service::Config
log_error : String? = nil,
env_vars : Hash(String, String) = Hash(String, String).new,
after : Set(String) = Set(String).new,
want : Set(String) = Set(String).new,
umask : String? = "007",
restart_delay : UInt32? = 9_u32

def initialize
end
abstract def build(io : IO)

def parse_env_vars(env_vars : String)
env_vars.rchop.split("\" ").each do |env|
Expand Down
18 changes: 12 additions & 6 deletions src/service/init_system.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ module Service::InitSystem
file : Path,
boot_file : Path

private abstract def config_parse(io : IO)
private abstract def config_build(io : IO)

getter config : Config do
if @file && File.exists? @file.to_s
File.open @file.to_s do |io|
config_parse io
@config_class.new io
end
else
Config.new
@config_class.new
end
end

abstract def write_config
abstract def delete

private def internal_write_config
File.open @file, "w" do |io|
config.build io
end
end

Expand Down Expand Up @@ -49,7 +55,7 @@ module Service::InitSystem
File.real_path @file.to_s
end

private def delete_internal
private def internal_delete
stop if run?
boot false if boot?
File.delete @file.to_s if exists?
Expand Down
15 changes: 4 additions & 11 deletions src/service/openrc.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ require "./init_system"

class Service::OpenRC
include InitSystem
@config_class = OpenRC::Config
class_getter type : String = "openrc"

class_getter version : String do
Expand All @@ -27,11 +28,11 @@ class Service::OpenRC
end

def delete
delete_internal
internal_delete
end

def link(service_file : String)
File.symlink service_file, @file.to_s
def write_config
internal_write_config
File.chmod @file.to_s, 0o750
end

Expand All @@ -40,14 +41,6 @@ class Service::OpenRC
Service.exec? "/sbin/rc-service", {@name, {{action}}}
end
{% end %}

private def config_parse(io : IO)
Config.from_openrc io
end

def config_build(io : IO)
config.to_openrc io
end
end

require "./openrc_config"
39 changes: 20 additions & 19 deletions src/service/openrc_config.cr
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
require "./config"

class Service::Config
class Service::OpenRC::Config < Service::Config
private OPENRC_RELOAD_COMMAND = "supervise-daemon --pidfile \"$pidfile\" --signal "
private OPENRC_PIDFILE = "pidfile=\"/run/${RC_SVCNAME}.pid\""
private OPENRC_SHEBANG = "#!/sbin/openrc-run"
private OPENRC_SUPERVISOR = "supervisor=supervise-daemon"
private OPENRC_ENV_VARS_PREFIX = "supervise_daemon_args=\"--env '"
private OPENRC_NETWORK_SERVICE = "net"

def initialize
end

# ameba:disable Metrics/CyclomaticComplexity
def self.from_openrc(data : String | IO)
service = new
def initialize(data : String | IO)
line_number = 1
function_name = ""

Expand All @@ -19,21 +21,21 @@ class Service::Config
if line.ends_with? '}'
function_name = ""
elsif function_name = line.rchop? "() {"
elsif service.description = line.lchop?("description='").try &.rchop
elsif service.directory = line.lchop?("directory='").try &.rchop
elsif service.umask = line.lchop? "umask="
elsif service.log_output = line.lchop?("output_log='").try &.rchop
elsif service.log_error = line.lchop?("error_log='").try &.rchop
elsif service.restart_delay = line.lchop?("respawn_delay=").try &.to_u32
elsif service.command = line.lchop?("command='").try &.rchop.+ service.command.to_s
elsif @description = line.lchop?("description='").try &.rchop
elsif @directory = line.lchop?("directory='").try &.rchop
elsif @umask = line.lchop? "umask="
elsif @log_output = line.lchop?("output_log='").try &.rchop
elsif @log_error = line.lchop?("error_log='").try &.rchop
elsif @restart_delay = line.lchop?("respawn_delay=").try &.to_u32
elsif @command = line.lchop?("command='").try &.rchop.+ @command.to_s
elsif command_args = line.lchop?("command_args='")
service.command = service.command.to_s + ' ' + command_args.rchop
@command = @command.to_s + ' ' + command_args.rchop
elsif command_user = line.lchop?("command_user='")
user_and_group = command_user.rchop.partition ':'
service.user = user_and_group[0].empty? ? nil : user_and_group[0]
service.group = user_and_group[2].empty? ? nil : user_and_group[2]
@user = user_and_group[0].empty? ? nil : user_and_group[0]
@group = user_and_group[2].empty? ? nil : user_and_group[2]
elsif openrc_env_vars = line.lchop?(OPENRC_ENV_VARS_PREFIX)
service.parse_env_vars openrc_env_vars.rchop("'\"")
parse_env_vars openrc_env_vars.rchop("'\"")
else
case line
when .empty?,
Expand All @@ -48,17 +50,17 @@ class Service::Config
case function_name
when "depend"
directive = true
line.split(' ') do |element|
line.split ' ' do |element|
if directive
raise "Unsupported line depend directive: " + element if element != "after"
directive = false
elsif element != OPENRC_NETWORK_SERVICE
service.after << element
@after << element
end
end
when "reload"
if reload_signal = line.lchop? OPENRC_RELOAD_COMMAND
service.reload_signal = reload_signal
@reload_signal = reload_signal
end
else
raise "Unsupported line"
Expand All @@ -68,11 +70,10 @@ class Service::Config
rescue ex
raise Error.new "Parse error line at #{line_number}: #{full_line}", ex
end
service
end

# ameba:disable Metrics/CyclomaticComplexity
def to_openrc(io : IO) : Nil
def build(io : IO) : Nil
io << OPENRC_SHEBANG << "\n\n"
io << OPENRC_SUPERVISOR << '\n'
io << OPENRC_PIDFILE
Expand Down
Loading

0 comments on commit e2a70c9

Please sign in to comment.