diff --git a/api/gitapi.py b/api/gitapi.py index dc00d0f..6458150 100644 --- a/api/gitapi.py +++ b/api/gitapi.py @@ -3,13 +3,54 @@ import os.path import os import git import shutil +import subprocess +import uuid from opengnsys_git_installer import OpengnsysGitInstaller -from flask import request +from flask import Flask, request +from flask_executor import Executor +import subprocess +from flask import stream_with_context, Response repositories_base_path = "/opt/opengnsys/images" # Create an instance of the Flask class app = Flask(__name__) +executor = Executor(app) + + + +tasks = {} + + +def do_repo_backup(repo, params): + + user = params["ssh_user"] + server = params["ssh_server"] + filename = params["filename"] + + os.chdir(repositories_base_path) + os.chdir(f"{repo}.git") + + subprocess.run(f"git archive --format=tar HEAD | ssh {user}@{server} -T \"cat > {filename}\"", shell=True, check=True) + #sleep(10) + +def do_repo_sync(repo, params): + gitrepo = git.Repo(f"{repositories_base_path}/{repo}.git") + + # Recreate the remote every time, it might change + if "backup" in gitrepo.remotes: + gitrepo.delete_remote("backup") + + backup_repo = gitrepo.create_remote("backup", params["remote_repository"]) + pushrets = backup_repo.push("*:*") + results = [] + + # This gets returned to the API + for ret in pushrets: + results = results + [ {"local_ref" : ret.local_ref.name, "remote_ref" : ret.remote_ref.name, "summary" : ret.summary }] + + return results + # Define a route for the root URL @app.route('/') @@ -63,11 +104,19 @@ def sync_repo(repo): data = request.json + + if data is None: + return jsonify({"error" : "Parameters missing"}), 400 + dest_repo = data["remote_repository"] + future = executor.submit(do_repo_sync, repo, data) + task_id = str(uuid.uuid4()) + tasks[task_id] = future + return jsonify({"status": "started", "task_id" : task_id}), 200 - return jsonify({"status": "Started synchronization", "repository" : repo, "destination_repository" : dest_repo}), 200 + # return jsonify({"status": "Started synchronization", "repository" : repo, "destination_repository" : dest_repo}), 200 @app.route('/repositories//backup', methods=['POST']) @@ -79,11 +128,35 @@ def backup_repo(repo): data = request.json + if data is None: + return jsonify({"error" : "Parameters missing"}), 400 + dest_server = data["ssh_server"] dest_user = data["ssh_user"] dest_file = data["filename"] - return jsonify({"status": "Started backup", "repository" : repo, "ssh_server" : dest_server, "ssh_user" : dest_user, "filename" : dest_file}), 200 + + future = executor.submit(do_repo_backup, repo, data) + task_id = str(uuid.uuid4()) + tasks[task_id] = future + + return jsonify({"status": "started", "task_id" : task_id}), 200 + + #return jsonify({"status": "Started backup", "repository" : repo, "ssh_server" : dest_server, "ssh_user" : dest_user, "filename" : dest_file}), 200 + +@app.route('/tasks//status') +def tasks_status(task_id): + if not task_id in tasks: + return jsonify({"error": "Task not found"}), 404 + + future = tasks[task_id] + + if future.done(): + result = future.result() + return jsonify({"status" : "completed", "result" : result}), 200 + else: + return jsonify({"status" : "in progress"}), 202 + @app.route('/repositories/', methods=['DELETE']) diff --git a/api/requirements.txt b/api/requirements.txt index c2fb0d6..985e8b7 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -2,6 +2,7 @@ click==8.0.4 colorterm==0.3 dataclasses==0.8 Flask==2.0.3 +Flask-Executor==1.0.0 gitdb==4.0.9 GitPython==3.1.20 importlib-metadata==4.8.3