from flask import Flask, jsonify import os.path import os import git import shutil import subprocess import uuid from opengnsys_git_installer import OpengnsysGitInstaller from flask import Flask, request from flask_executor import Executor import subprocess from flask import stream_with_context, Response import paramiko 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): gitrepo = git.Repo(f"{repositories_base_path}/{repo}.git") ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(params["ssh_server"], params["ssh_port"], params["ssh_user"]) sftp = ssh.open_sftp() with sftp.file(params["filename"], mode='wb+') as remote_file: gitrepo.archive(remote_file, format="tar.gz") return True 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 def do_repo_gc(repo): gitrepo = git.Repo(f"{repositories_base_path}/{repo}.git") gitrepo.git.gc() return True # Define a route for the root URL @app.route('/') def home(): return jsonify({ "message": "OpenGnsys Git API" }) # Define another route for /hello/ @app.route('/repositories') def get_repositories(): if not os.path.isdir(repositories_base_path): return jsonify({"error": "Repository storage not found, git functionality may not be installed."}), 500 repos = [] for entry in os.scandir(repositories_base_path): if entry.is_dir(follow_symlinks=False) and os.path.isfile(os.path.join(entry.path, "HEAD")): name = entry.name if name.endswith(".git"): name = name[:-4] repos = repos + [name] return jsonify({ "repositories": repos }) @app.route('/repositories/', methods=['PUT']) def create_repo(repo): repo_path = os.path.join(repositories_base_path, repo + ".git") if os.path.isdir(repo_path): return jsonify({"status": "Repository already exists"}), 200 installer = OpengnsysGitInstaller() installer._init_git_repo(repo + ".git") return jsonify({"status": "Repository created"}), 201 @app.route('/repositories//sync', methods=['POST']) def sync_repo(repo): repo_path = os.path.join(repositories_base_path, repo + ".git") if not os.path.isdir(repo_path): return jsonify({"error": "Repository not found"}), 404 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 @app.route('/repositories//backup', methods=['POST']) def backup_repo(repo): repo_path = os.path.join(repositories_base_path, repo + ".git") if not os.path.isdir(repo_path): return jsonify({"error": "Repository not found"}), 404 data = request.json if data is None: return jsonify({"error" : "Parameters missing"}), 400 if not "ssh_port" in data: data["ssh_port"] = 22 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('/repositories//gc', methods=['POST']) def gc_repo(repo): repo_path = os.path.join(repositories_base_path, repo + ".git") if not os.path.isdir(repo_path): return jsonify({"error": "Repository not found"}), 404 future = executor.submit(do_repo_gc, repo) task_id = str(uuid.uuid4()) tasks[task_id] = future return jsonify({"status": "started", "task_id" : task_id}), 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']) def delete_repo(repo): repo_path = os.path.join(repositories_base_path, repo + ".git") if not os.path.isdir(repo_path): return jsonify({"error": "Repository not found"}), 404 shutil.rmtree(repo_path) return jsonify({"status": "Repository deleted"}), 200 @app.route('/repositories//branches') def get_repository_branches(repo): repo_path = os.path.join(repositories_base_path, repo + ".git") if not os.path.isdir(repo_path): return jsonify({"error": "Repository not found"}), 404 gitRepo = git.Repo(repo_path) branches = [] for branch in gitRepo.branches: branches = branches + [branch.name] return jsonify({ "branches": branches }) # Define a route for health check @app.route('/health') def health_check(): return jsonify({ "status": "OK" }) # Run the Flask app if __name__ == '__main__': app.run(debug=True, host='0.0.0.0')