Skip to content

Commit

Permalink
fixes and improvements based on analytics
Browse files Browse the repository at this point in the history
  • Loading branch information
cryi committed Dec 31, 2024
1 parent 8f97f0f commit 7f6c1d6
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 192 deletions.
6 changes: 3 additions & 3 deletions build/build.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ end
local function minify(filePath)
if not fs.exists("../build/luasrcdiet") then
net.download_file("https://github.com/cryi/luasrcdiet/archive/refs/tags/1.1.1.zip", "../build/luasrcdiet.zip",
{ followRedirects = true })
{ follow_redirects = true })
fs.mkdirp("../build/luasrcdiet")
zip.extract("../build/luasrcdiet.zip", "../build/luasrcdiet", { flatten_root_dir = true })
end
Expand Down Expand Up @@ -83,12 +83,12 @@ fs.mkdirp("../bin/ami/")
local amiAsctlEntrypoint = "ami-plugin/asctl.lua"
local amiAsctlOutput = "../bin/ami/asctl.lua"
amalg("-o", amiAsctlOutput, "-s", amiAsctlEntrypoint, table.unpack(collect_requires(amiAsctlEntrypoint)))
local fileName = string.interpolate("${pluginName}-${version}.zip", { pluginName = "asctl", version = require"version-info".VERSION })
local fileName = string.interpolate("${plugin_name}-${version}.zip", { plugin_name = "asctl", version = require"version-info".VERSION })
zip.compress("../bin/ami", path.combine("../bin", fileName), { recurse = true, content_only = true, overwrite = true })

-- minify
-- if not fs.exists("../build/luasrcdiet") then
-- net.download_file("https://github.com/cryi/luasrcdiet/archive/refs/tags/1.1.1.zip", "../build/luasrcdiet.zip", { followRedirects = true })
-- net.download_file("https://github.com/cryi/luasrcdiet/archive/refs/tags/1.1.1.zip", "../build/luasrcdiet.zip", { follow_redirects = true })
-- fs.mkdirp("../build/luasrcdiet")
-- zip.extract("../build/luasrcdiet.zip", "../build/luasrcdiet", { flatten_root_dir = true })
-- end
Expand Down
50 changes: 25 additions & 25 deletions src/ami-plugin/asctl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ local asctl = {}
function asctl.exec(...)
local cmd = string.join_strings(" ", ...)
trace("Executing asctl " .. cmd)
local proc = proc.spawn("asctl", { ... }, { stdio = { stdout = "pipe", stderr = "pipe" }, wait = true }) --[[@as SpawnResult]]
if not proc then
local process = proc.spawn("asctl", { ... }, { stdio = { stdout = "pipe", stderr = "pipe" }, wait = true }) --[[@as SpawnResult]]
if not process then
error("Failed to execute asctl command: " .. cmd)
end
trace("asctl exit code: " .. proc.exit_code)
trace("asctl exit code: " .. process.exit_code)

local stderr = proc.stderrStream:read("a")
local stdout = proc.stdoutStream:read("a")
return proc.exit_code, stdout, stderr
local stderr = process.stderr_stream:read("a")
local stdout = process.stdout_stream:read("a")
return process.exit_code, stdout, stderr
end

function asctl.with_options(options)
Expand All @@ -34,8 +34,8 @@ function asctl.install_service(sourceFile, serviceName, options)
if type(options.kind) ~= "string" then
options.kind = "service"
end
local serviceUnitFile = string.interpolate("${serivceDirectory}/${service}.hjson", {
serivceDirectory = ASCEND_SERVICES,
local serviceUnitFile = string.interpolate("${service_directory}/${service}.hjson", {
service_directory = ASCEND_SERVICES,
service = serviceName
})
local _ok, _error = fs.safe_copy_file(sourceFile, serviceUnitFile)
Expand All @@ -53,40 +53,40 @@ function asctl.install_service(sourceFile, serviceName, options)
end
end

function asctl.start_service(serviceName)
trace("Starting service: ${service}", { service = serviceName })
local exit_code = asctl.exec("start", serviceName)
function asctl.start_service(service_name)
trace("Starting service: ${service}", { service = service_name })
local exit_code = asctl.exec("start", service_name)
assert(exit_code == 0, "Failed to start service")
trace("Service ${service} started.", { service = serviceName })
trace("Service ${service} started.", { service = service_name })
end

function asctl.stop_service(serviceName)
trace("Stoping service: ${service}", { service = serviceName })
local exit_code = asctl.exec("stop", serviceName)
function asctl.stop_service(service_name)
trace("Stoping service: ${service}", { service = service_name })
local exit_code = asctl.exec("stop", service_name)
assert(exit_code == 0, "Failed to stop service")
trace("Service ${service} stopped.", { service = serviceName })
trace("Service ${service} stopped.", { service = service_name })
end

function asctl.remove_service(serviceName, options)
function asctl.remove_service(service_name, options)
if type(options) ~= "table" then
options = {}
end
local serviceUnitFile = string.interpolate("${serivceDirectory}/${service}.hjson", {
serivceDirectory = ASCEND_SERVICES,
service = serviceName
local serviceUnitFile = string.interpolate("${service_directory}/${service}.hjson", {
service_directory = ASCEND_SERVICES,
service = service_name
})
if not fs.exists(serviceUnitFile) then return end -- service not found so skip

trace("Removing service: ${service}", { service = serviceName })
local exit_code = asctl.exec("stop", serviceName)
trace("Removing service: ${service}", { service = service_name })
local exit_code = asctl.exec("stop", service_name)
assert(exit_code == 0, "Failed to stop service")
trace("Service ${service} stopped.", { service = serviceName })
trace("Service ${service} stopped.", { service = service_name })

trace("Removing service...")
local ok, error = fs.safe_remove(serviceUnitFile)
if not ok then
error(string.interpolate("Failed to remove ${service} (${file}): ${error}", {
service = serviceName,
service = service_name,
file = serviceUnitFile,
error = error
}))
Expand All @@ -98,7 +98,7 @@ function asctl.remove_service(serviceName, options)
warn({ msg = "Failed to reload ascend!", stdout = stdout, stderr = stderr })
end
end
trace("Service ${service} removed.", { service = serviceName })
trace("Service ${service} removed.", { service = service_name })
end

function asctl.get_service_status(serviceName)
Expand Down
4 changes: 2 additions & 2 deletions src/ascend.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ tasks.add(services.healthcheck())

local end_time = timeout and os.time() + timeout or nil
log_info("ascend started")
local stop_reason = tasks.run({ stopOnError = true , end_time = end_time })
local stop_reason = tasks.run({ stop_on_error = true , end_time = end_time })

tasks.clear()
tasks.add(services.stop_all())
tasks.run({ ignoreStop = true, stopOnEmpty = true })
tasks.run({ ignore_stop = true, stop_on_empty = true })

log_info("ascend stopped")

Expand Down
4 changes: 2 additions & 2 deletions src/ascend/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ local init = {}
local function ami_init()
local appsDir = os.getenv("ASCEND_APPS")
if not appsDir then
appsDir = path.combine(path.dir(aenv.servicesDirectory), "apps")
appsDir = path.combine(path.dir(aenv.services_directory), "apps")
end
fs.mkdirp(appsDir)

Expand Down Expand Up @@ -43,7 +43,7 @@ local commonInitStrategies = {

local function run_init_hook()
fs.mkdirp(aenv.logDirectory)
fs.mkdirp(aenv.servicesDirectory)
fs.mkdirp(aenv.services_directory)
fs.mkdirp(aenv.healthchecksDirectory)

if aenv.initScript ~= nil then
Expand Down
107 changes: 63 additions & 44 deletions src/ascend/internals/env.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ local input = require "common.input"
local isUnix = package.config:sub(1, 1) == "/"

local defaultAEnv = {
servicesDirectory = isUnix and "/etc/ascend/services" or "C:\\ascend\\services",
services_directory = isUnix and "/etc/ascend/services" or "C:\\ascend\\services",
healthchecksDirectory = isUnix and "/etc/ascend/healthchecks" or "C:\\ascend\\healthchecks",
ipcEndpoint = "/tmp/ascend.sock",
logDirectory = isUnix and "/var/log/ascend" or "C:\\ascend\\logs",
initScript = nil --[[@as string?]]
}

local aenv = util.merge_tables({
servicesDirectory = args.options.services or env.get_env("ASCEND_SERVICES"),
services_directory = args.options.services or env.get_env("ASCEND_SERVICES"),
healthchecksDirectory = args.options.healthchecks or env.get_env("ASCEND_HEALTHCHECKS"),
ipcEndpoint = args.options.socket or env.get_env("ASCEND_SOCKET"),
logDirectory = args.options["log-dir"] or env.get_env("ASCEND_LOGS"),
Expand Down Expand Up @@ -68,123 +68,141 @@ local function validate_service_definition(definition)
if k == "all" then
return false, "module name 'all' is reserved"
end
local moduleInfo = { name = k }
local module_info = { name = k }
if type(v) ~= "table" then
return false, string.interpolate("module ${name} must be an JSON object", moduleInfo)
local msg = string.interpolate("module ${name} must be an JSON object", module_info)
return false, msg
end

if type(v.executable) ~= "string" then
return false, string.interpolate("module ${name} - executable must be a string", moduleInfo)
local msg = string.interpolate("module ${name} - executable must be a string", module_info)
return false, msg
end

if type(v.args) ~= "table" then
return false, string.interpolate("module ${name} - args must be an array", moduleInfo)
local msg = string.interpolate("module ${name} - args must be an array", module_info)
return false, msg
end

if not table.is_array(v.depends) then
return false, string.interpolate("module ${name} - depends must be an array", moduleInfo)
local msg = string.interpolate("module ${name} - depends must be an array", module_info)
return false, msg
end

if type(v.restart) ~= "string" then
return false, string.interpolate("module ${name} - restart must be a string", moduleInfo)
local msg = string.interpolate("module ${name} - restart must be a string", module_info)
return false, msg
end

if not table.includes({ "always", "never", "on-failure", "on-success", "on-exit" }, v.restart) then
return false,
string.interpolate("module ${name} - restart must be one of: always, never, on-failure, on-success",
moduleInfo)
local msg = string.interpolate("module ${name} - restart must be one of: always, never, on-failure, on-success", module_info)
return false, msg
end

if type(v.restart_delay) ~= "number" then
return false, string.interpolate("module ${name} - restart_delay must be a number", moduleInfo)
local msg = string.interpolate("module ${name} - restart_delay must be a number", module_info)
return false, msg
end

if type(v.restart_max_retries) ~= "number" then
return false, string.interpolate("module ${name} - restart_max_retries must be a number", moduleInfo)
local msg = string.interpolate("module ${name} - restart_max_retries must be a number", module_info)
return false, msg
end

if v.stop_timeout and type(v.stop_timeout) ~= "number" then
return false, string.interpolate("module ${name} - stop_timeout must be a number or undefined", moduleInfo)
local msg = string.interpolate("module ${name} - stop_timeout must be a number or undefined", module_info)
return false, msg
end

if type(v.stop_signal) ~= "number" then
return false, string.interpolate("module ${name} - stop_signal must be a number", moduleInfo)
local msg = string.interpolate("module ${name} - stop_signal must be a number", module_info)
return false, msg
end

if type(v.environment) ~= "table" then
return false, string.interpolate("module ${name} - environment must be an JSON object", moduleInfo)
local msg = string.interpolate("module ${name} - environment must be an JSON object", module_info)
return false, msg
end

if type(v.working_directory) ~= "string" and type(v.working_directory) ~= "nil" then
return false,
string.interpolate("module ${name} - working_directory must be a string or undefined", moduleInfo)
local msg = string.interpolate("module ${name} - working_directory must be a string or undefined", module_info)
return false, msg
end

if type(v.working_directory) == "string" and #v.working_directory == 0 then
return false, string.interpolate("module ${name} - working_directory must not be empty", moduleInfo)
local msg = string.interpolate("module ${name} - working_directory must not be empty", module_info)
return false, msg
end

if type(v.log_file) == "string" and path.isabs(v.log_file) then
local dir = path.dir(v.log_file)
if not fs.exists(dir) then
return false,
string.interpolate("module ${name} - log_file directory ${dir} does not exist",
{ name = k, dir = dir })
local msg = string.interpolate("module ${name} - log_file directory ${dir} does not exist",
{ name = k, dir = dir })
return false, msg
end
end

if type(v.log_rotate) ~= "boolean" then
return false, string.interpolate("module ${name} - log_rotate must be a boolean", moduleInfo)
local msg = string.interpolate("module ${name} - log_rotate must be a boolean", module_info)
return false, msg
end

if type(v.log_max_files) ~= "number" then
return false, string.interpolate("module ${name} - log_max_files must be a number", moduleInfo)
local msg = string.interpolate("module ${name} - log_max_files must be a number", module_info)
return false, msg
elseif v.log_max_files < 0 then
return false, string.interpolate("module ${name} - log_max_files must be greater than 0", moduleInfo)
local msg = string.interpolate("module ${name} - log_max_files must be greater than 0", module_info)
return false, msg
end

local max_log_file_size = input.parse_size_value(tostring(v.log_max_size))
if type(max_log_file_size) ~= "number" then
return false,
string.interpolate("module ${name} - log_max_size must be a number (accepts k, m, g suffixes)",
moduleInfo)
local msg = string.interpolate("module ${name} - log_max_size must be a number (accepts k, m, g suffixes)",
module_info)
return false, msg
elseif max_log_file_size < 1024 then
return false,
string.interpolate("module ${name} - log_max_size must be greater than 1KB", moduleInfo)
local msg = string.interpolate("module ${name} - log_max_size must be greater than 1KB", module_info)
return false, msg
end

if type(v.healthcheck) == "table" then -- healthchecks are optional so validate only if defined
if type(v.healthcheck.name) ~= "string" then
return false, string.interpolate("module ${name} - healthcheck.name must be a string", moduleInfo)
local msg = string.interpolate("module ${name} - healthcheck.name must be a string", module_info)
return false, msg
end

if type(v.healthcheck.action) == "string" and not table.includes({ "restart", "none" }, v.healthcheck.action) then
return false,
string.interpolate("module ${name} - healthcheck.action must be one of: restart, none", moduleInfo)
local msg = string.interpolate("module ${name} - healthcheck.action must be one of: restart, none", module_info)
return false, msg
end

if type(v.healthcheck.interval) ~= "number" then
return false, string.interpolate("module ${name} - healthcheck.interval must be a number", moduleInfo)
local msg = string.interpolate("module ${name} - healthcheck.interval must be a number", module_info)
return false, msg
end

if type(v.healthcheck.timeout) ~= "number" then
return false, string.interpolate("module ${name} - healthcheck.timeout must be a number", moduleInfo)
local msg = string.interpolate("module ${name} - healthcheck.timeout must be a number", module_info)
return false, msg
end

if type(v.healthcheck.retries) ~= "number" then
return false, string.interpolate("module ${name} - healthcheck.retries must be a number", moduleInfo)
local msg = string.interpolate("module ${name} - healthcheck.retries must be a number", module_info)
return false, msg
end
if v.healthcheck.retries <= 0 then
return false,
string.interpolate("module ${name} - healthcheck.retries must be greater than 0", moduleInfo)
local msg = string.interpolate("module ${name} - healthcheck.retries must be greater than 0", module_info)
return false, msg
end
if type(v.healthcheck.delay) ~= "number" then
return false, string.interpolate("module ${name} - healthcheck.delay must be a number", moduleInfo)
local msg = string.interpolate("module ${name} - healthcheck.delay must be a number", module_info)
return false, msg
end

if v.healthcheck.interval < 1 then
return false,
string.interpolate("module ${name} - healthcheck.interval must be greater than 0", moduleInfo)
local msg = string.interpolate("module ${name} - healthcheck.interval must be greater than 0", module_info)
return false, msg
end
end
end
Expand Down Expand Up @@ -311,11 +329,12 @@ end

---@return table<string, AscendServiceDefinition>?, string?
function aenv.load_service_definitions()
if fs.file_type(aenv.servicesDirectory) ~= "directory" then
return nil, string.interpolate("path ${path} is not a directory", { path = aenv.servicesDirectory })
if fs.file_type(aenv.services_directory) ~= "directory" then
local msg = string.interpolate("path ${path} is not a directory", { path = aenv.services_directory })
return nil, msg
end

local defs = fs.read_dir(aenv.servicesDirectory, { recurse = false, return_full_paths = true, as_dir_entries = false }) --[=[@as string[]]=]
local defs = fs.read_dir(aenv.services_directory, { recurse = false, return_full_paths = true, as_dir_entries = false }) --[=[@as string[]]=]

---@type table<string, { definition: table, source: string }>
local services = {}
Expand Down
Loading

0 comments on commit 7f6c1d6

Please sign in to comment.