Compare commits

..

No commits in common. "oggit" and "main" have entirely different histories.
oggit ... main

5 changed files with 52 additions and 1332 deletions

View File

@ -48,22 +48,6 @@ trash_file = '/opt/opengnsys/ogrepository/etc/trashinfo.json'
config_file = '/opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg' config_file = '/opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg'
# --------------------------------------------------------------------------------------------
# GIT
# --------------------------------------------------------------------------------------------
REPOSITORIES_BASE_PATH = "/opt/opengnsys/ogrepository/oggit/git/"
OGGIT_USER = "oggit"
import sys
import git
import pkgutil
import importlib
import paramiko
# -------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------
# FUNCTIONS # FUNCTIONS
# -------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------
@ -2210,720 +2194,6 @@ def rename_image():
# -----------------------------------------------------------
# ____ _ _
# / ___(_) |_
# | | _| | __|
# | |_| | | |_
# \____|_|\__|
#
# -----------------------------------------------------------
def git_compact_repository_task(repo, job_id):
journal.send("Running function 'git_compact_repository_task'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
git_repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
git_repo = git.Repo(git_repo_path)
git_repo.git.config('--global', '--add', 'safe.directory', git_repo_path)
git_repo.git.gc()
data = {
'job_id': job_id,
'success': True
}
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: True)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
recall_ogcore(data)
def git_sync_repository_task(repo, remote_repository, job_id):
journal.send("Running function 'git_sync_repository_task'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
git_repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
git_repo = git.Repo(git_repo_path)
git_repo.git.config('--global', '--add', 'safe.directory', git_repo_path)
# Recreate the remote every time, it might change
if "backup" in git_repo.remotes:
git_repo.delete_remote("backup")
backup_repo = git_repo.create_remote("backup", remote_repository)
pushed_references = backup_repo.push("*:*")
results = []
# This gets returned to the API
for ref in pushed_references:
results = results + [ {"local_ref" : ref.local_ref.name, "remote_ref" : ref.remote_ref.name, "summary" : ref.summary }]
data = {
'job_id': job_id,
'success': True,
'updated_references' : results
}
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: True)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
recall_ogcore(data)
def git_backup_repository_task(repo, params, job_id):
journal.send("Running function 'git_sync_repository_task'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
git_repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
git_repo = git.Repo(git_repo_path)
git_repo.git.config('--global', '--add', 'safe.directory', git_repo_path)
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:
git_repo.archive(remote_file, format="tar.gz")
data = {
'job_id': job_id,
'success': True,
}
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: True)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
recall_ogcore(data)
def git_add_sshkey_task(oglive, description, job_id):
module = _load_installer()
print(f"Got {module}")
OpengnsysGitInstaller = getattr(module, 'OpengnsysGitInstaller')
installer = OpengnsysGitInstaller()
results = installer.add_ssh_key_from_squashfs(oglive_file = oglive)
keys_added = 0
keys_existed = 0
keys_failed = 0
for status, message in results:
if status == 200 or status == 201:
keys_added = keys_added + 1
elif status == 422:
keys_existed = keys_existed + 1
else:
keys_failed = keys_failed + 1
journal.send(f"Unrecognized reply from forgejo: code {status}, content {message}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
data = {
'job_id': job_id,
'keys_added' : keys_added,
'keys_failed' : keys_failed,
'keys_existed' : keys_existed,
'output' : message
}
journal.send(f"Calling function 'recall_ogcore' (JOB_ID: {job_id}, SUCCESS: True)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
recall_ogcore(data)
@app.route("/ogrepository/v1/git/repositories", methods=['GET'])
def git_list_repositories():
"""
Retrieve a list of Git repositories.
This endpoint scans the OpenGnsys image path for directories that
appear to be Git repositories (i.e., they contain a "HEAD" file).
It returns a JSON response containing the names of these repositories.
Returns:
Response: A JSON response with a list of repository names or an
error message if the repository storage is not found.
- 200 OK: When the repositories are successfully retrieved.
- 500 Internal Server Error: When the repository storage is not found.
Example JSON response:
{
"repositories": ["repo1", "repo2"]
}
"""
journal.send("Running endpoint 'Obtener Información de todos los repositorios Git'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
if not os.path.isdir(REPOSITORIES_BASE_PATH):
journal.send(f"Can't list repositories. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Repository storage not found, git functionality may not be installed."}), 500
repos = []
if os.path.exists(os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER)):
# If the base path exists, but the OGGIT_USER subpath doesn't, it means we've got an empty
# install. OgGit is present, but there's no repos yet.
for entry in os.scandir(os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER)):
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]
journal.send(f"Returning {len(repos)} repositories", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({
"repositories": repos
}), 200
def _load_module(module_name):
# module = importlib.util.find_spec(module_name)
module = importlib.import_module(module_name)
if module is not None:
journal.send(f"Module {module_name} loaded successfully. Got {module}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="oggit-api_DEBUG")
return module
journal.send(f"Module {module_name} failed to load, not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="oggit-api_DEBUG")
return False
def _load_installer():
journal.send(f"Loading oggit installer module", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="oggit-api_DEBUG")
script_dir = os.path.dirname(os.path.realpath(__file__))
system_bin_path = '/opt/opengnsys/ogrepository/oggit/bin/'
system_lib_path = '/opt/opengnsys/ogrepository/oggit/lib/'
devel_lib_path = os.path.join(script_dir, "../../oggit/installer")
if devel_lib_path not in sys.path and os.path.isdir(devel_lib_path):
journal.send(f"Using {devel_lib_path} development library path", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="oggit-api_DEBUG")
sys.path.append(devel_lib_path)
if system_bin_path not in sys.path:
journal.send(f"Using {system_bin_path} system library path", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="oggit-api_DEBUG")
sys.path.append(system_bin_path)
if system_lib_path not in sys.path:
journal.send(f"Using {system_lib_path} system library path", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="oggit-api_DEBUG")
sys.path.append(system_lib_path)
return _load_module("opengnsys_git_installer")
@app.route("/ogrepository/v1/git/repositories", methods=['POST'])
def git_create_repository():
"""
Create a new Git repository.
This endpoint creates a new Git repository with the specified name.
If the repository already exists, it returns a status message indicating so.
Args:
repo (str): The name of the repository to be created.
Returns:
Response: A JSON response with a status message and HTTP status code.
- 409: If the repository already exists.
- 201: If the repository is successfully created.
"""
data = request.json
if data is None:
journal.send(f"Can't create repository, JSON post data missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
repo = data["name"]
repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
if os.path.isdir(repo_path):
journal.send(f"Can't create repository {repo}, already exists at {repo_path}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"status": "Repository already exists"}), 409
module = _load_installer()
print(f"Got {module}")
OpengnsysGitInstaller = getattr(module, 'OpengnsysGitInstaller')
installer = OpengnsysGitInstaller()
installer.add_forgejo_repo(repo)
journal.send(f"Repository {repo} created", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"status": "Repository created"}), 201
@app.route("/ogrepository/v1/git/repositories", methods=['DELETE'])
def git_delete_repository():
return jsonify({"error" : "Not implemented"}), 500
@app.route("/ogrepository/v1/git/repositories/<string:repo>/sync", methods=['POST'])
def git_sync_repository(repo):
journal.send("Running endpoint 'Sincronizar repositorio Git'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
if not os.path.isdir(REPOSITORIES_BASE_PATH):
journal.send(f"Can't sync repositories. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Repository storage not found, git functionality may not be installed."}), 500
data = request.json
if data is None:
journal.send(f"Can't sync repository, JSON post data missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
if "remote_repository" in data:
remote_repository = data["remote_repository"]
else:
journal.send(f"Can't sync repository, JSON remote_repository parameter missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
job_id = f"GitSync_{''.join(random.choice('0123456789abcdef') for char in range(8))}"
threading.Thread(target=git_sync_repository_task, args=(repo, remote_repository, job_id,)).start()
return jsonify({
"success": True,
"output": "Synchronizing...",
"job_id": job_id
}), 200
@app.route("/ogrepository/v1/git/repositories/<string:repo>/backup", methods=['POST'])
def git_backup_repository(repo):
journal.send("Running endpoint 'Backup de repositorio Git'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
if not os.path.isdir(REPOSITORIES_BASE_PATH):
journal.send(f"Can't backup repositories. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Repository storage not found, git functionality may not be installed."}), 500
data = request.json
if data is None:
journal.send(f"Can't backup repository, JSON post data missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
if not "ssh_server" in data:
journal.send(f"Can't sync repository, JSON ssh_server parameter missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
if not "ssh_port" in data:
journal.send(f"Can't sync repository, JSON ssh_port parameter missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
if not "ssh_user" in data:
journal.send(f"Can't sync repository, JSON ssh_user parameter missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
if not "filename" in data:
journal.send(f"Can't sync repository, JSON filename parameter missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
job_id = f"GitBackup_{''.join(random.choice('0123456789abcdef') for char in range(8))}"
threading.Thread(target=git_backup_repository_task, args=(repo, data, job_id,)).start()
return jsonify({
"success": True,
"output": "Backing up...",
"job_id": job_id
}), 200
@app.route("/ogrepository/v1/git/repositories/<string:repo>/compact", methods=['POST'])
def git_compact_repository(repo):
journal.send("Running endpoint 'Compactar repositorio Git'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
if not os.path.isdir(REPOSITORIES_BASE_PATH):
journal.send(f"Can't list repositories. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Repository storage not found, git functionality may not be installed."}), 500
job_id = f"GitGC_{''.join(random.choice('0123456789abcdef') for char in range(8))}"
threading.Thread(target=git_compact_repository_task, args=(repo, job_id,)).start()
return jsonify({
"success": True,
"output": "Compacting...",
"job_id": job_id
}), 200
@app.route("/ogrepository/v1/git/repositories/<string:repo>/branches", methods=['GET'])
def git_get_branches(repo):
"""
Retrieve the list of branches for a given repository.
Args:
repo (str): The name of the repository.
Returns:
Response: A JSON response containing a list of branch names or an error message if the repository is not found.
- 200: A JSON object with a "branches" key containing a list of branch names.
- 404: A JSON object with an "error" key containing the message "Repository not found" if the repository does not exist.
"""
repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
if not os.path.isdir(repo_path):
journal.send(f"Can't list repositories. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Repository not found"}), 404
git_repo = git.Repo(repo_path)
git_repo.git.config('--global', '--add', 'safe.directory', repo_path)
branches = []
for branch in git_repo.branches:
branches = branches + [branch.name]
journal.send(f"Returning {len(branches)} branches", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return {
"branches": branches
}
@app.route("/ogrepository/v1/git/repositories/<string:repo>/branches/<string:branch>/commits", methods=['GET'])
def git_get_commits(repo, branch):
"""
Retrieve the list of commits in a branch in a given repository.
Args:
repo (str): The name of the repository.
Returns:
Response: A JSON response containing a list of commits
- 200: A JSON object with a "branches" key containing a list of branch names.
- 404: A JSON object with an "error" key containing the message "Repository not found" if the repository does not exist.
"""
repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
if not os.path.isdir(repo_path):
journal.send(f"Can't list repositories. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Repository not found"}), 404
max_commits = request.args.get('max_commits') or 100
skip_commits = request.args.get('skip') or 0
git_repo = git.Repo(repo_path)
git_repo.git.config('--global', '--add', 'safe.directory', repo_path)
if not branch in git_repo.branches:
journal.send(f"Branch {branch} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Branch not found"}), 404
# Lookup table for hash/tag
hash_to_tag = {}
for tag in git_repo.tags:
sha = tag.commit.hexsha
if not sha in hash_to_tag:
hash_to_tag[sha] = []
hash_to_tag[sha] = hash_to_tag[sha] + [ tag.name ]
commits = []
for com in git_repo.iter_commits(branch, max_count = max_commits, skip = skip_commits):
tag_list = []
if com.hexsha in hash_to_tag:
tag_list = hash_to_tag[com.hexsha]
commits = commits + [
{
"hexsha" : com.hexsha,
"message" : com.message,
"committed_date" : com.committed_date,
"tags" : tag_list,
"size" : com.size
}
]
journal.send(f"Returning {len(commits)} commits", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return {
"commits": commits
}
@app.route("/ogrepository/v1/git/repositories/<string:repo>/branches", methods=['POST'])
def git_create_branch(repo):
"""Create a given branch in a given repository
Args:
repo (str): The name of the repository.
Returns:
Response: A JSON response containing a creation status
- 201: A JSON object with a "status" key containing "created"
- 404: A JSON object with an "error" key containing the message "Repository not found"
- 409: A JSON object with an "error" key containing the message "Branch already exists"
"""
repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
if not os.path.isdir(repo_path):
journal.send(f"Can't create branch. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Repository not found"}), 404
git_repo = git.Repo(repo_path)
git_repo.git.config('--global', '--add', 'safe.directory', repo_path)
data = request.json
if data is None:
journal.send(f"Can't create branch. JSON post data missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
if not "commit" in data:
journal.send(f"Can't create branch. Commit parameter missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "commit parameter missing"}), 400
if not "name" in data:
journal.send(f"Can't create branch. Name parameter missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "name parameter missing"}), 400
branch = data["name"]
if branch in git_repo.branches:
journal.send(f"Can't create branch. Already found in repository {repo}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Branch already exists"}), 409
git_repo.create_tag(branch, ref = data["commit"])
journal.send(f"Branch {branch} created in repo {repo}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"status": "created"}), 201
@app.route("/ogrepository/v1/git/repositories/<string:repo>/branches/<string:branch>", methods=['DELETE'])
def git_delete_branch(repo, branch):
"""Delete a given branch in a given repository
Args:
repo (str): The name of the repository.
Returns:
Response: A JSON response containing a list of branch names or an error message if the repository is not found.
- 200: A JSON object with a "status" key containing "deleted"
- 404: A JSON object with an "error" key containing the message "Repository not found" or "Branch not found"
"""
repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
if not os.path.isdir(repo_path):
journal.send(f"Can't delete branch. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return {"error": "Repository not found"}, 404
git_repo = git.Repo(repo_path)
git_repo.git.config('--global', '--add', 'safe.directory', repo_path)
if not branch in git_repo.branches:
journal.send(f"Can't delete branch. Not found in repository {repo}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Branch not found"}), 404
git_repo.delete_head(branch)
journal.send(f"Branch {branch} deleted in repo {repo}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"status": "deleted"}), 200
@app.route("/ogrepository/v1/git/repositories/<string:repo>/tags", methods=['GET'])
def git_list_tags(repo):
"""
Retrieve the list of tags for a given repository.
Args:
repo (str): The name of the repository.
Returns:
Response: A JSON response containing a list of tag names or an error message if the repository is not found.
- 200: A JSON object with a "branches" key containing a list of tag names.
- 404: A JSON object with an "error" key containing the message "Repository not found" if the repository does not exist.
"""
repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
if not os.path.isdir(repo_path):
journal.send(f"Can't list repositories. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Repository not found"}), 404
git_repo = git.Repo(repo_path)
git_repo.git.config('--global', '--add', 'safe.directory', repo_path)
tags = []
for tag in git_repo.tags:
tag_info = {
"name" : tag.name,
"commit" : tag.commit.hexsha,
"committer" : tag.commit.committer.name,
"committed_datetime" : tag.commit.committed_datetime.timestamp()
}
if not tag.tag is None:
tag_info["message"] = tag.tag.message
tag_info["tagged_date"] = tag.tag.tagged_date
tag_info["tagger"] = tag.tag.tagger.name
tag_info["tagger_tz_offset"] = tag.tag.tagger_tz_offset
tags = tags + [ tag_info ]
journal.send(f"Returning {len(tags)} branches", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return {
"tags": tags
}
@app.route("/ogrepository/v1/git/repositories/<string:repo>/tags", methods=['POST'])
def git_create_tag(repo):
"""Create a given tag in a given repository
Args:
repo (str): The name of the repository.
Returns:
Response: A JSON response containing a creation status
- 200: A JSON object with a "status" key containing "created"
- 404: A JSON object with an "error" key containing the message "Repository not found"
- 409: A JSON object with an "error" key containing the message "Tag already exists"
"""
repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
if not os.path.isdir(repo_path):
journal.send(f"Can't create tag. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Repository not found"}), 404
git_repo = git.Repo(repo_path)
git_repo.git.config('--global', '--add', 'safe.directory', repo_path)
data = request.json
if data is None:
journal.send(f"Can't create tag. JSON post data missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
if not "commit" in data:
journal.send(f"Can't create tag. Commit parameter missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "commit parameter missing"}), 400
if not "name" in data:
journal.send(f"Can't create tag. Name parameter missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "name parameter missing"}), 400
commit_message = ""
tag = data["name"]
if "message" in data:
commit_message = data["message"]
if tag in git_repo.tags:
journal.send(f"Can't create tag. Already found in repository {repo}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Tag already exists"}), 409
try:
git_repo.create_tag(tag, ref = data["commit"], message = commit_message)
except git.exc.GitCommandError as ge:
if "not a valid tag name" in ge.stderr:
journal.send(f"Tag name {tag} is invalid", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Invalid tag name"}), 400
else:
journal.send(f"Git error {ge}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Error when performing git command"}), 500
journal.send(f"Tag {tag} created in repo {repo}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"status": "created"}), 200
@app.route("/ogrepository/v1/git/repositories/<string:repo>/tags/<string:tag>", methods=['DELETE'])
def git_delete_tag(repo, tag):
"""Delete a given tag in a given repository
Args:
repo (str): The name of the repository.
Returns:
Response: A JSON response containing a list of tag names or an error message if the repository is not found.
- 200: A JSON object with a "status" key containing "deleted"
- 404: A JSON object with an "error" key containing the message "Repository not found" or "Tag not found"
"""
repo_path = os.path.join(REPOSITORIES_BASE_PATH, OGGIT_USER, repo + ".git")
if not os.path.isdir(repo_path):
journal.send(f"Can't delete tag. Repository storage at {REPOSITORIES_BASE_PATH} not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return {"error": "Repository not found"}, 404
git_repo = git.Repo(repo_path)
git_repo.git.config('--global', '--add', 'safe.directory', repo_path)
if not tag in git_repo.tags:
journal.send(f"Can't delete tag. Not found in repository {repo}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error": "Tag not found"}), 404
git_repo.delete_head(tag)
journal.send(f"Tag {tag} deleted in repo {repo}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"status": "deleted"}), 200
@app.route("/ogrepository/v1/git/ssh_key", methods=['POST'])
def git_add_sshkey():
"""Add a SSH key
Args:
ssh_key (str): The SSH key
oglive (str): URL to an oglive image from which to extract the key. May be a local file or HTTP.
description (str): Description for the SSH key
Returns:
Response: A JSON response containing a list of tag names or an error message if the key can't be added.
- 200: A JSON object with a "status" key containing "added"
"""
data = request.json
if data is None:
journal.send(f"Can't add SSH keys, POST data missing", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing"}), 400
if not "description" in data:
data["description"] = ""
if not ("ssh_key" in data or "oglive" in data):
journal.send(f"Can't add SSH keys, either ssh_key or oglive is required", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({"error" : "Parameters missing, specify ssh_key or oglive"}), 400
module = _load_installer()
print(f"Got {module}")
OpengnsysGitInstaller = getattr(module, 'OpengnsysGitInstaller')
installer = OpengnsysGitInstaller()
if "oglive" in data:
job_id = f"GitSshKey_{''.join(random.choice('0123456789abcdef') for char in range(8))}"
threading.Thread(target=git_add_sshkey_task, args=(data["oglive"], data["description"], job_id)).start()
return jsonify({
"success": True,
"output": "Extracting key from ogLive...",
"job_id": job_id
}), 200
else:
status, content = installer.add_forgejo_sshkey(data["ssh_key"], data["description"])
message = "Result unrecognized"
success = False
httpcode = 500
if status == 200 or status == 201:
message = "SSH key added"
success = True
httpcode = 200
elif status == 422:
message = "SSH key already existed"
success = True
httpcode = 200
else:
message = "Unrecognized reply from forgejo"
success = False
httpcode = status
journal.send(f"Unrecognized reply from forgejo: code {status}, content {content}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
return jsonify({
"success": success,
"output": message,
}), httpcode
# -------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------

View File

@ -18,7 +18,7 @@ tags:
- name: "Transferencia entre Repositorios y Backup" - name: "Transferencia entre Repositorios y Backup"
- name: "Importar y Exportar Máquinas Virtuales" - name: "Importar y Exportar Máquinas Virtuales"
- name: "Varios" - name: "Varios"
- name: "Git"
# ----------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------
# Apartado "Estado de ogRepository" # Apartado "Estado de ogRepository"
@ -1960,521 +1960,3 @@ paths:
example: "(Exception description)" example: "(Exception description)"
# ----------------------------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------------------------
# -----------------------------------------------------------
# ____ _ _
# / ___(_) |_
# | | _| | __|
# | |_| | | |_
# \____|_|\__|
#
# -----------------------------------------------------------
/ogrepository/v1/git/ssh_key:
post:
summary: "Agregar clave de SSH de ogLive"
description: |
Agrega una clave de SSH que va a usarse desde el ogLive
para interactuar con Git.
Es necesario especificar **ssh_key** o **oglive**.
Especificando **ssh_key** se agrega la cclave especificada directamente.
Especificando **oglive** se descarga si es necesario el .iso, se monta, y se extrae la clave.
Esta acción se hace en el fondo, y se devuelve un job_id.
tags:
- "Git"
parameters:
- name: JSON
in: body
required: true
description: |
* **ssh_key** - Clave de SSH (opcional)
* **oglive** - URL a ogLive (opcional, NO USAR DE MOMENTO)
* **description** - Descripcion (opcional)
schema:
type: object
properties:
ssh_key:
type: string
example: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINEOttwhJ+9THRZ1Zv/6QUwPUDq1X7opG9V7EFLVWxQV"
required: False
description:
type: string
example: "OgLive r20250518"
required: False
oglive:
type: string
example: "https://ognproject.evlt.uma.es/oglive/ogLive-noble-6.8.0-31-generic-amd64-r20250518.cf13a6d_20250519.iso"
required: False
responses:
"200":
description: "Exito"
schema:
type: object
properties:
success:
type: boolean
example: True
required: True
output:
type: string
example: "SSH key added"
required: True
job_id:
type: string
example: "GitSshKey_873f353f"
required: False
/ogrepository/v1/git/repositories:
get:
summary: "Obtener lista de repositorios"
description: |
Devuelve una lista de repositorios de Git
tags:
- "Git"
responses:
"200":
description: "Lista de repositorios"
schema:
type: object
properties:
repositories:
type: array
items:
type: string
example: linux
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
post:
summary: "Crear repositorio"
description: |
Crea un repositorio nuevo de Git
tags:
- "Git"
parameters:
- name: JSON
in: body
required: true
description: |
* **name** - Nombre de repositorio
schema:
type: object
properties:
name:
type: string
example: linux
responses:
"201":
description: "Repositorio creado"
schema:
type: object
properties:
status:
type: string
example: "Repository created"
"500 (Exception)":
description: "JSON post data missing"
schema:
type: object
properties:
error:
type: string
example: "Parameters missing"
/ogrepository/v1/git/repositories/{repository}/tags:
get:
summary: "Obtener lista de tags"
description: |
Devuelve una lista de tags de Git
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
responses:
"200":
description: "Lista de tags"
schema:
type: object
properties:
tags:
type: array
items:
type: object
properties:
name:
type: string
example: v0.1
commit:
type: string
example: db8e84d5d2548f589ee503c1c6d5003cc6a0d803
committer:
type: string
example: John Smith
committed_datetime:
type: int
example: 1745360193
message:
type: string
example: "Initial release"
required: False
tagged_date:
type: int
example: 1745360194
required: False
tagger:
type: string
example: John Smith
required: False
tagger_tz_offset:
type: int
example: -7200
required: False
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
post:
summary: "Crear tag"
description: |
Crea una tag de git
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
- name: JSON
in: body
required: true
description: |
* **name** - Nombre del tag
* **commit** - Commit al que apunta el tag nuevo. Puede ser un nombre de otra rama/tag.
* **message** - Mensaje descriptivo para el tag. Opcional, si no se especifica se asume una cadena vacía.
schema:
type: object
properties:
name:
type: string
example: v1.0
required: True
commit:
type: string
example: HEAD
required: True
message:
type: string
example: Version 1.0
required: False
responses:
"201":
description: "Tag creado"
schema:
type: object
properties:
status:
type: string
example: created
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
"404":
description: "El repositorio no existe"
schema:
type: object
properties:
error:
type: string
example: "Repository not found"
"409":
description: "El tag ya existe"
schema:
type: object
properties:
error:
type: string
example: "Tag already exists"
delete:
summary: "Eliminar tag"
description: |
Elimina un tag de git
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
- name: tag
in: path
required: true
type: string
description: "Rama del repositorio"
responses:
"200":
description: "Tag eliminado"
schema:
type: object
properties:
status:
type: string
example: deleted
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
/ogrepository/v1/git/repositories/{repository}/branches/{branch}/commits:
get:
summary: "Obtener lista de commits en una rama"
description: |
Devuelve una lista de commits de Git
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
- name: branch
in: path
required: true
type: string
description: "Rama dentro del repositorio"
- name: max_commits
in: query
required: false
type: int
description: "Máximo de commits a obtener"
- name: skip
in: query
required: false
type: int
description: "Commits a saltar (para paginación)"
responses:
"200":
description: "Lista de commits"
schema:
type: object
properties:
commits:
type: array
items:
type: object
properties:
committed_date:
type: int
example: 1745360193
hexsha:
type: string
example: "db8e84d5d2548f589ee503c1c6d5003cc6a0d803"
message:
type: string
example: "Install updates"
size:
type: int
example: 67108864
tags:
type: array
example: ["updates"]
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
"404":
description: "El repositorio o branch no existe"
schema:
type: object
properties:
error:
type: string
example: "Repository not found"
/ogrepository/v1/git/repositories/{repository}/branches:
get:
summary: "Obtener lista de branches"
description: |
Devuelve una lista de branches de Git
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
responses:
"200":
description: "Lista de branches"
schema:
type: object
properties:
branches:
type: array
items:
type: string
example: main
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
"404":
description: "El repositorio no existe"
schema:
type: object
properties:
error:
type: string
example: "Repository not found"
"409":
description: "El branch ya existe"
schema:
type: object
properties:
error:
type: string
example: "Branch already exists"
post:
summary: "Crear branch"
description: |
Crea una rama de git
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
- name: JSON
in: body
required: true
description: |
* **commit** - Commit al que apunta la rama nueva. Puede ser un nombre de otra rama/tag.
schema:
type: object
properties:
name:
type: string
example: devel
required: True
commit:
type: string
example: HEAD
required: True
responses:
"201":
description: "Rama creada"
schema:
type: array
items:
type: string
example: main
"500":
description: "Git no instalado"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
delete:
summary: "Eliminar branch"
description: |
Elimina una rama de git
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
- name: branch
in: path
required: true
type: string
description: "Branch del repositorio"
responses:
"200":
description: "Branch eliminado"
schema:
type: object
properties:
status:
type: string
example: deleted
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"

20
debian/changelog vendored
View File

@ -1,23 +1,3 @@
ogrepository (1.1.2) UNRELEASED; urgency=medium
* Fix path handling when there are no repositories
* Add another search path for installer module
* Fix path handling
* Add SSH key endpoint
* Update dependencies
-- OpenGnsys <opengnsys@opengnsys.com> Tue, 30 Jun 2025 15:20:23 +0000
ogrepository (1.1.1) unstable; urgency=medium
* OgGit - fix repo path handling
-- Tu Nombre <tuemail@example.com> Jue, 5 Jun 2025 08:43:58 +0000
ogrepository (1.1.0) unstable; urgency=medium
* OgGit
-- Tu Nombre <tuemail@example.com> Tue, 11 Mar 2025 04:43:58 +0000
ogrepository (1.0.0+deb-packages20250311-1) unstable; urgency=medium ogrepository (1.0.0+deb-packages20250311-1) unstable; urgency=medium
* First debian version * First debian version

2
debian/control vendored
View File

@ -8,7 +8,7 @@ Build-Depends: debhelper-compat (= 12)
Package: ogrepository Package: ogrepository
Architecture: all Architecture: all
Pre-Depends: debian-archive-keyring , debconf (>= 1.5.0), Pre-Depends: debian-archive-keyring , debconf (>= 1.5.0),
Depends: ${misc:Depends}, git, python3, python3-pip, python3-flask, python3-paramiko, python3-psutil, python3-flasgger, samba, gunicorn, wakeonlan , lzop , partclone , qemu-utils , udpcast, uftp, mktorrent, aria2 , opengnsys-opentracker, opengnsys-gitinstaller, opengnsys-forgejo Depends: ${misc:Depends}, git, python3, python3-pip, python3-flask, python3-paramiko, python3-psutil, python3-flasgger, samba, gunicorn, wakeonlan , lzop , partclone , qemu-utils , udpcast, uftp, mktorrent, aria2 , opengnsys-opentracker
Description: Ogrepsoitory Package Description: Ogrepsoitory Package
This package provides Ogrepository service. This package provides Ogrepository service.

View File

@ -53,16 +53,6 @@ USER="opengnsys"
# done # done
# " # "
if [ "$1" = "configure" ] && [ -z "$2" ]; then if [ "$1" = "configure" ] && [ -z "$2" ]; then
systemd-run --no-block /bin/bash -c "
sleep 10;
apt update -y;
for pkg in bittorrent bittornado ctorrent; do
if ! dpkg -l | grep -qw \"\$pkg\"; then
apt install -y \"\$pkg\"
fi
done
"
sed -i "s/%%OGREPOSITORY_USER%%/$SAMBA_USER/g" /etc/systemd/system/ogrepo-api.service sed -i "s/%%OGREPOSITORY_USER%%/$SAMBA_USER/g" /etc/systemd/system/ogrepo-api.service
sed -i "s/%%OGREPOSITORY_USER%%/$SAMBA_USER/g" /etc/samba/ogrepo-smb.conf sed -i "s/%%OGREPOSITORY_USER%%/$SAMBA_USER/g" /etc/samba/ogrepo-smb.conf
@ -125,10 +115,8 @@ fi
# Cambiar la propiedad de los archivos al usuario especificado # Cambiar la propiedad de los archivos al usuario especificado
chown opengnsys:www-data /opt/opengnsys/ chown opengnsys:www-data /opt/opengnsys/
chown -R opengnsys:www-data /opt/opengnsys/ogrepository chown -R opengnsys:www-data /opt/opengnsys/ogrepository
chmod 755 /opt/opengnsys
chmod 755 /opt/opengnsys/ogrepository/bin/* chmod 755 /opt/opengnsys/ogrepository/bin/*
# Install http server stuff # Install http server stuff
# Reiniciar servicios si es necesario # Reiniciar servicios si es necesario
# systemctl restart nombre_del_servicio # systemctl restart nombre_del_servicio