234 lines
5.9 KiB
Python
234 lines
5.9 KiB
Python
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/<name>
|
|
@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/<repo>', 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/<repo>/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/<repo>/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/<repo>/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/<task_id>/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/<repo>', 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/<repo>/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')
|
|
|
|
|