diff --git a/clean_ubuntu.sh b/clean_ubuntu.sh new file mode 100644 index 0000000..caeb553 --- /dev/null +++ b/clean_ubuntu.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# USAGE: bash clean_ubuntu.sh [config_file] + +config_file=${1:-"config.json"} + +# TODO: reuse the log_error and log_info functions from deploy_ubuntu.sh +log_error () { + echo -e "\e[31m[ERROR]: $1\e[0m" + exit 1 +} + +log_info () { + echo "[INFO]: $1" +} + +log_info "Cleaning up..." +python script/deploy_helper.py \ + --config-path "$config_file" \ + --clean \ + --distro ubuntu \ + --default-config-path ./config_default.json || \ + log_error "Failed to run deploy_helper.py for cleaning up the environment" diff --git a/config.json b/config.json index 1181c53..2c63c08 100644 --- a/config.json +++ b/config.json @@ -1,5 +1,2 @@ { - "name": "noname", - "sex": "nosex", - "age": 10 } diff --git a/config_debug.json b/config_debug.json index 4049507..ecf04f1 100644 --- a/config_debug.json +++ b/config_debug.json @@ -1,12 +1,7 @@ { - "deploy": true, "createGitUser": false, "deployWithDocker": false, "repositoryDirectory": "~/.local/gcs/repository", - "serviceUser": "gcs", - "servicePassword": "gcs", - "serviceName": "gcs", - "postgresPassword": null, "debug": true, "runTest": true } diff --git a/config_default.json b/config_default.json new file mode 100644 index 0000000..7326e02 --- /dev/null +++ b/config_default.json @@ -0,0 +1,30 @@ +{ + "deploy": true, + "debug": false, + "runTest": false, + "createGitUser": true, + "deployWithDocker": true, + "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", + "serviceRestartDelaySecond": 5, + "serviceStartJavaCommand": "/usr/bin/java", + "serviceStartJavaArgs": [ + "-jar" + ], + "serviceStartJarFile": "/opt/gcs/gcs.jar", + "serviceAfter": [ + "network.target" + ], + "serviceWantedBy": [ + "multi-user.target" + ] +} diff --git a/deploy_ubuntu.sh b/deploy_ubuntu.sh index 84635f1..13d9676 100644 --- a/deploy_ubuntu.sh +++ b/deploy_ubuntu.sh @@ -38,6 +38,13 @@ fi if ! command -v mvn; then install_package maven fi +if ! command -v systemctl; then + install_package systemd +fi -python script/deploy_helper.py -f "$config_file" -d ubuntu || \ - log_error "Failed to run deploy_helper.py $config_file" +log_info "Deploying..." +python script/deploy_helper.py \ + --config-path "$config_file" \ + --distro ubuntu \ + --default-config-path ./config_default.json || \ + log_error "Failed to run deploy_helper.py for deploying the environment" diff --git a/script/deploy_helper.py b/script/deploy_helper.py index a18b367..aaaf106 100644 --- a/script/deploy_helper.py +++ b/script/deploy_helper.py @@ -12,14 +12,61 @@ import subprocess -def load_json_file_as_obj(file_path: str): +# open config_path and default_config_path +# union the result as an new obj +# return the new obj or None if error +def load_config_file_as_obj(config_path: str, default_config_path: str): try: - with open(file_path, 'r', encoding='utf-8') as file: - data = json.load(file, object_hook=lambda d: SimpleNamespace(**d)) + with open(config_path, 'r') as f: + config = json.load(f, object_hook=lambda d: SimpleNamespace(**d)) + 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}") return None - return data + for key in default_config.__dict__: + if not hasattr(config, key): + setattr(config, key, getattr(default_config, key)) + return config + + +def parse_iterable_into_str(iterable, sep=" "): + res = "" + for it in iterable: + res += f'{it}{sep}' + res.strip() + return res + + +def create_systemd_service(config): + if config == None: + return -1 + 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"""\ +[Unit] +Description={config.serviceDescription} +After={after} + +[Service] +PIDFile={config.servicePIDFile} +User={config.serviceUser} +WorkingDirectory={config.serviceWorkingDirectory} +Restart={config.serviceRestartPolicy} +RestartSec={config.serviceRestartDelaySecond} +ExecStart={exec_start} + +[Install] +WantedBy={wanted_by} +""" + res = os.system( + f'echo "{gcs_file_content}" | sudo tee {service_full_path}') + if res != 0: + exit(res) # TODO: add checker to check @@ -32,13 +79,7 @@ def deploy_on_ubuntu(config): print("Test failed.") return res if config.deploy: - if os.path.exists(f'/etc/init.d/{config.serviceName}'): - res = os.system(f'sudo service {config.serviceName} stop && ' - f'sudo rm /etc/init.d/{config.serviceName} && ' - f'sudo systemctl daemon-reload') - if res != 0: - return res - res = subprocess.run('script/get_jar_position.sh', shell=True, + res = subprocess.run('bash script/get_jar_position.sh', shell=True, capture_output=True, text=True) if res.returncode != 0: return res.returncode @@ -49,34 +90,68 @@ def deploy_on_ubuntu(config): if os.system(f"cat /etc/passwd | grep -w -E '^{config.serviceUser}'") != 0: os.system(f'sudo useradd {config.serviceUser}') - process = subprocess.Popen(['sudo', 'chpasswd'], stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - assert(process.stdin is not None) - process.stdin.write(f'{config.serviceUser}:{config.servicePassword}') - process.stdin.flush() - process.communicate() - - res = os.system( - f'sudo chown {config.serviceUser}:{config.serviceUser} {package_path}') - if res != 0: - return res - res = os.system(f'sudo ln -s {package_path} /etc/init.d/{config.serviceName}') + if config.serviceUserPassword == None or config.serviceUserPassword == "": + os.system(f'sudo passwd -d {config.serviceUser}') + else: + process = subprocess.Popen(['sudo', 'chpasswd'], stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + assert(process.stdin is not None) + process.stdin.write(f'{config.serviceUser}:{config.serviceUserPassword}') + process.stdin.flush() + process.communicate() + + if not os.path.exists(os.path.dirname(config.serviceStartJarFile)): + os.system(f'sudo mkdir -p {os.path.dirname(config.serviceStartJarFile)}') + res = os.system(f'sudo cp {package_path} {config.serviceStartJarFile}') if res != 0: return res - res = os.system( - f'sudo systemctl daemon-reload && sudo service {config.serviceName} start &') + create_systemd_service(config) + if config.serviceEnable: + res = os.system(f'sudo systemctl enable {config.serviceName}') + if res != 0: + return res + else: + res = os.system(f'sudo systemctl disable {config.serviceName}') + if res != 0: + return res + res = os.system(f'sudo systemctl start {config.serviceName}') if res != 0: return res # TODO: finish deploy on docker +# TODO: add checker to check +def clean(config): + os.system(f'sudo systemctl disable {config.serviceName}') + os.system(f'sudo systemctl stop {config.serviceName}') + if os.path.exists(f'/etc/systemd/system/{config.serviceName}.{config.serviceSuffix}'): + os.system( + f'sudo rm -rf /etc/systemd/system/{config.serviceName}.{config.serviceSuffix} && ' + f'sudo systemctl daemon-reload') + os.system(f'sudo systemctl reset-failed {config.serviceName}') + if os.path.exists(f'{config.serviceWorkingDirectory}'): + os.system(f'sudo rm -rf {config.serviceWorkingDirectory}') + if os.path.exists(f'{config.serviceStartJarFile}'): + os.system(f'sudo rm -rf {config.serviceStartJarFile}') + if os.path.exists(f'{config.servicePIDFile}'): + os.system(f'sudo rm -rf {config.servicePIDFile}') + if os.system(f"cat /etc/passwd | grep -w -E '^{config.serviceUser}'") == 0: + os.system(f'sudo userdel {config.serviceUser}') + os.system(f'mvn clean') + + if __name__ == "__main__": parser = argparse.ArgumentParser( description="Deploy the project when the environment is ready.") - parser.add_argument('-f', '--file_path', nargs='?', default='../config.json', + parser.add_argument('--config-path', nargs='?', default='../config.json', type=str, help="Path to the JSON file") - parser.add_argument('-d', '--distro', nargs='?', default='ubuntu', + parser.add_argument('--distro', nargs='?', default='ubuntu', + type=str, help="Linux distribution") + parser.add_argument('--default-config-path', nargs='?', default='../config_default.json', type=str, help="Linux distribution") + parser.add_argument('--clean', action='store_true', help="Clean up the project") args = parser.parse_args() - if args.distro == 'ubuntu': - exit(deploy_on_ubuntu(load_json_file_as_obj(args.file_path))) + if args.clean: + clean(load_config_file_as_obj(args.config_path, args.default_config_path)) + elif args.distro == 'ubuntu': + exit(deploy_on_ubuntu(load_config_file_as_obj(args.config_path, args.default_config_path)))