This commit is contained in:
anlicheng 2026-06-01 14:45:27 +08:00
parent c9c48edd42
commit 16e63a5c74
2 changed files with 91 additions and 6 deletions

View File

@ -24,7 +24,9 @@ SERVICE_GROUP="${SERVICE_GROUP:-$(id -gn "$SERVICE_USER")}"
# IOT_ENV is rendered into the systemd service file as Environment= lines,
# using the [prod] section from iot/env.file. Directory creation is driven by
# those service env values. IOT_DIR_ENV_KEYS lists env keys whose values are
# directories that must be created if they do not exist.
# directories that must be created if they do not exist. IOT_PARENT_DIR_ENV_KEYS
# lists env keys whose values are file paths; their parent directories must be
# created if they do not exist.
#
# Use {install_dir}, {work_dir} and {service_name} in commands and directories.
# service_user and service_group are optional.
@ -43,6 +45,7 @@ IOT_ENV=(
"ENDPOINT_ROOT_DIR=/var/lib/endpoint/database/"
"ENDPOINT_LOG_PATH=/var/lib/endpoint/endpoint_log"
"IOT_MNESIA_DIR=/var/lib/iot/mnesia/"
"IOT_CTRL_SOCKET_PATH=/var/lib/iot/ctl.sock"
)
IOT_DIR_ENV_KEYS=(
@ -51,6 +54,10 @@ IOT_DIR_ENV_KEYS=(
"IOT_MNESIA_DIR"
)
IOT_PARENT_DIR_ENV_KEYS=(
"IOT_CTRL_SOCKET_PATH"
)
TEMP_FILES=()
INSTALLED_SERVICES=()
@ -75,6 +82,7 @@ Array config inside script:
INSTALL_IOT
IOT_ENV
IOT_DIR_ENV_KEYS
IOT_PARENT_DIR_ENV_KEYS
Package format:
INSTALL_<APP>=(
@ -348,6 +356,29 @@ service_dir_env_keys() {
done
}
service_parent_dir_env_keys() {
local service_name="$1"
local parent_dir_keys_array_name=""
local parent_dir_keys_count
local index
local env_key
case "$service_name" in
iot)
parent_dir_keys_array_name="IOT_PARENT_DIR_ENV_KEYS"
;;
*)
return 0
;;
esac
eval "parent_dir_keys_count=\${#${parent_dir_keys_array_name}[@]}"
for ((index=0; index<parent_dir_keys_count; index++)); do
eval "env_key=\"\${${parent_dir_keys_array_name}[$index]}\""
printf '%s\n' "$env_key"
done
}
env_value_for_key() {
local service_name="$1"
local env_key="$2"
@ -385,6 +416,31 @@ create_dependency_dirs_from_env() {
done < <(service_dir_env_keys "$service_name")
}
create_parent_dependency_dirs_from_env() {
local service_name="$1"
local install_dir="$2"
local service_user="$3"
local service_group="$4"
local env_key
local dependency_path
local dependency_dir
while IFS= read -r env_key; do
[[ -n "$env_key" ]] || continue
dependency_path="$(env_value_for_key "$service_name" "$env_key")"
dependency_path="$(replace_placeholders "$dependency_path" "$install_dir" "$service_name")"
[[ "$dependency_path" = /* ]] || fail "Dependency path must be an absolute path: $dependency_path"
dependency_dir="$(dirname "$dependency_path")"
[[ -n "$dependency_dir" && "$dependency_dir" != "." ]] || fail "Cannot parse parent directory from path: $dependency_path"
log "Creating parent dependency directory from $env_key: $dependency_dir"
run_as_root install -d -m 0755 "$dependency_dir"
run_as_root chown -R "${service_user}:${service_group}" "$dependency_dir"
done < <(service_parent_dir_env_keys "$service_name")
}
install_program() {
local service_name="$1"
local download_url="$2"
@ -431,6 +487,7 @@ install_program() {
run_as_root chown -R "${service_user}:${service_group}" "$install_dir"
create_dependency_dirs_from_env "$service_name" "$install_dir" "$service_user" "$service_group"
create_parent_dependency_dirs_from_env "$service_name" "$install_dir" "$service_user" "$service_group"
write_service_file "$service_file" "$service_name" "$service_user" "$service_group" "$install_dir" "$start_command" "$stop_command"
INSTALLED_SERVICES+=("$service_name")
@ -491,6 +548,7 @@ main() {
require_command wget
require_root_runner
require_command dirname
require_command tar
require_command systemctl

View File

@ -98,11 +98,18 @@ Environment="KEY=value"
- 如果目录不存在,则创建。
- 将目录 owner 设置为服务用户和服务组。
### IOT_PARENT_DIR_ENV_KEYS
`IOT_PARENT_DIR_ENV_KEYS` 声明哪些环境变量的值是文件路径,脚本会创建这些文件路径的父目录。
例如 `IOT_CTRL_SOCKET_PATH=/var/lib/iot/ctl.sock` 是 Unix socket 文件路径,脚本应创建并授权 `/var/lib/iot`,不能把 `/var/lib/iot/ctl.sock` 当目录创建。
当前 iot 会创建:
- `/var/lib/endpoint/database/`
- `/var/lib/endpoint/endpoint_log`
- `/var/lib/iot/mnesia/`
- `/var/lib/iot`,来自 `IOT_CTRL_SOCKET_PATH` 的父目录
当前 efka 会创建:
@ -116,7 +123,7 @@ Environment="KEY=value"
1. 解析命令行参数。
2. 校验 `WORK_DIR` 和服务配置。
3. 检查依赖命令:`wget``tar`、`systemctl`
3. 检查依赖命令:`wget``dirname`、`tar`、`systemctl`
4. 创建 `WORK_DIR`
5. 安装当前服务。
6. 重新加载 systemd。
@ -131,7 +138,7 @@ Environment="KEY=value"
5. 创建安装目录。
6. 解压压缩包。
7. 设置安装目录 owner。
8. 根据 `*_DIR_ENV_KEYS` 创建数据目录。
8. 根据 `*_DIR_ENV_KEYS` 创建数据目录,并根据 `*_PARENT_DIR_ENV_KEYS` 创建文件路径父目录
9. 生成 systemd service 文件。
10. 记录服务名,后续统一 enable。
@ -174,6 +181,18 @@ IOT_DIR_ENV_KEYS=(
非目录型环境变量只需要加入 `*_ENV`,不要加入 `*_DIR_ENV_KEYS`
如果环境变量是文件路径,需要把变量名加入对应的 `*_PARENT_DIR_ENV_KEYS`,脚本只创建父目录:
```bash
IOT_ENV=(
"IOT_CTRL_SOCKET_PATH=/var/lib/iot/ctl.sock"
)
IOT_PARENT_DIR_ENV_KEYS=(
"IOT_CTRL_SOCKET_PATH"
)
```
## 权限原则
脚本支持 root 或普通用户运行。
@ -212,7 +231,7 @@ SERVICE_GROUP="${SERVICE_GROUP:-$(id -gn "$SERVICE_USER")}"
- `{work_dir}`
- `{service_name}`
如果该变量是目录,需要加入对应 `*_DIR_ENV_KEYS`
如果该变量是目录,需要加入对应 `*_DIR_ENV_KEYS`如果该变量是文件路径,需要加入对应 `*_PARENT_DIR_ENV_KEYS`
## 修改和扩展原则
@ -235,6 +254,13 @@ IOT_ENV=(
- `IOT_ENV``EFKA_ENV`
- `IOT_DIR_ENV_KEYS``EFKA_DIR_ENV_KEYS`
### 新增文件路径
同时修改:
- `IOT_ENV``EFKA_ENV`
- 对应的 `*_PARENT_DIR_ENV_KEYS`
### 修改下载包
只修改对应服务脚本:
@ -262,7 +288,8 @@ INSTALL_IOT=(
4. 在 `validate_args` 中校验对应配置。
5. 在 `service_env_lines` 中映射服务名到 env 数组。
6. 在 `service_dir_env_keys` 中映射服务名到目录 key 数组。
7. 在 `install_programs` 中调用对应配置。
7. 如服务有文件路径型环境变量,在 `service_parent_dir_env_keys` 中映射服务名到父目录 key 数组。
8. 在 `install_programs` 中调用对应配置。
## 兼容性原则
@ -297,5 +324,5 @@ systemd-analyze verify /etc/systemd/system/efka.service
- 环境变量中如包含空格或特殊字符,需要确认 systemd `Environment=` 语法是否仍然正确。
- token 等敏感信息会写入 systemd service 文件,需控制 `/etc/systemd/system/*.service` 的读取权限和服务器访问权限。
- 数据目录必须使用绝对路径。
- 数据目录和文件路径型变量必须使用绝对路径。
- 现有卸载脚本如果需要同步目录清理规则,应按 `IOT_DIR_ENV_KEYS` / `EFKA_DIR_ENV_KEYS` 的思路同步调整。