From 4ae8e639333d4773dfd8d726fff492488ee18d2d Mon Sep 17 00:00:00 2001 From: Kaiser-Yang <624626089@qq.com> Date: Sat, 10 Aug 2024 15:39:26 +0800 Subject: [PATCH] Finish the script for deploying in docker In this commit, we finish the script for deploying in docker. We found that `systemd` can not be used in docker, so we use `Sys V Init` to start a service in docker. This commit is related with #8. Those below are not finished yet: * Create database automatically. --- README-zh.md | 51 ++++---- config_debug_docker.json | 6 + config_default.json | 21 +++- deploy_ubuntu.sh | 21 +--- script/deploy_helper.py | 249 ++++++++++++++++++++++++++++----------- script/service_tmp.sh | 55 +++++++++ 6 files changed, 290 insertions(+), 113 deletions(-) create mode 100644 config_debug_docker.json create mode 100644 script/service_tmp.sh diff --git a/README-zh.md b/README-zh.md index 43bd20c..50b27b7 100644 --- a/README-zh.md +++ b/README-zh.md @@ -1,29 +1,38 @@ # gcs-back-end -`git`中央仓库服务的后端实现。 +`git` 中央仓库服务的后端实现。 # 部署设置说明 | 变量 | 类型 | 默认值 | 说明 | | - | - | - | - | -| `deploy` | `bool` | `true` | 是否进行部署,当为`false`只进行打包操作。 | +| `deploy` | `bool` | `true` | 是否进行部署,当为 `false` 只进行打包操作。 | | `debug` | `bool` | `false` | 是否启用调试模式。 | | `skipTest` | `bool` | `true` | 是否跳过测试。 | -| `createGitUser` | `bool` | `true` | 是否创建`git`用户。 | -| `deployWithDocker` | `bool` | `true` | 是否使用`Docker`进行部署。 | -| `repositoryDirectory` | `string` | `"/home/git/repositories"` | `git`仓库存放目录。 | -| `postgresPassword` | `string` | `null` | `Postgres`数据库密码。 | -| `serviceEnable` | `bool` | `true` | 是否启用`systemd`服务。 | -| `serviceName` | `string` | `"gcs"` | `systemd`服务名称。 | -| `serviceSuffix` | `string` | `"service"` | `systemd`服务文件后缀。 | -| `serviceDescription` | `string` | `"Git server center back-end service"` | `systemd`服务描述。 | -| `servicePIDFile` | `string` | `"/var/run/gcs.pid"` | `systemd`服务`PID`文件。 | -| `serviceUser` | `string` | `gcs` | `systemd`服务运行用户。 | -| `serviceUserPassword` | `string` | `null` | `systemd`服务运行用户密码。 | -| `serviceWorkingDirectory` | `string` | `"/opt/gcs"` | `systemd`服务工作目录。 | -| `serviceRestartPolicy` | `string` | `"always"` | `systemd`服务重启策略。 | -| `serviceRestartDelaySeconds` | `int` | `5` | `systemd`服务重启延迟时间。 | -| `serviceStartJavaCommand` | `string` | `"/usr/bin/java"` | `systemd`服务启动`Java`命令。 | -| `serviceStartJavaArgs` | `list` | `["-jar"]` | `systemd`服务启动`Java`参数。 | -| `serviceStartJarFile` | `string` | `"/opt/gcs/gcs.jar"` | `systemd`服务启动`Jar`文件。脚本会将`maven`打包出来的文件拷贝到该位置。 | -| `serviceAfter` | `list` | `["network.target"]` | `systemd`服务会在这些服务启动后启动。 | -| `serviceWantedBy` | `list` | `"multi-user.target"` | `systemd`服务会被这些服务依赖。 | +| `createGitUser` | `bool` | `true` | 是否创建 `git` 用户。 | +| `deployWithDocker` | `bool` | `true` | 是否使用 `Docker` 进行部署。 | +| `dockerName` | `string` | `"gcs-backend"` | `Docker` 容器名称。 | +| `dockerImage` | `string` | `"ubuntu:latest"` | `Docker` 镜像。 | +| `dockerPortMapping` | `list` | `["8080:8080"]` | `Docker` 端口映射。 | +| `dockerWithGpu` | `bool` | `false` | `Docker` 是否使用 `GPU`。 | +| `dockerSrcPath` | `string` | `"/opt/gcs-back-end-src"` | `Docker` 中源码路径。源码会被拷贝到该路径进行编译。 | +| `repositoryDirectory` | `string` | `"/home/git/repositories"` | `git` 仓库存放目录。 | +| `postgresPassword` | `string` | `null` | `Postgres` 数据库密码。 | +| `serviceEnable` | `bool` | `true` | 是否启用 `systemd` 服务。 | +| `serviceName` | `string` | `"gcs"` | 服务名称。 | +| `serviceDescription` | `string` | `"Git server center back-end service"` | 服务描述。 | +| `servicePIDFile` | `string` | `"/var/run/gcs.pid"` | 服务 `PID` 文件。 | +| `serviceUser` | `string` | `gcs` | 服务运行用户。 | +| `serviceUserPassword` | `string` | `null` | 服务运行用户密码。 | +| `serviceStartJavaCommand` | `string` | `"/usr/bin/java"` | 服务启动的 `Java` 命令。 | +| `serviceStartJavaArgs` | `list` | `["-jar"]` | 服务启动的 `Java` 参数。 | +| `serviceStartJarFile` | `string` | `"/opt/gcs/gcs.jar"` | 服务启动的 `Jar` 文件。脚本会将 `maven` 打包出来的文件拷贝到该位置。 | +| `serviceSuffix` | `string` | `"service"` | `systemd` 服务文件后缀。 | +| `serviceWorkingDirectory` | `string` | `"/opt/gcs"` | `systemd` 服务工作目录。 | +| `serviceRestartPolicy` | `string` | `"always"` | `systemd` 服务重启策略。 | +| `serviceRestartDelaySeconds` | `int` | `5` | `systemd` 服务重启延迟时间。 | +| `serviceAfter` | `list` | `["network.target"]` | `systemd` 服务会在这些服务启动后启动。 | +| `serviceWantedBy` | `list` | `"multi-user.target"` | `systemd` 服务会被这些服务依赖。 | +| `serviceSystemdDirectory` | `string` | `"/etc/systemd/system"` | `systemd` 服务文件存放目录。 | +| `serviceSysVInitDirectory` | `string` | `"/etc/init.d"` | `Sys-Init-V` 服务文件存放目录。 | +| `serviceStartWithBoot` | `bool` | `true` | `Sys-Init-V` 服务是否随系统启动。 | +| `serviceLogFile` | `string` | `"/tmp/log/gcs.log"` | `Sys-Init-V` 服务日志文件。 | diff --git a/config_debug_docker.json b/config_debug_docker.json new file mode 100644 index 0000000..d4e7572 --- /dev/null +++ b/config_debug_docker.json @@ -0,0 +1,6 @@ +{ + "createGitUser": false, + "repositoryDirectory": "~/.local/gcs/repository", + "debug": true, + "skipTest": false +} diff --git a/config_default.json b/config_default.json index 63379a2..ccfca05 100644 --- a/config_default.json +++ b/config_default.json @@ -4,27 +4,38 @@ "skipTest": true, "createGitUser": true, "deployWithDocker": true, + "dockerName": "gcs-back-end", + "dockerImage": "ubuntu:20.04", + "dockerPortMapping": [ + "8080:8080" + ], + "dockerWithGpu": false, + "dockerSrcPath": "/opt/gcs-back-end-src", "repositoryDirectory": "/home/git/repositories", "postgresPassword": null, "serviceEnable": true, "serviceName": "gcs", - "serviceSuffix": "service", "serviceDescription": "Git server center back-end service", "servicePIDFile": "/var/run/gcs.pid", "serviceUser": "gcs", "serviceUserPassword": null, - "serviceWorkingDirectory": "/opt/gcs", - "serviceRestartPolicy": "always", - "serviceRestartDelaySeconds": 5, "serviceStartJavaCommand": "/usr/bin/java", "serviceStartJavaArgs": [ "-jar" ], "serviceStartJarFile": "/opt/gcs/gcs.jar", + "serviceSuffix": "service", + "serviceWorkingDirectory": "/opt/gcs", + "serviceRestartPolicy": "always", + "serviceRestartDelaySeconds": 5, "serviceAfter": [ "network.target" ], "serviceWantedBy": [ "multi-user.target" - ] + ], + "serviceSystemdDirectory": "/etc/systemd/system", + "serviceSysVInitDirectory": "/etc/init.d", + "serviceStartWithBoot": true, + "serviceLogFile": "/tmp/log/gcs.log" } diff --git a/deploy_ubuntu.sh b/deploy_ubuntu.sh index 13d9676..25e1338 100644 --- a/deploy_ubuntu.sh +++ b/deploy_ubuntu.sh @@ -2,8 +2,6 @@ config_file=${1:-"config.json"} -echo "Config file: ${config_file}" - log_error () { echo -e "\e[31m[ERROR]: $1\e[0m" exit 1 @@ -13,6 +11,8 @@ log_info () { echo "[INFO]: $1" } +log_info "Config file: ${config_file}" + apt_updated=false install_package() { local sudo_cmd @@ -25,22 +25,7 @@ install_package() { } # install essential packages -if ! command -v python || ! command -v python3; then - install_package python-is-python3 -fi -if ! command -v psql; then - install_package postgresql - install_package postgresql-client -fi -if ! dpkg -l | grep jdk-17; then - install_package openjdk-17-jdk-headless -fi -if ! command -v mvn; then - install_package maven -fi -if ! command -v systemctl; then - install_package systemd -fi +install_package python-is-python3 log_info "Deploying..." python script/deploy_helper.py \ diff --git a/script/deploy_helper.py b/script/deploy_helper.py index 4d05ed6..9ce940a 100644 --- a/script/deploy_helper.py +++ b/script/deploy_helper.py @@ -13,6 +13,16 @@ import logging import inspect +essential_packages = ['python-is-python3', 'postgresql postgresql-client', + 'openjdk-17-jdk-headless', 'maven', 'systemd'] +sudo_cmd = os.popen('command -v sudo').read().strip() +apt_updated = False +message_tmp = '''\ +The command below failed: + {0} +Expected status code 0, got status code {1} +''' + def setup_logger(log_level=logging.INFO): """ @@ -21,7 +31,7 @@ def setup_logger(log_level=logging.INFO): :param log_level: Set the logging level, defaulting to INFO. """ logging.basicConfig(level=log_level, - format='%(asctime)s -%(levelname)s- in %(pathname)s:%(caller_lineno)d: %(message)s', + format='%(asctime)s -%(levelname)s- in %(pathname)s:%(caller_lineno)d: %(message)s', datefmt='%Y-%m-%d %H:%M:%S') @@ -39,6 +49,16 @@ def command_checker(status_code: int, message: str, expected_code: int = 0): exit(status_code) +def log_info(message: str): + caller_frame = inspect.currentframe().f_back + logging.info(message, extra={'caller_lineno': caller_frame.f_lineno}) + + +def log_debug(message: str): + caller_frame = inspect.currentframe().f_back + logging.debug(message, extra={'caller_lineno': caller_frame.f_lineno}) + + # open config_path and default_config_path # union the result as an new obj # return the new obj or None if error @@ -49,7 +69,7 @@ def load_config_file_as_obj(config_path: str, default_config_path: str): with open(default_config_path, 'r') as f: default_config = json.load(f, object_hook=lambda d: SimpleNamespace(**d)) except Exception as e: - print(f"Error: {e}") + command_checker(1, f"Error: {e}") return None for key in default_config.__dict__: if not hasattr(config, key): @@ -58,23 +78,17 @@ def load_config_file_as_obj(config_path: str, default_config_path: str): def parse_iterable_into_str(iterable, sep=" "): - res = "" - for it in iterable: - res += f'{it}{sep}' - res.strip() - return res + return sep.join(iterable).strip() def create_systemd_service(config): - if config == None: - return -1 + assert(config != None) exec_start = parse_iterable_into_str( [config.serviceStartJavaCommand] + config.serviceStartJavaArgs + [config.serviceStartJarFile]) wanted_by = parse_iterable_into_str(config.serviceWantedBy) after = parse_iterable_into_str(config.serviceAfter) - service_full_path = f'/etc/systemd/system/{config.serviceName}.{config.serviceSuffix}' - gcs_file_content = \ -f"""\ + service_full_path = f'{config.serviceSystemdDirectory}/{config.serviceName}.{config.serviceSuffix}' + gcs_file_content = f"""\ [Unit] Description={config.serviceDescription} After={after} @@ -90,37 +104,109 @@ def create_systemd_service(config): [Install] WantedBy={wanted_by} """ - command = f'echo "{gcs_file_content}" | sudo tee {service_full_path}' + command = f'echo "{gcs_file_content}" | {sudo_cmd} tee {service_full_path}' + res = os.system(command) + message = message_tmp.format(command, res) + command_checker(res, message) + + +def create_sys_v_init_service(config): + try: + with open('script/service_tmp.sh', 'r') as f: + service_content = f.read() + except Exception as e: + command_checker(1, f"Error: {e}") + return + + header = f'''#!/bin/env bash +NAME={config.serviceName} +SCRIPT="{parse_iterable_into_str([config.serviceStartJavaCommand] + +config.serviceStartJavaArgs + [config.serviceStartJarFile])}" +RUNAS={config.serviceUser} +PIDFILE={config.servicePIDFile} +LOGFILE={config.serviceLogFile} +''' + service_content = header + service_content + log_debug(f"service_content:\n {service_content}") + + res = os.system( + f"echo '{service_content}' | {sudo_cmd} tee {config.serviceSysVInitDirectory}/{config.serviceName}") + command_checker(res, f"Failed to create {config.serviceSysVInitDirectory}/{config.serviceName}") + res = os.system(f'{sudo_cmd} chmod +x {config.serviceSysVInitDirectory}/{config.serviceName}') + command_checker( + res, f"Failed to chmod +x {config.serviceSysVInitDirectory}/{config.serviceName}") + + if logging.getLogger().level == logging.DEBUG: + try: + with open(f'{config.serviceSysVInitDirectory}/{config.serviceName}', 'r') as f: + log_debug(f"Service content:\n {f.read()}") + except Exception as e: + command_checker(1, f"Error: {e}") + return + + +def apt_install_package(name): + global apt_updated + if not apt_updated: + res = os.system(f'{sudo_cmd} apt update') + command_checker(res, 'Failed to update apt') + apt_updated = True + res = os.system(f'{sudo_cmd} apt install -y {name}') + command_checker(res, f'Failed to install {name}') + + +def deploy_with_systemd(config): + create_systemd_service(config) + if config.serviceEnable: + command = f'{sudo_cmd} systemctl enable {config.serviceName}' + res = os.system(command) + message = message_tmp.format(command, res) + command_checker(res, message) + else: + command = f'{sudo_cmd} systemctl disable {config.serviceName}' + res = os.system(command) + message = message_tmp.format(command, res) + command_checker(res, message) + command = f'{sudo_cmd} systemctl start {config.serviceName}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) -# TODO: add checker to check +def deploy_with_sys_v_init(config): + create_sys_v_init_service(config) + res = os.system(f'{sudo_cmd} service {config.serviceName} start') + command_checker(res, f"Failed to start {config.serviceName}") + if config.serviceStartWithBoot: + res = os.system(f'{sudo_cmd} update-rc.d {config.serviceName} defaults') + command_checker(res, f"Failed to start {config.serviceName} with boot") + + def deploy_on_ubuntu(config): - if config == None: - return -1 + assert(config != None) + if config.inDocker: + essential_packages.remove('systemd') + apt_install_package(parse_iterable_into_str(essential_packages)) skip_test = "" if config.skipTest: skip_test = "-Dmaven.test.skip=true" res = subprocess.run('bash script/get_jar_position.sh', shell=True, capture_output=True, text=True) - if res.returncode != 0: - return res.returncode + command_checker(res.returncode, res.stderr) package_path = res.stdout.strip() - command = f'mvn package {skip_test}' + command = f'mvn package {skip_test}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) if config.deploy: if os.system(f"cat /etc/passwd | grep -w -E '^{config.serviceUser}'") != 0: - command = f'sudo useradd {config.serviceUser}' + command = f'{sudo_cmd} useradd {config.serviceUser}' res = os.system(command) message = message_tmp.format(command, res) - command_checker(res, message) + command_checker(res, message) if config.serviceUserPassword == None or config.serviceUserPassword == "": - command =f'sudo passwd -d {config.serviceUser}' + command = f'{sudo_cmd} passwd -d {config.serviceUser}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) @@ -133,69 +219,62 @@ def deploy_on_ubuntu(config): process.communicate() if not os.path.exists(os.path.dirname(config.serviceStartJarFile)): - command = f'sudo mkdir -p {os.path.dirname(config.serviceStartJarFile)}' + command = f'{sudo_cmd} mkdir -p {os.path.dirname(config.serviceStartJarFile)}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) - command = f'sudo cp {package_path} {config.serviceStartJarFile}' + command = f'{sudo_cmd} cp {package_path} {config.serviceStartJarFile}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) - create_systemd_service(config) - if config.serviceEnable: - command = f'sudo systemctl enable {config.serviceName}' - res = os.system(command) - message = message_tmp.format(command, res) - command_checker(res, message) + if config.inDocker: + deploy_with_sys_v_init(config) else: - command = f'sudo systemctl disable {config.serviceName}' - res = os.system(command) - message = message_tmp.format(command, res) - command_checker(res, message) - command = f'sudo systemctl start {config.serviceName}' - res = os.system(command) - message = message_tmp.format(command, res) - command_checker(res, message) - # TODO: finish deploy on docker + deploy_with_systemd(config) -# TODO: add checker to check def clean(config): - command = f'sudo systemctl disable {config.serviceName}' + if config.deployWithDocker: + res = os.system(f"docker stop {config.dockerName}") + command_checker(res, f"Failed to stop {config.dockerName}") + res = os.system(f"docker rm {config.dockerName}") + command_checker(res, f"Failed to remove {config.dockerName}") + return + command = f'{sudo_cmd} systemctl disable {config.serviceName}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) - command = f'sudo systemctl stop {config.serviceName}' + command = f'{sudo_cmd} systemctl stop {config.serviceName}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) - if os.path.exists(f'/etc/systemd/system/{config.serviceName}.{config.serviceSuffix}'): - command = f'''sudo rm -rf /etc/systemd/system/{config.serviceName}.{config.serviceSuffix} && \\ - sudo systemctl daemon-reload''' + if os.path.exists(f'{config.serviceSystemdDirectory}/{config.serviceName}.{config.serviceSuffix}'): + command = f'''{sudo_cmd} rm -rf {config.serviceSystemdDirectory}/{config.serviceName}.{config.serviceSuffix} && \\ + {sudo_cmd} systemctl daemon-reload''' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) - command = f'sudo systemctl reset-failed {config.serviceName}' + command = f'{sudo_cmd} systemctl reset-failed {config.serviceName}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) if os.path.exists(f'{config.serviceWorkingDirectory}'): - command = f'sudo rm -rf {config.serviceWorkingDirectory}' + command = f'{sudo_cmd} rm -rf {config.serviceWorkingDirectory}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) if os.path.exists(f'{config.serviceStartJarFile}'): - command = f'sudo rm -rf {config.serviceStartJarFile}' + command = f'{sudo_cmd} rm -rf {config.serviceStartJarFile}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) if os.path.exists(f'{config.servicePIDFile}'): - command = f'sudo rm -rf {config.servicePIDFile}' + command = f'{sudo_cmd} rm -rf {config.servicePIDFile}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) if os.system(f"cat /etc/passwd | grep -w -E '^{config.serviceUser}'") == 0: - command = f'sudo userdel {config.serviceUser}' + command = f'{sudo_cmd} userdel {config.serviceUser}' res = os.system(command) message = message_tmp.format(command, res) command_checker(res, message) @@ -205,12 +284,7 @@ def clean(config): command_checker(res, message) -if __name__ == "__main__": - message_tmp = '''\ -The command below failed: - {0} -Expected status code 0, got status code {1} -''' +def get_cli_args(): parser = argparse.ArgumentParser( description="Deploy the project when the environment is ready.") parser.add_argument('--config-path', nargs='?', default='../config.json', @@ -221,21 +295,58 @@ def clean(config): type=str, help="Linux distribution") parser.add_argument('--clean', action='store_true', help="Clean up the project") parser.add_argument('--log-level', nargs='?', default='INFO', - type=str, help=( - "Set the logging level. Possible values are: " - "'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'. " - "Default is 'INFO'.\n" - "- DEBUG: Detailed information, typically of interest only when diagnosing problems.\n" - "- INFO: Confirmation that things are working as expected.\n" - "- WARNING: An indication that something unexpected happened, or indicative of some problem in the near future. The software is still working as expected.\n" - "- ERROR: Due to a more serious problem, the software has not been able to perform some function.\n" - "- CRITICAL: A very serious error, indicating that the program itself may be unable to continue running." - )) - args = parser.parse_args() + type=str, help=( + "Set the logging level. Possible values are: " + "'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'. " + "Default is 'INFO'.\n" + "- DEBUG: Detailed information, typically of interest only when diagnosing problems.\n" + "- INFO: Confirmation that things are working as expected.\n" + "- WARNING: An indication that something unexpected happened, or indicative of some problem in the near future. The software is still working as expected.\n" + "- ERROR: Due to a more serious problem, the software has not been able to perform some function.\n" + "- CRITICAL: A very serious error, indicating that the program itself may be unable to continue running." + )) + parser.add_argument('--in-docker', action='store_true', help="Whether or not deploy in docker") + return parser.parse_args() + + +def deploy_in_docker(config): + res = os.system(f'cd 3rdparty/docker-script && ' + f'bash create_docker.sh -n {config.dockerName} -d {config.dockerImage} ' + f'-w {int(config.dockerWithGpu)} ' + f'-p {parse_iterable_into_str(config.dockerPortMapping, sep = " -p ")}') + command_checker(res, f"Failed to create docker: {config.dockerName}") + res = os.system(f'{sudo_cmd} docker exec -it {config.dockerName} ' + f'bash -c "sudo apt update && sudo apt install -y python-is-python3"') + command_checker(res, f"Failed to install python-is-python3 in docker: {config.dockerName}") + res = os.system(f'{sudo_cmd} docker cp . {config.dockerName}:{config.dockerSrcPath}') + command_checker(res, f"Failed to copy the repository to docker: {config.dockerName}") + res = os.system(f'{sudo_cmd} docker exec -it {config.dockerName} ' + f'bash -c "cd {config.dockerSrcPath} && ' + f'python script/deploy_helper.py --config-path {config.configPath} ' + f'--default-config-path {config.defaultConfigPath} ' + f'--distro {config.distro} --in-docker"') + command_checker(res, f"Failed to deploy in docker: {config.dockerName}") + return + + +def main(): + args = get_cli_args() if args.log_level.upper() not in logging._nameToLevel: raise ValueError(f"Invalid log level: {args.log_level}") setup_logger(getattr(logging, args.log_level.upper())) + config = load_config_file_as_obj(args.config_path, args.default_config_path) + assert(config != None) + setattr(config, 'inDocker', args.in_docker) + setattr(config, 'configPath', args.config_path) + setattr(config, 'defaultConfigPath', args.default_config_path) + setattr(config, 'distro', args.distro) if args.clean: - clean(load_config_file_as_obj(args.config_path, args.default_config_path)) + clean(config) + elif not args.in_docker and config.deployWithDocker: + deploy_in_docker(config) elif args.distro == 'ubuntu': - exit(deploy_on_ubuntu(load_config_file_as_obj(args.config_path, args.default_config_path))) + deploy_on_ubuntu(config) + + +if __name__ == "__main__": + main() diff --git a/script/service_tmp.sh b/script/service_tmp.sh new file mode 100644 index 0000000..f4281e8 --- /dev/null +++ b/script/service_tmp.sh @@ -0,0 +1,55 @@ +PIDDIR=$(dirname "$PIDFILE") +LOGDIR=$(dirname "$LOGFILE") +start() { + if [ -f "$PIDDIR/$PIDNAME" ] && kill -0 "$(cat "$PIDDIR/$PIDNAME")"; then + echo 'Service already running' >&2 + return 1 + fi + echo 'Starting service…' >&2 + local CMD="$SCRIPT &> \"$LOGFILE\" & echo \$!" + su -c "mkdir -p ""$PIDDIR" "$RUNAS" + su -c "mkdir -p ""$LOGDIR" "$RUNAS" + su -c "$CMD" "$RUNAS" > "$PIDFILE" + echo 'Service started' >&2 +} + +stop() { + if [ ! -f "$PIDFILE" ] || ! kill -0 "$(cat "$PIDFILE")"; then + echo 'Service not running' >&2 + return 1 + fi + echo 'Stopping service…' >&2 + kill -15 "$(cat "$PIDFILE")" && rm -f "$PIDFILE" + echo 'Service stopped' >&2 +} + +uninstall() { + echo -n "Are you really sure you want to uninstall this service? That cannot be undone. [yes|No] " + local SURE + read SURE + if [ "$SURE" = "yes" ]; then + stop + rm -f "$PIDFILE" + echo "Notice: log file is not be removed: '$LOGFILE'" >&2 + update-rc.d -f "$NAME" remove + rm -fv "$0" + fi +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + uninstall) + uninstall + ;; + restart) + stop + start + ;; + *) + echo "Usage: $0 {start|stop|restart|uninstall}" +esac