Updating service definitions format.
THIS IS A BREAKING CHANGE Hopefully, this change will make it easier to remove data on service removal, but also to export and backup service data and to add per-service system users. A few obsolete service definitions have also been updated to the new format. Testing is still incomplete, you may want to wait a few commits before using this.master
parent
e0e81d8581
commit
87929be026
|
@ -1,22 +1,17 @@
|
|||
name: authd
|
||||
command: authd -K ${SERVICE_ROOT}/jwt_key -u ${SERVICE_ROOT}/passwd -g ${SERVICE_ROOT}/group
|
||||
environment-variables:
|
||||
- LD_LIBRARY_PATH=/usr/local/lib
|
||||
command: authd -K jwt_key -u passwd -g group
|
||||
user: authd
|
||||
provides: auth
|
||||
%pre-start
|
||||
name: Creating IPC directory
|
||||
unless-directory: /run/ipc
|
||||
|
||||
%file /run/ipc
|
||||
name: IPC directory
|
||||
command: install -d -m6777 /run/ipc
|
||||
%pre-start
|
||||
name: Creating JWT key
|
||||
unless-file: ${SERVICE_ROOT}/jwt_key
|
||||
command: head -c 64 /dev/urandom | base64 > ${SERVICE_ROOT}/jwt_key
|
||||
%pre-start
|
||||
%file jwt_key
|
||||
name: JWT key
|
||||
creation-command: head -c 64 /dev/urandom | base64 > jwt_key
|
||||
%file passwd
|
||||
name: passwd file
|
||||
unless-file: ${SERVICE_ROOT}/passwd
|
||||
command: touch ${SERVICE_ROOT}/passwd
|
||||
%pre-start
|
||||
command: touch passwd
|
||||
%file group
|
||||
name: group file
|
||||
unless-file: ${SERVICE_ROOT}/group
|
||||
command: touch ${SERVICE_ROOT}/group
|
||||
command: touch group
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
command: gitea -C . -w . -c ./custom/conf/app.ini
|
||||
command: gitea -C . -w . -c gitea.cfg
|
||||
consumes: postgresql, http?
|
||||
requires-domain: true
|
||||
ports: http
|
||||
|
||||
%directory ${SERVICE_ROOT}/custom/conf
|
||||
name: working directory
|
||||
#%directory ${SERVICE_ROOT}/custom/conf
|
||||
# name: working directory
|
||||
# configuration: true
|
||||
|
||||
%configuration gitea.cfg ${SERVICE_ROOT}/custom/conf/app.ini
|
||||
|
||||
%pre-start
|
||||
name: gitea database creation
|
||||
%file db-is-setup
|
||||
name: postgresql database
|
||||
# 'command' is run only if this directory doesn't exist
|
||||
unless-file: ${SERVICE_ROOT}/db_is_setup
|
||||
command: pg_create_user.sh create_user_and_db && touch ${SERVICE_ROOT}/db_is_setup
|
||||
creation-command: pg_create_user.sh create_user_and_db && touch db-is-setup
|
||||
deletion-command: pg_remove_user.sh bla bla bla && rm db-is-setup
|
||||
export-command: pg_export_user.sh bla bla bla # FIXME: Where/how does it export?
|
||||
|
||||
# With syntaxic sugar.
|
||||
%configuration gitea.cfg
|
||||
|
||||
#%database
|
||||
# type: postgresql
|
||||
# from-token: postgresql
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
name: kanband
|
||||
command: kanband -k ${AUTHD_ROOT}/jwt_key -S data
|
||||
user: kanband
|
||||
consumes: auth
|
||||
|
||||
%file data
|
||||
name: storage directory
|
||||
creation-command: mkdir -p data && chown kanband:kanband data
|
|
@ -1,11 +0,0 @@
|
|||
name: kanband
|
||||
command: kanband -k /srv/%{ENVIRONMENT}/jwt_key -S /srv/%{ENVIRONMENT}/kanban
|
||||
user: kanban
|
||||
environment-variables:
|
||||
- LD_LIBRARY_PATH=/usr/local/lib
|
||||
consumes:
|
||||
- token: auth
|
||||
checks:
|
||||
- name: storage directory creation
|
||||
directory: /srv/%{ENVIRONMENT}/kanban
|
||||
command: mkdir -p /srv/%{ENVIRONMENT}/kanban && chown kanban:kanban /srv/%{ENVIRONMENT}/kanban
|
|
@ -1,9 +1,6 @@
|
|||
command: nginx -c ${SERVICE_ROOT}/nginx.conf
|
||||
command: nginx -c nginx.conf
|
||||
consumes: http?
|
||||
provides: www, http
|
||||
ports: http=80, https=443
|
||||
|
||||
%directory ${SERVICE_ROOT}/
|
||||
name: working directory
|
||||
|
||||
%configuration nginx.conf ${SERVICE_ROOT}/nginx.conf
|
||||
%configuration nginx.conf
|
||||
|
|
|
@ -1,32 +1,28 @@
|
|||
name: postgresql
|
||||
user: postgres
|
||||
command: postgres -D ${SERVICE_ROOT} -k /tmp/postgresql-${ENVIRONMENT}
|
||||
command: postgres -D ${SERVICE_ROOT}/db -k /tmp/postgresql-${ENVIRONMENT}
|
||||
#stop-command: kill -HUP ${PID}
|
||||
environment-variables:
|
||||
- PGROOT=${SERVICE_ROOT}
|
||||
provides: postgresql
|
||||
ports: postgresql
|
||||
|
||||
%pre-start
|
||||
name: database directory creation
|
||||
unless-directory: ${SERVICE_ROOT}
|
||||
command: mkdir -p ${SERVICE_ROOT} && chown postgres:postgres ${SERVICE_ROOT}
|
||||
#%file db
|
||||
# name: database directory
|
||||
# command: mkdir -p db && chown postgres:postgres db
|
||||
|
||||
%pre-start
|
||||
%file db
|
||||
name: database creation
|
||||
unless-file: ${SERVICE_ROOT}/base
|
||||
command: su - postgres -c "initdb --locale en_US.UTF-8 -D '${SERVICE_ROOT}'" && rm ${SERVICE_ROOT}/postgresql.conf
|
||||
creation-command: mkdir db && chown postgres:postgres db && su - postgres -c "initdb --locale en_US.UTF-8 -D '${SERVICE_ROOT}/db'" && rm db/postgresql.conf
|
||||
#export-command: FIXME
|
||||
|
||||
%pre-start
|
||||
name: database configuration
|
||||
# once this file is created, there is no need to perform the command
|
||||
unless-file: ${SERVICE_ROOT}/postgresql.conf
|
||||
%configuration db/postgresql.conf
|
||||
# gen-config inherits its parameters from the environment
|
||||
command: gen-config postgresql.conf ${SERVICE_ROOT}/postgresql.conf && chown postgres:postgres ${SERVICE_ROOT}/postgresql.conf
|
||||
creation-command: gen-config postgresql.conf ${SERVICE_ROOT}/postgresql.conf && chown postgres:postgres ${SERVICE_ROOT}/postgresql.conf
|
||||
|
||||
%pre-start
|
||||
%file /tmp/${SERVICE_NAME}-${ENVIRONMENT}
|
||||
name: sockets directory
|
||||
unless-directory: /tmp/postgresql-${ENVIRONMENT}
|
||||
unless-directory: /tmp/${SERVICE_NAME}-${ENVIRONMENT}
|
||||
# FIXME: impose permissions
|
||||
command: mkdir -p /tmp/postgresql-${ENVIRONMENT} && chown postgres:postgres /tmp/postgresql-${ENVIRONMENT}
|
||||
command: mkdir -p /tmp/${SERVICE_NAME}-${ENVIRONMENT} && chown postgres:postgres /tmp/${SERVICE_NAME}-${ENVIRONMENT}
|
||||
# FIXME: add postgresql-pre-start-db-dir around here
|
||||
|
|
|
@ -2,5 +2,6 @@ command: none
|
|||
consumes: www
|
||||
requires-domain: true
|
||||
|
||||
%directory ${SERVICE_ROOT}/
|
||||
%file www
|
||||
name: data directory
|
||||
creation-command: mkdir www
|
||||
|
|
|
@ -8,7 +8,7 @@ class Environment
|
|||
|
||||
getter name : String
|
||||
getter type : Type = Type::Prefix
|
||||
getter pre_start_hooks = Array(ServiceDefinition::Hook).new
|
||||
getter files = Array(ServiceDefinition::FileDefinition).new
|
||||
|
||||
# The place we’ll put services’ data and configuration.
|
||||
@root : String?
|
||||
|
@ -20,12 +20,14 @@ class Environment
|
|||
def initialize(@name, type = "prefix")
|
||||
@type = Type.parse type
|
||||
|
||||
@pre_start_hooks = Array(ServiceDefinition::Hook).new
|
||||
@files = Array(ServiceDefinition::FileDefinition).new
|
||||
|
||||
# FIXME: Should this *really* be here?
|
||||
@pre_start_hooks << ServiceDefinition::Hook.new "Creating data directory",
|
||||
"mkdir -p /srv/${ENVIRONMENT} && chmod a+rwt /srv/${ENVIRONMENT}",
|
||||
unless_directory: "/srv/${ENVIRONMENT}"
|
||||
# FIXME: $ENVIRONMENT_ROOT
|
||||
@files << ServiceDefinition::FileDefinition.new "/srv/${ENVIRONMENT}",
|
||||
"environment root",
|
||||
creation_command: "mkdir -p /srv/${ENVIRONMENT} && chmod a+rwt /srv/${ENVIRONMENT}",
|
||||
deletion_command: "rmdir /srv/${ENVIRONMENT}"
|
||||
end
|
||||
|
||||
def initialize(@name, specs : SpecParser)
|
||||
|
@ -36,7 +38,7 @@ class Environment
|
|||
end
|
||||
|
||||
specs.sections.select(&.name.==("check")).each do |check|
|
||||
@pre_start_hooks << ServiceDefinition::Hook.new check
|
||||
@files << ServiceDefinition::FileDefinition.new check
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -193,6 +193,7 @@ class Service
|
|||
private def build_environment
|
||||
env = {} of String => String
|
||||
|
||||
env["SERVICE_NAME"] = name
|
||||
env["SERVICE_ROOT"] = root
|
||||
env["SERVICE_ID"] = full_id
|
||||
env["ENVIRONMENT"] = @environment.name
|
||||
|
@ -240,32 +241,33 @@ class Service
|
|||
end
|
||||
end
|
||||
|
||||
def pre_start_hooks
|
||||
@environment.pre_start_hooks + @reference.pre_start_hooks
|
||||
def files
|
||||
@environment.files + @reference.files
|
||||
end
|
||||
|
||||
def start(pid_dir : String, log_dir : String)
|
||||
pre_start_hooks.each do |hook|
|
||||
FileUtils.mkdir_p root
|
||||
|
||||
files.each do |file|
|
||||
run_hook = false
|
||||
|
||||
hook.unless_file.try do |file|
|
||||
file = evaluate file
|
||||
run_hook = true if ! File.exists? file
|
||||
next unless creation_command = file.creation_command
|
||||
|
||||
path = evaluate file.file_path
|
||||
if path[0] != '/'
|
||||
path = "#{root}/#{path}"
|
||||
end
|
||||
|
||||
hook.unless_directory.try do |directory|
|
||||
directory = evaluate directory
|
||||
run_hook = true if ! Dir.exists? directory
|
||||
end
|
||||
run_hook = (!File.exists? path) || file.is_configuration?
|
||||
|
||||
unless run_hook
|
||||
next
|
||||
end
|
||||
next unless run_hook
|
||||
|
||||
puts " - #{hook.name}"
|
||||
puts " - Creating #{file.name}"
|
||||
|
||||
child = Process.fork do
|
||||
Process.exec "sh", ["-c", hook.command],
|
||||
Dir.cd root
|
||||
|
||||
Process.exec "sh", ["-c", creation_command],
|
||||
output: Process::Redirect::Inherit,
|
||||
error: Process::Redirect::Inherit,
|
||||
env: build_environment
|
||||
|
|
|
@ -19,21 +19,40 @@ class ServiceDefinition
|
|||
def initialize(@token)
|
||||
end
|
||||
end
|
||||
struct Hook
|
||||
struct FileDefinition
|
||||
getter name : String
|
||||
getter command : String
|
||||
getter unless_directory : String?
|
||||
getter unless_file : String?
|
||||
getter file_path : String
|
||||
|
||||
def initialize(@name, @command, @unless_file = nil, @unless_directory = nil)
|
||||
getter creation_command : String?
|
||||
getter deletion_command : String?
|
||||
getter export_command : String?
|
||||
|
||||
@configuration = false
|
||||
|
||||
def initialize(@file_path, @name = @file_path,
|
||||
@creation_command = nil,
|
||||
@deletion_command = nil,
|
||||
@export_command = nil,
|
||||
@configuration = false)
|
||||
end
|
||||
def initialize(section : SpecParser::Section)
|
||||
@name = section.content["name"].as_s
|
||||
@command = section.content["command"].as_s
|
||||
@file_path = section.options[0]
|
||||
@name = section.content["name"]?.try(&.as_s) || @file_path
|
||||
|
||||
@unless_directory = section.content["unless-directory"]?
|
||||
@creation_command = section.content["creation-command"]?
|
||||
.try &.as_s
|
||||
@unless_file = section.content["unless-file"]?.try &.as_s
|
||||
@deletion_command = section.content["deletion-command"]?
|
||||
.try &.as_s
|
||||
@export_command = section.content["export-command"]?
|
||||
.try &.as_s
|
||||
|
||||
#@unless_directory = section.content["unless-directory"]?
|
||||
# .try &.as_s
|
||||
#@unless_file = section.content["unless-file"]?.try &.as_s
|
||||
end
|
||||
|
||||
def is_configuration?
|
||||
@configuration
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -59,7 +78,7 @@ class ServiceDefinition
|
|||
getter provides : String?
|
||||
getter consumes : Array(Consumes)
|
||||
getter environment_variables : Array(String)
|
||||
getter pre_start_hooks : Array(Hook)
|
||||
getter files : Array(FileDefinition)
|
||||
getter provides : Array(Provides)
|
||||
getter port_definitions : Array(PortDefinition)
|
||||
getter non_runnable : Bool
|
||||
|
@ -92,39 +111,39 @@ class ServiceDefinition
|
|||
STDERR.puts "warning: definition '#{@name}' has a 'requires-domain' entry with an invalid value"
|
||||
end
|
||||
|
||||
@pre_start_hooks = Array(Hook).new
|
||||
@files = Array(FileDefinition).new
|
||||
|
||||
sections.each do |section|
|
||||
case section.name
|
||||
when "pre-start"
|
||||
@pre_start_hooks << Hook.new section
|
||||
when "directory"
|
||||
directory = section.options[0]?
|
||||
name = section.content["name"]?.try &.as_s
|
||||
|
||||
if directory.nil?
|
||||
STDERR.puts "warning: (#{@name}) %directory was not provided a path"
|
||||
next
|
||||
end
|
||||
|
||||
pre_start_hooks << Hook.new (name || "directory: #{directory}"),
|
||||
"mkdir -p \"#{directory}\"",
|
||||
unless_directory: directory
|
||||
when "file", "directory"
|
||||
@files << FileDefinition.new section
|
||||
when "configuration"
|
||||
options = section.options[0].split /[ \t]/
|
||||
|
||||
template = options[0]?
|
||||
target = options[1]?
|
||||
|
||||
name = section.content["name"]?.try &.as_s
|
||||
|
||||
if template.nil? || target.nil?
|
||||
STDERR.puts "warning: (#{@name}) %configuration received less than 2 options"
|
||||
if template.nil?
|
||||
STDERR.puts "warning: (#{@name}) %configuration wasn’t provided a target."
|
||||
next
|
||||
end
|
||||
|
||||
pre_start_hooks << Hook.new (name || "configuration file: #{template}"),
|
||||
"gen-config \"#{template}\" \"#{target}\"",
|
||||
unless_file: target
|
||||
target = options[1]?
|
||||
unless target
|
||||
target = template
|
||||
template = File.basename target
|
||||
end
|
||||
|
||||
files << FileDefinition.new target, (name || target),
|
||||
creation_command: "gen-config \"#{template}\" \"#{target}\"",
|
||||
deletion_command: "rm \"#{target}\"",
|
||||
configuration: true
|
||||
when "database"
|
||||
options = section.options[0].split /[ \t]/
|
||||
type = options[0]? || section.content["type"]?.try &.as_s
|
||||
|
||||
# FIXME: %database is not currently implemented.
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue