Compare commits
33 Commits
813cae1a7e
...
199ef8c5e1
Author | SHA1 | Date |
---|---|---|
|
199ef8c5e1 | |
|
05b51de851 | |
|
228bd85aa8 | |
|
3992ff27f0 | |
|
8728682936 | |
|
a1f0561f5c | |
|
e355562714 | |
|
8dcd1faefd | |
|
05b963d611 | |
|
da5d6fd8c5 | |
|
3c2fc27e2e | |
|
b04bf3c5b1 | |
|
bff65cde01 | |
|
984b251615 | |
|
28f2537aed | |
|
c949cfb9a9 | |
|
9f87997722 | |
|
a387af27d0 | |
|
9a9cf17403 | |
|
ba5384ea77 | |
|
74efebf3c8 | |
|
88953696e7 | |
|
f972ae1ae9 | |
|
95524ac9cf | |
|
ccf04ba8fc | |
|
9f170c23c7 | |
|
6236be85d8 | |
|
0118ca53a5 | |
|
bada82e88a | |
|
a3b938e41e | |
|
dd60800c97 | |
|
ecbba3d45e | |
|
a58023f893 |
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,5 +1,20 @@
|
|||
# Changelog
|
||||
|
||||
## [0.9.0] - 2025-06-25
|
||||
|
||||
## Added
|
||||
|
||||
- Changed old tools for tools non dependant of Pyhton2 in repo
|
||||
- mktorrent to handle creation of torrent files
|
||||
- aria2c as torrent client for initial seeding
|
||||
- opentracker as torrent tracker tool
|
||||
|
||||
## [0.8.2] - 2025-06-01
|
||||
|
||||
### Changed
|
||||
|
||||
- Modified sudoersfile to start torrent
|
||||
|
||||
## [0.8.1] - 2025-04-01
|
||||
|
||||
### Changed
|
||||
|
|
819
api/repo_api.py
819
api/repo_api.py
|
@ -2,16 +2,16 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
API de ogRepository, programada en Flask.
|
||||
API de ogRepository, programada en Flask.
|
||||
|
||||
Responde a peticiones HTTP (en principio, enviadas desde ogCore) mediante endpoints, que a su vez ejecutan los scripts Python almacenados en ogRepository.
|
||||
En ciertos casos, transforma los parámetros recibidos desde el portal, para adaptarlos a los que es necesario enviar a los scripts
|
||||
(por ejemplo, a partir del ID de una imagen obtiene su nombre y su extensión).
|
||||
(por ejemplo, a partir del ID de una imagen obtiene su nombre y su extensión).
|
||||
|
||||
Librerías Python requeridas: - flask (se puede instalar con "sudo apt install python3-flask")
|
||||
- paramiko (se puede instalar con "sudo apt install python3-paramiko")
|
||||
Librerías Python requeridas: - flask (se puede instalar con "sudo apt install python3-flask")
|
||||
- paramiko (se puede instalar con "sudo apt install python3-paramiko")
|
||||
- requests (se puede instalar con "sudo apt install python3-requests") - No es necesario instalarlo en Ubuntu 24
|
||||
- flasgger (se puede instalar con "sudo apt install python3-flasgger")
|
||||
- flasgger (se puede instalar con "sudo apt install python3-flasgger")
|
||||
"""
|
||||
|
||||
# --------------------------------------------------------------------------------------------
|
||||
|
@ -48,6 +48,22 @@ trash_file = '/opt/opengnsys/ogrepository/etc/trashinfo.json'
|
|||
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
|
||||
# --------------------------------------------------------------------------------------------
|
||||
|
@ -73,9 +89,9 @@ swagger = Swagger(app, template=swagger_template)
|
|||
def get_IPcore():
|
||||
""" Obtiene el valor asociado a la variable "IPcore", desde el archivo '/opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg'.
|
||||
Retorna la IP encontrada (que corresponde a la IP de ogCore), o un error (si no la encuentra).
|
||||
"""
|
||||
"""
|
||||
journal.send("Running function 'get_IPcore'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
||||
|
||||
IPcore = None
|
||||
with open(config_file, 'r') as file:
|
||||
for line in file:
|
||||
|
@ -143,7 +159,7 @@ def search_process(process, string_to_search):
|
|||
""" Busca procesos que contengan el valor del parámetro "process" y el valor del parámetro "string_to_search" (la ruta de la imagen, normalmente).
|
||||
Si encuentra alguno retorna "True", y si no encuentra ninguno retorna "False".
|
||||
"""
|
||||
journal.send("Running function 'search_process'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send(f"Running function 'search_process' {process} wit string {string_to_search}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
||||
try:
|
||||
# Obtenemos todos los procesos que están corriendo, y almacenamos la salida y los errores:
|
||||
|
@ -155,11 +171,11 @@ def search_process(process, string_to_search):
|
|||
|
||||
# Si hemos encontrado algún proceso que cumpla las condiciones, retornamos "True", y si no retornamos "False":
|
||||
if process_list != []:
|
||||
journal.send("Process found", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send(f"Process found: {process} with string {string_to_search} ", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'INFO', 'operation':'Run function search_process', 'desc':'Process found'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
return True
|
||||
else:
|
||||
journal.send("Process not found", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send(f"Process not found: {process} with string {string_to_search}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'WARNING', 'operation':'Run function search_process', 'desc':'Process not found'}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
return False
|
||||
# Si se ha producido una excepción, imprimimos el error:
|
||||
|
@ -327,7 +343,7 @@ def check_remote_backup(image_name, remote_ip, remote_user, remote_path, job_id)
|
|||
# Creamos un bucle infinito:
|
||||
while True:
|
||||
# Comprobamos si ya se ha copiado la imagen y cada uno de sus archivos asociados (y almacenamos el resultado):
|
||||
try:
|
||||
try:
|
||||
for ext in extensions:
|
||||
sftp_client.stat(f"{remote_path}{image_name}{ext}")
|
||||
all_files_copied = True
|
||||
|
@ -601,7 +617,7 @@ def recall_ogcore(data):
|
|||
|
||||
def check_file_exists(file_path):
|
||||
""" Comprueba la existencia del archivo cuya ruta recibe como parámetro.
|
||||
Si el archivo existe devuelve "True", y si no devuelve "False".
|
||||
Si el archivo existe devuelve "True", y si no devuelve "False".
|
||||
"""
|
||||
journal.send("Running function 'check_file_exists'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
||||
|
@ -671,7 +687,7 @@ def get_repo_status():
|
|||
journal.send("Running script 'getRepoStatus.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
# Ejecutamos el script "getRepoStatus.py", y almacenamos el resultado:
|
||||
result = subprocess.run(['python3', f"{script_path}/getRepoStatus.py"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
||||
|
||||
|
||||
# Evaluamos el resultado de la ejecución, y devolvemos la respuesta:
|
||||
if result.returncode == 0:
|
||||
journal.send("Script 'getRepoStatus.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
@ -973,7 +989,7 @@ def recover_image():
|
|||
|
||||
# Almacenamos el parámetro "ID_img" (enviado por JSON):
|
||||
json_data = json.loads(request.data)
|
||||
image_id = json_data.get("ID_img")
|
||||
image_id = json_data.get("ID_img")
|
||||
|
||||
# Obtenemos el nombre y la extensión de la imagen:
|
||||
param_dict = get_image_params(image_id, "trash")
|
||||
|
@ -1136,7 +1152,7 @@ def import_image():
|
|||
if result.returncode is None:
|
||||
journal.send("Script 'importImage.py' result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script importImage.py', 'desc':'Result OK (ReturnCode: None)'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
|
||||
|
||||
# Si el resultado es correcto, llamamos a la función "check_lock_local" en un hilo paralelo
|
||||
# (para que compruebe si la imagen se ha acabado de importar exitosamente):
|
||||
journal.send("Calling function 'check_lock_local'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
@ -1179,7 +1195,7 @@ def import_image():
|
|||
def backup_image():
|
||||
""" Este endpoint exporta la imagen especificada como primer parámetro (y todos sus archivos asociados), desde el servidor local a un equipo remoto (que no tiene por qué ser un repositorio).
|
||||
Para ello, ejecuta el script "backupImage.py", con el nombre de la imagen como primer parámetro, la IP o hostname del equipo remoto como segundo parámetro,
|
||||
el usuario con el que conectar al equipo remoto como tercer parámetro, y la ruta remota en la que copiar la imagen como cuarto parámetro.
|
||||
el usuario con el que conectar al equipo remoto como tercer parámetro, y la ruta remota en la que copiar la imagen como cuarto parámetro.
|
||||
"""
|
||||
journal.send("Running endpoint 'Hacer backup de una Imagen'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
||||
|
@ -1260,7 +1276,7 @@ def backup_image():
|
|||
}), 200
|
||||
else:
|
||||
journal.send("Script 'backupImage.py' result KO (Backup image failed)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script backupImage.py', 'desc':'Result KO (Backup image failed)'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script backupImage.py', 'desc':'Result KO (Backup image failed)'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "Backup image failed"
|
||||
|
@ -1357,7 +1373,7 @@ def create_torrent_sum():
|
|||
# ---------------------------------------------------------
|
||||
|
||||
|
||||
# 12 - Endpoint "Enviar paquete Wake On Lan" (SINCRONO):
|
||||
# 12 - Endoint "Enviar paquete Wake On Lan" (SINCRONO):
|
||||
@app.route("/ogrepository/v1/wol", methods=['POST'])
|
||||
def send_wakeonlan():
|
||||
""" Este endpoint envía un paquete mágico Wake On Lan a la dirección MAC especificada, a través de la IP de broadcast especificadac.
|
||||
|
@ -1567,8 +1583,7 @@ def send_p2p():
|
|||
|
||||
# Evaluamos los parámetros obtenidos, para construir las llamadas a los scripts, o para devolver un error si no se ha encontrado la imagen:
|
||||
if param_dict:
|
||||
cmd_tracker = ['sudo', 'python3', f"{script_path}/runTorrentTracker.py"] # Este script si que requiere ser ejecutado con "sudo"
|
||||
cmd_seeder = ['sudo', 'python3', f"{script_path}/runTorrentSeeder.py"] # Este script si que requiere ser ejecutado con "sudo"
|
||||
cmd_seeder = ['python3', f"{script_path}/runTorrentSeeder.py" , param_dict['name']] # Este script si que requiere ser ejecutado con "sudo" , Lanzamos el seeder con el nombre de la imagen como parámetro
|
||||
base_path = repo_path.rstrip('/') # Le quito la última barra para poder buscar correctamente en los procesos
|
||||
else:
|
||||
journal.send("Image not found", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
@ -1578,11 +1593,18 @@ def send_p2p():
|
|||
"error": "Image not found"
|
||||
}), 400
|
||||
|
||||
# Ejecutamos los scripts "runTorrentSeeder.py" y "runTorrentSeeder.py", que no reciben parámetros.
|
||||
# NOTA: No almacenamos la salida ni comprobamos los errores, porque los procesos quedarán corriendo hasta que se finalicen manualmente,
|
||||
# por lo que no podemos comprobar el returncode (luego comprobaremos si los procesos se han iniciado correctamente).
|
||||
journal.send("Running script 'runTorrentTracker.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
subprocess.Popen(cmd_tracker)
|
||||
# Comprobamos si el tracker esta ejecutandose, si no lo esta devolevemos un error y salimos del endpoint:
|
||||
tracker_running = search_process('opentracker' , '/etc/opentracker/opentracker.conf') # El tracker se ececuta con "opentracker" y el fichero de configuración "/etc/opentracker/opentracker.conf"
|
||||
if not tracker_running:
|
||||
journal.send("Tracker not running", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run opentrack', 'desc':'Tracker not running'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
error_message = "Tracker not running. Check if the tracker is installed and configured correctly."
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": error_message
|
||||
}), 500
|
||||
|
||||
# Ejecutamos los scripts "runTorrentSeeder.py", que no reciben parámetros.
|
||||
|
||||
journal.send("Running script 'runTorrentSeeder.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
subprocess.Popen(cmd_seeder)
|
||||
|
@ -1590,25 +1612,28 @@ def send_p2p():
|
|||
# Comprobamos si el tracker y el seeder están corriendo, y si apuntan al directorio que le hemos pasado
|
||||
# (esperamos 10 segundos antes de hacerlo, porque los procesos no se inician inmediatamente):
|
||||
sleep(10)
|
||||
tracker_running = search_process('bttrack', base_path)
|
||||
seeder_running = search_process('btlaunchmany', base_path)
|
||||
seeder_running = search_process('aria2c', f"{param_dict['name']}.img.torrent") # El seeder se ejecuta con "aria2c" y el nombre de la imagen como parámetro
|
||||
|
||||
|
||||
# Evaluamos las comprobaciones anteriores, para devolver la respuesta que corresponda:
|
||||
if tracker_running and seeder_running:
|
||||
journal.send("Scripts 'runTorrentTracker.py' and 'runTorrentSeeder.py' results OK (ReturnCodes: None), and processes running", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run scripts runTorrentTracker.py and runTorrentSeeder.py', 'desc':'Results OK (ReturnCodes: None), and processes running'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
if seeder_running:
|
||||
journal.send("'runTorrentSeeder.py' results OK (ReturnCodes: None), and processes running", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script runTorrentSeeder.py', 'desc':'Results OK (ReturnCodes: None), and processes running'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"output": "Tracker and Seeder serving image correctly"
|
||||
}), 200
|
||||
else:
|
||||
journal.send("Scripts 'runTorrentTracker.py' and 'runTorrentSeeder.py' results KO (Tracker or/and Seeder not runnig)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run scripts runTorrentTracker.py and runTorrentSeeder.py', 'desc':'Results KO (Tracker or/and Seeder not runnig)'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
journal.send("Script 'runTorrentSeeder.py' results KO (Seeder not runnig)", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'ERROR', 'http_code':'500', 'operation':'Run script runTorrentSeeder.py', 'desc': '" + error_message + "'}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
error_message = f"Seeder not running. Check if the image {param_dict['name']}.{param_dict['extension']} exists in the repository."
|
||||
|
||||
return jsonify({
|
||||
"success": False,
|
||||
"error": "Tracker or Seeder (or both) not running"
|
||||
"error": error_message
|
||||
}), 500
|
||||
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
|
@ -1875,7 +1900,7 @@ def stop_p2p():
|
|||
journal.send("Running script 'stopP2P.py'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
# Ejecutamos el script "stopP2P.py", y almacenamos el resultado (este script si que requiere ser ejecutado con "sudo"):
|
||||
result = subprocess.run(['sudo', 'python3', f"{script_path}/stopP2P.py"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='UTF8')
|
||||
|
||||
|
||||
# Evaluamos el resultado de la ejecución, y devolvemos la respuesta:
|
||||
if result.returncode == 0:
|
||||
journal.send("Script 'stopP2P.py' result OK (ReturnCode: 0)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
@ -1909,7 +1934,7 @@ def convert_virtual_image():
|
|||
""" Este endpoint convierte la imagen virtual especificada como parámetro en una imagen "img" como las que se generan desde OpenGnsys
|
||||
(con "partclone" y "lzop"), por lo que luego puede ser restaurada como cualquier otra imagen del repositorio.
|
||||
Para ello, ejecuta el script "convertVMtoIMG.py", con el nombre de la imagen virtual como primer parámetro,
|
||||
y el sistema de archivos de la partición a clonar (en formato "blkid") como segundo parámetro.
|
||||
y el sistema de archivos de la partición a clonar (en formato "blkid") como segundo parámetro.
|
||||
"""
|
||||
journal.send("Running endpoint 'Convertir imagen virtual a imagen OpenGnsys'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
||||
|
@ -1972,7 +1997,7 @@ def convert_virtual_image():
|
|||
if result.returncode is None:
|
||||
journal.send("Script 'convertVMtoIMG.py' result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script convertVMtoIMG.py', 'desc':'Result OK (ReturnCode: None)'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
|
||||
|
||||
# Si el resultado es correcto, llamamos a la función "check_virtual_image_conversion" en un hilo paralelo
|
||||
# (para que compruebe si la imagen se ha acabado de convertir exitosamente):
|
||||
journal.send("Calling function 'check_virtual_image_conversion'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
@ -2015,7 +2040,7 @@ def convert_virtual_image():
|
|||
def convert_image_to_virtual():
|
||||
""" Este endpoint convierte la imagen de OpenGnsys especificada como parámetro en una imagen virtual con la extensión especificada (".vdi", ".vmdk", etc).
|
||||
Para ello, ejecuta el script "convertIMGtoVM.py", con el nombre de la imagen "img" como primer parámetro,
|
||||
y la extensión del disco virtual destino (sin punto) como segundo parámetro.
|
||||
y la extensión del disco virtual destino (sin punto) como segundo parámetro.
|
||||
"""
|
||||
journal.send("Running endpoint 'Convertir imagen OpenGnsys a imagen virtual'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
||||
|
@ -2077,7 +2102,7 @@ def convert_image_to_virtual():
|
|||
if result.returncode is None:
|
||||
journal.send("Script 'convertIMGtoVM.py' result OK (ReturnCode: None)", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
journal.send("{'component':'ogRepo', 'severity':'INFO', 'http_code':'200', 'operation':'Run script convertIMGtoVM.py', 'desc':'Result OK (ReturnCode: None)'}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
|
||||
|
||||
# Si el resultado es correcto, llamamos a la función "check_virtual_image_reconversion" en un hilo paralelo
|
||||
# (para que compruebe si la imagen se ha acabado de convertir exitosamente):
|
||||
journal.send("Calling function 'check_virtual_image_reconversion'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
@ -2119,7 +2144,7 @@ def convert_image_to_virtual():
|
|||
@app.route("/ogrepository/v1/images/rename", methods=['PUT'])
|
||||
def rename_image():
|
||||
""" Este endpoint renombra la imagen especificada como primer parámetro (y todos sus archivos asociados), asignando el nombre especificado como segundo parámetro.
|
||||
Para ello, ejecuta el script "renameImage.py", con el nombre original de la imagen como primer parámetro, y el nuevo nombre a asignar como segundo parámetro.
|
||||
Para ello, ejecuta el script "renameImage.py", con el nombre original de la imagen como primer parámetro, y el nuevo nombre a asignar como segundo parámetro.
|
||||
"""
|
||||
journal.send("Running endpoint 'Renombrar una Imagen'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
||||
|
@ -2185,6 +2210,720 @@ 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
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
|
566
api/swagger.yaml
566
api/swagger.yaml
|
@ -4,7 +4,7 @@ info:
|
|||
version: "1.0"
|
||||
description: |
|
||||
---
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
# Esto hace que el Swagger se ordene por los tags (apartados), de la forma especificada:
|
||||
|
@ -18,7 +18,7 @@ tags:
|
|||
- name: "Transferencia entre Repositorios y Backup"
|
||||
- name: "Importar y Exportar Máquinas Virtuales"
|
||||
- name: "Varios"
|
||||
|
||||
- name: "Git"
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------
|
||||
# Apartado "Estado de ogRepository"
|
||||
|
@ -30,7 +30,7 @@ paths:
|
|||
summary: "Obtener Información de Estado de ogRepository"
|
||||
description: >
|
||||
Este endpoint ejecuta el script "**getRepoStatus.py**" y devuelve su salida en formato JSON,
|
||||
incluyendo información sobre la CPU, memoria RAM, disco duro, servicios, y procesos específicos de ogRepository, e instalación de ogGit.
|
||||
incluyendo información sobre la CPU, memoria RAM, disco duro, servicios, y procesos específicos de ogRepository, e instalación de ogGit.
|
||||
tags:
|
||||
- "Estado de ogRepository"
|
||||
responses:
|
||||
|
@ -140,14 +140,14 @@ paths:
|
|||
# -----------------------------------------------------------------------------------------------------------
|
||||
# Apartado "Información de Imágenes"
|
||||
# -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/ogrepository/v1/images:
|
||||
put:
|
||||
summary: "Actualizar Información del Repositorio"
|
||||
description: |
|
||||
Este endpoint actualiza la información de las imágenes almacenadas en el repositorio, reflejándola en los archivos "**repoinfo.json**" y "**trashinfo.json**".
|
||||
Utiliza el script "**updateRepoInfo.py**", que a su vez llama al script "**updateTrashInfo.py**", para actualizar también la información de la papelera.
|
||||
|
||||
|
||||
No hace falta que se le llame al crear o exportar una imagen, ya que lo llama el endpoint "**Crear archivos auxiliares**" (que sí debe ser llamado en esos casos).
|
||||
tags:
|
||||
- "Información de Imágenes"
|
||||
|
@ -192,7 +192,7 @@ paths:
|
|||
get:
|
||||
summary: "Obtener Información de todas las Imágenes"
|
||||
description: |
|
||||
Este endpoint ejecuta el script "**getRepoInfo.py**" con el parámetro "**all**", para devolver información de todas las imágenes almacenadas en el repositorio y en la papelera, que a su vez llama al script "**updateRepoInfo.py**", para actualizar previamente la información del repositorio.
|
||||
Este endpoint ejecuta el script "**getRepoInfo.py**" con el parámetro "**all**", para devolver información de todas las imágenes almacenadas en el repositorio y en la papelera, que a su vez llama al script "**updateRepoInfo.py**", para actualizar previamente la información del repositorio.
|
||||
Devuelve detalles como el nombre de la imagen, tipo, nombre del cliente, clonador, compresor, sistema de archivos, tamaño de los datos, tamaño de la imagen, y hashes MD5.
|
||||
tags:
|
||||
- "Información de Imágenes"
|
||||
|
@ -1257,7 +1257,7 @@ paths:
|
|||
|
||||
# -----------------------------------------------------------------------------------------------------------
|
||||
|
||||
#/ogrepository/v1/p2p:
|
||||
#/ogrepository/v1/p2p:
|
||||
delete:
|
||||
summary: "Cancelar Transmisiones P2P"
|
||||
description: |
|
||||
|
@ -1311,10 +1311,10 @@ paths:
|
|||
Este endpoint importa la imagen especificada desde un repositorio remoto al repositorio local (en el que se ejecuta el endpoint).
|
||||
Utiliza el script "**importImage.py**", que recibe como parámetros el nombre de la imagen, la IP o hostname del servidor remoto, y el usuario con el que conectar al servidor remoto.
|
||||
que a su vez llama al script "**updateRepoInfo.py**", para actualizar la información del repositorio.
|
||||
|
||||
|
||||
**NOTA**: Este endpoint es asíncrono, ya que puede tardar mucho tiempo, por lo que solo informa de que la imagen se está importando, y abre un proceso paralelo, que avisará a ogCore cuando finalice la tarea (llamando a un endpoint de ogCore).
|
||||
tags:
|
||||
- "Transferencia entre Repositorios y Backup"
|
||||
- "Transferencia entre Repositorios y Backup"
|
||||
parameters:
|
||||
- name: JSON
|
||||
in: body
|
||||
|
@ -1436,7 +1436,7 @@ paths:
|
|||
* **ID_img** - Identificador de la imagen, correspondiente al contenido del archivo 'full.sum'
|
||||
* **repo_ip** - Dirección IP del servidor remoto
|
||||
* **user** - Usuario con el que conectar al servidor remoto
|
||||
* **remote_path** - Ruta remota en la que copiar la imagen
|
||||
* **remote_path** - Ruta remota en la que copiar la imagen
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -1457,7 +1457,7 @@ paths:
|
|||
example: "/home/opengnsys"
|
||||
responses:
|
||||
"200":
|
||||
description: "Se está haciendo backup de la imagen."
|
||||
description: "Se está haciendo backup de la imagen."
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -1532,20 +1532,20 @@ paths:
|
|||
post:
|
||||
summary: "Convertir Imagen Virtual a Imagen OpenGnsys"
|
||||
description: |
|
||||
Este endpoint convierte la imagen virtual especificada como primer parámetro en una imagen "img" como las que se generan desde OpenGnsys, debiendo haberse copiado previamente en la ruta "opt/opengnsys/ogrepository/images_virtual".
|
||||
Utiliza el script "**convertVMtoIMG.py**", que recibe como parámetros el nombre de la imagen virtual, y el sistema de archivos de la partición a clonar (en formato "blkid").
|
||||
Se puede comprobar todos los sistemas de archivos aceptados por "blkid" ejecutando el comando "blkid -k".
|
||||
|
||||
Este endpoint convierte la imagen virtual especificada como primer parámetro en una imagen "img" como las que se generan desde OpenGnsys, debiendo haberse copiado previamente en la ruta "opt/opengnsys/ogrepository/images_virtual".
|
||||
Utiliza el script "**convertVMtoIMG.py**", que recibe como parámetros el nombre de la imagen virtual, y el sistema de archivos de la partición a clonar (en formato "blkid").
|
||||
Se puede comprobar todos los sistemas de archivos aceptados por "blkid" ejecutando el comando "blkid -k".
|
||||
|
||||
**NOTA**: Este endpoint es asíncrono, ya que puede tardar mucho tiempo, por lo que solo informa de que la imagen virtual se está convirtiendo, y abre un proceso paralelo, que avisará a ogCore cuando finalice la tarea (llamando a un endpoint de ogCore).
|
||||
tags:
|
||||
- "Importar y Exportar Máquinas Virtuales"
|
||||
- "Importar y Exportar Máquinas Virtuales"
|
||||
parameters:
|
||||
- name: JSON
|
||||
in: body
|
||||
required: true
|
||||
description: |
|
||||
* **virtual_image** - Nombre de la imagen virtual, con extensión
|
||||
* **filesystem** - Sistema de archivos de la partición a clonar, en formato "blkid"
|
||||
* **virtual_image** - Nombre de la imagen virtual, con extensión
|
||||
* **filesystem** - Sistema de archivos de la partición a clonar, en formato "blkid"
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -1640,19 +1640,19 @@ paths:
|
|||
put:
|
||||
summary: "Convertir Imagen OpenGnsys a Imagen Virtual"
|
||||
description: |
|
||||
Este endpoint convierte la imagen "img" especificada como primer parámetro en una imagen virtual con la extensión especificada como segundo parámetro ("vdi", "vmdk", etc), guardándola en la ruta "opt/opengnsys/ogrepository/images_virtual/export".
|
||||
Utiliza el script "**convertIMGtoVM.py**", que recibe como parámetros el nombre de la imagen, y la extensión del disco virtual destino ("vdi", "vmdk", etc).
|
||||
|
||||
Este endpoint convierte la imagen "img" especificada como primer parámetro en una imagen virtual con la extensión especificada como segundo parámetro ("vdi", "vmdk", etc), guardándola en la ruta "opt/opengnsys/ogrepository/images_virtual/export".
|
||||
Utiliza el script "**convertIMGtoVM.py**", que recibe como parámetros el nombre de la imagen, y la extensión del disco virtual destino ("vdi", "vmdk", etc).
|
||||
|
||||
**NOTA**: Este endpoint es asíncrono, ya que puede tardar mucho tiempo, por lo que solo informa de que la imagen se está convirtiendo a virtual, y abre un proceso paralelo, que avisará a ogCore cuando finalice la tarea (llamando a un endpoint de ogCore).
|
||||
tags:
|
||||
- "Importar y Exportar Máquinas Virtuales"
|
||||
- "Importar y Exportar Máquinas Virtuales"
|
||||
parameters:
|
||||
- name: JSON
|
||||
in: body
|
||||
required: true
|
||||
description: |
|
||||
* **ID_img** - Identificador de la imagen, correspondiente al contenido del archivo 'full.sum'
|
||||
* **vm_extension** - Extensión del disco virtual destino ("vdi", "vmdk", etc)
|
||||
* **vm_extension** - Extensión del disco virtual destino ("vdi", "vmdk", etc)
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
|
@ -1883,7 +1883,7 @@ paths:
|
|||
summary: "Renombrar una Imagen"
|
||||
description: |
|
||||
Este endpoint renombra la imagen especificada como primer parámetro (y todos sus archivos asociados), asignando el nombre especificado como segundo parámetro.
|
||||
Utiliza el script "**renameImage.py**", que recibe como parámetros el nombre original y el nuevo nombre a asignar.
|
||||
Utiliza el script "**renameImage.py**", que recibe como parámetros el nombre original y el nuevo nombre a asignar.
|
||||
tags:
|
||||
- "Varios"
|
||||
parameters:
|
||||
|
@ -1960,3 +1960,521 @@ paths:
|
|||
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)"
|
|
@ -134,8 +134,8 @@ def create_torrent(file_path, torrent_file, datafullsum):
|
|||
repo_ip = get_IPlocal()
|
||||
tracker_url = f"http://{repo_ip}:6969/announce"
|
||||
|
||||
# Creamos una lista con el comando para crear el torrrent, y lo imprimimos con espacios:
|
||||
splitted_cmd = f"nice -n 0 ctorrent -t {file_path} -u {tracker_url} -s {torrent_file} -c {datafullsum} -l 4194304".split()
|
||||
# Creamos una litas para ejecutar el comando mktorrent para crear el archivo torrent
|
||||
splitted_cmd = f"nice -n 0 mktorrent -a {tracker_url} -c {datafullsum} -o {torrent_file} {file_path}".split()
|
||||
print(f"Sending command: {' '.join(splitted_cmd)}")
|
||||
|
||||
# Ejecutamos el comando en el sistema, e imprimimos el resultado:
|
||||
|
|
|
@ -106,11 +106,11 @@ def main():
|
|||
total_disk, used_disk, free_disk, percent_disk = get_disk_info()
|
||||
|
||||
# Obtenemos el estado de los servicios listados, que almacenamos en un diccionario:
|
||||
service_list = ['ssh', 'smbd', 'rsync']
|
||||
service_list = ['ssh', 'smbd', 'opentracker']
|
||||
services_status = {service: get_service_status(service) for service in service_list}
|
||||
|
||||
# Obtenemos el estado de los procesos listados, que almacenamos en un diccionario:
|
||||
process_list = ['udp-sender', 'uftp', 'bttrack', 'btlaunchmany.bittornado']
|
||||
process_list = ['udp-sender', 'uftp', 'aria2c']
|
||||
process_status = {process: get_process_status(process) for process in process_list}
|
||||
|
||||
# Creamos un diccionario con toda la información obtenida:
|
||||
|
|
|
@ -16,6 +16,8 @@ No recibe ningún parámetro.
|
|||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import psutil
|
||||
import re
|
||||
from systemd import journal
|
||||
|
||||
|
||||
|
@ -31,29 +33,73 @@ repo_path = '/opt/opengnsys/ogrepository/images' # En este caso, no lleva barra
|
|||
# --------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
def run_bittornado(repo_path):
|
||||
""" Ejecuta el comando "btlaunchmany.bittornado", con sus parámetros correspondientes.
|
||||
Además, captura el resultado y los posibles errores, y los imprime.
|
||||
"""
|
||||
# Creamos una lista con el comando "btlaunchmany.bittornado" y sus parámetros, y lo imprimimos con espacios:
|
||||
splitted_cmd = f"btlaunchmany.bittornado {repo_path}".split()
|
||||
print(f"Sending command: {' '.join(splitted_cmd)}")
|
||||
journal.send(f"runTorrentSeeder.py: Running command: {' '.join(splitted_cmd)}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
||||
# Ejecutamos el comando "btlaunchmany.bittornado" en el sistema, e imprimimos el resultado:
|
||||
# def run_bittornado(repo_path):
|
||||
# """ Ejecuta el comando "btlaunchmany.bittornado", con sus parámetros correspondientes.
|
||||
# Además, captura el resultado y los posibles errores, y los imprime.
|
||||
# """
|
||||
# # Creamos una lista con el comando "btlaunchmany.bittornado" y sus parámetros, y lo imprimimos con espacios:
|
||||
# splitted_cmd = f"btlaunchmany.bittornado {repo_path}".split()
|
||||
# print(f"Sending command: {' '.join(splitted_cmd)}")
|
||||
# journal.send(f"runTorrentSeeder.py: Running command: {' '.join(splitted_cmd)}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
||||
# # Ejecutamos el comando "btlaunchmany.bittornado" en el sistema, e imprimimos el resultado:
|
||||
# try:
|
||||
# result = subprocess.run(splitted_cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
# journal.send(f"runTorrentSeeder.py: Command ReturnCode: {result.returncode}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
# print(f"Bittornado ReturnCode: {result.returncode}")
|
||||
# except subprocess.CalledProcessError as error:
|
||||
# journal.send("runTorrentSeeder.py: Process finalized", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
# print(f"Bittornado ReturnCode: {error.returncode}")
|
||||
# print(f"Bittornado Error Output: {error.stderr.decode()}")
|
||||
# except Exception as error:
|
||||
# journal.send(f"runTorrentSeeder.py: Command exception: {error}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
# print(f"Unexpected bittornado error: {error}")
|
||||
|
||||
|
||||
|
||||
def run_aria2c_seeder(image_name):
|
||||
"""Lanza aria2c como seeder puro para una imagen concreta ya existente."""
|
||||
|
||||
repo_path = '/opt/opengnsys/ogrepository/images'
|
||||
torrent_file = os.path.join(repo_path, f"{image_name}.img.torrent")
|
||||
image_file = os.path.join(repo_path, f"{image_name}.img")
|
||||
|
||||
# Verificación básica
|
||||
if not os.path.exists(torrent_file):
|
||||
print(f"Torrent file not found: {torrent_file}")
|
||||
journal.send(f"Seeder error: Torrent file not found: {torrent_file}",
|
||||
PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
return
|
||||
|
||||
if not os.path.exists(image_file):
|
||||
print(f"Image file not found: {image_file}")
|
||||
journal.send(f"Seeder error: Image file not found: {image_file}",
|
||||
PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
return
|
||||
|
||||
# Comando aria2c como seeder puro
|
||||
cmd = [
|
||||
'aria2c',
|
||||
'--enable-peer-exchange=true',
|
||||
'--bt-seed-unverified=true',
|
||||
'--check-integrity=true',
|
||||
'--seed-ratio=0.0',
|
||||
'--dir=' + repo_path,
|
||||
torrent_file
|
||||
]
|
||||
|
||||
journal.send(f"Launching aria2c seeder for {image_name}",
|
||||
PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
journal.send(f"Command: {' '.join(cmd)}",
|
||||
PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
print("Running command:", ' '.join(cmd))
|
||||
try:
|
||||
result = subprocess.run(splitted_cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
journal.send(f"runTorrentSeeder.py: Command ReturnCode: {result.returncode}", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
print(f"Bittornado ReturnCode: {result.returncode}")
|
||||
except subprocess.CalledProcessError as error:
|
||||
journal.send("runTorrentSeeder.py: Process finalized", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
print(f"Bittornado ReturnCode: {error.returncode}")
|
||||
print(f"Bittornado Error Output: {error.stderr.decode()}")
|
||||
except Exception as error:
|
||||
journal.send(f"runTorrentSeeder.py: Command exception: {error}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
print(f"Unexpected bittornado error: {error}")
|
||||
|
||||
|
||||
subprocess.run(cmd, check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
journal.send(f"aria2c seeder failed: {e}",
|
||||
PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api")
|
||||
print(f"Seeder process exited with code {e.returncode}")
|
||||
|
||||
# --------------------------------------------------------------------------------------------
|
||||
# MAIN
|
||||
|
@ -64,16 +110,40 @@ def main():
|
|||
"""
|
||||
"""
|
||||
# Finalizamos el proceso "btlaunchmany.bittornado" (en caso de que estuviera corriendo):
|
||||
try:
|
||||
journal.send("runTorrentSeeder.py: Killing process 'btlaunchmany.bittornado'...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
subprocess.run(f"pkill btlaunchmany".split(), check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
except Exception as error_description:
|
||||
journal.send("runTorrentSeeder.py: No 'btlaunchmany.bittornado' process running", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
print(f"No btlaunchmany.bittornado process running? Returned error: {error_description}")
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: runTorrentSeeder.py <image_name>")
|
||||
journal.send("runTorrentSeeder.py: Invalid number of arguments. Expected 1 argument: <image_name>",
|
||||
PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
sys.exit(1)
|
||||
|
||||
image_name = sys.argv[1]
|
||||
torrent_file = os.path.join(repo_path, f"{image_name}.img.torrent")
|
||||
found = False
|
||||
# Matamos los procesos de aria2c que sirvan la imagen en concreto. Chequeamos todos los procesos
|
||||
|
||||
# Ejecutamos el comando "btlaunchmany.bittornado" (para hacer seed de los torrents):
|
||||
run_bittornado(repo_path)
|
||||
journal.send(f"runTorrentSeeder.py: looking for aria2c processes for {image_name}.torrent",
|
||||
PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
for proc in psutil.process_iter(['pid','name','cmdline']):
|
||||
try:
|
||||
if proc.info['name'] != 'aria2c':
|
||||
continue
|
||||
|
||||
if any(arg.endswith(torrent_file) for arg in proc.info['cmdline']):
|
||||
proc.terminate()
|
||||
found = True
|
||||
print(f"Killed aria2c process with PID {proc.info['pid']} for {image_name}.torrent")
|
||||
journal.send(f"runTorrentSeeder.py: Killed aria2c process with PID {proc.info['pid']} for {image_name}.torrent",
|
||||
PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
continue
|
||||
|
||||
if not found:
|
||||
print(f"No aria2c process found for {image_name}.torrent")
|
||||
journal.send(f"runTorrentSeeder.py: No aria2c process found for {image_name}.torrent",
|
||||
PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
|
||||
|
||||
# Lanzamos aria2c como seeder para la imagen proporcionada
|
||||
run_aria2c_seeder(image_name)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
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
|
||||
|
||||
* First debian version
|
||||
|
|
|
@ -8,7 +8,7 @@ Build-Depends: debhelper-compat (= 12)
|
|||
Package: ogrepository
|
||||
Architecture: all
|
||||
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
|
||||
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
|
||||
Description: Ogrepsoitory Package
|
||||
This package provides Ogrepository service.
|
||||
X-OG-Release: opengnsys-1.6.0-beta, opengnsys-1.6.1-beta
|
||||
|
||||
|
|
|
@ -1,10 +1,29 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -x
|
||||
set -x
|
||||
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
restore_config_if_modified() {
|
||||
local new="$1"
|
||||
local backup="$1.bak.upgrade_package"
|
||||
|
||||
if [ -f "$backup" ]; then
|
||||
if ! cmp -s "$new" "$backup"; then
|
||||
echo ">>> Archivo modificado por el usuario detectado en $new"
|
||||
echo " - Guardando archivo nuevo como ${new}.new"
|
||||
mv -f "$new" "${new}.new"
|
||||
echo " - Restaurando archivo anterior desde backup"
|
||||
mv -f "$backup" "$new"
|
||||
else
|
||||
echo ">>> El archivo $new no ha cambiado desde la última versión, eliminando backup"
|
||||
rm -f "$backup"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Cargar variables de configuración
|
||||
db_get opengnsys/ogrepository_ogrepoIp
|
||||
OGREPO_IP="$RET"
|
||||
|
@ -19,10 +38,20 @@ SAMBA_PASS="$RET"
|
|||
USER="opengnsys"
|
||||
|
||||
|
||||
# Provisionar base de datos si es necesario en caso de instalación.
|
||||
# Provisionar base de datos si es necesario en caso de instalación.
|
||||
|
||||
|
||||
# Detectar si es una instalación nueva o una actualización
|
||||
# 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
|
||||
# "
|
||||
if [ "$1" = "configure" ] && [ -z "$2" ]; then
|
||||
systemd-run --no-block /bin/bash -c "
|
||||
sleep 10;
|
||||
|
@ -33,7 +62,7 @@ for pkg in bittorrent bittornado ctorrent; do
|
|||
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/samba/ogrepo-smb.conf
|
||||
|
||||
|
@ -49,7 +78,7 @@ done
|
|||
chmod 700 $OPENGNSYS_HOME/.ssh
|
||||
chmod 600 $OPENGNSYS_HOME/.ssh/id_ed25519
|
||||
chmod 644 $OPENGNSYS_HOME/.ssh/id_ed25519.pub
|
||||
# Genera authorized_keys
|
||||
# Genera authorized_keys
|
||||
cat $OPENGNSYS_HOME/.ssh/id_ed25519.pub >> $OPENGNSYS_HOME/.ssh/authorized_keys
|
||||
chmod 600 $OPENGNSYS_HOME/.ssh/authorized_keys
|
||||
chown -R opengnsys:opengnsys $OPENGNSYS_HOME/.ssh
|
||||
|
@ -62,7 +91,7 @@ done
|
|||
fi
|
||||
(echo "$SAMBA_PASS"; echo "$SAMBA_PASS") | smbpasswd -a $SAMBA_USER
|
||||
fi
|
||||
|
||||
systemctl enable ogrepo-api
|
||||
# Configure Repo
|
||||
|
||||
cp /opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg.tmpl /opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg
|
||||
|
@ -70,11 +99,11 @@ done
|
|||
sed -i "s/OGCOREIP/$OGCORE_IP/g" /opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg
|
||||
|
||||
# Copiar sudoers file ogrepository/etc/opengnsys-repository
|
||||
cp /opt/opengnsys/ogrepository/etc/opengnsys-repository /etc/sudoers.d/opengnsys
|
||||
cp /opt/opengnsys/ogrepository/etc/opengnsys-repository /etc/sudoers.d/opengnsys
|
||||
elif [ "$1" = "configure" ] && [ -n "$2" ]; then
|
||||
echo "Actualización desde la versión $2"
|
||||
# Recopy static files without configuration
|
||||
cp /opt/opengnsys/ogrepository/etc/opengnsys-repository /etc/sudoers.d/opengnsys-repository
|
||||
# Recopy static files without configuration
|
||||
cp /opt/opengnsys/ogrepository/etc/opengnsys-repository /etc/sudoers.d/opengnsys-repository
|
||||
OPENGNSYS_HOME=$(getent passwd opengnsys | cut -d: -f6)
|
||||
# Create .ssh directory
|
||||
mkdir -p $OPENGNSYS_HOME/.ssh
|
||||
|
@ -83,13 +112,23 @@ elif [ "$1" = "configure" ] && [ -n "$2" ]; then
|
|||
cp /opt/opengnsys/ogrepository/etc/opengnsys.pub $OPENGNSYS_HOME/.ssh/id_ed25519.pub
|
||||
cat $OPENGNSYS_HOME/.ssh/id_ed25519.pub >> $OPENGNSYS_HOME/.ssh/authorized_keys
|
||||
|
||||
restore_config_if_modified "/opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg"
|
||||
restore_config_if_modified "/opt/opengnsys/ogrepository/etc/repoinfo.json"
|
||||
restore_config_if_modified "/opt/opengnsys/ogrepository/etc/trashinfo.json"
|
||||
restore_config_if_modified "/etc/samba/smb.conf"
|
||||
restore_config_if_modified "/etc/samba/ogrepo-smb.conf"
|
||||
restore_config_if_modified "/etc/sudoers.d/opengnsys-repository"
|
||||
|
||||
|
||||
fi
|
||||
|
||||
# Cambiar la propiedad de los archivos al usuario especificado
|
||||
chown opengnsys:www-data /opt/opengnsys/
|
||||
chown -R opengnsys:www-data /opt/opengnsys/ogrepository
|
||||
chmod 755 /opt/opengnsys
|
||||
chmod 755 /opt/opengnsys/ogrepository/bin/*
|
||||
|
||||
|
||||
# Install http server stuff
|
||||
# Reiniciar servicios si es necesario
|
||||
# systemctl restart nombre_del_servicio
|
||||
|
|
|
@ -2,8 +2,18 @@
|
|||
|
||||
set -e
|
||||
|
||||
KEY_FILE="/usr/share/keyrings/debian-archive-buster-stable.gpg"
|
||||
REPO_FILE="/etc/apt/sources.list.d/buster.list"
|
||||
backup_file_if_exists() {
|
||||
local original="$1"
|
||||
local backup="$1.bak.upgrade_package"
|
||||
|
||||
if [ -e "$original" ]; then
|
||||
echo " - Guardando backup de $original en $backup"
|
||||
cp -a "$original" "$backup"
|
||||
fi
|
||||
}
|
||||
|
||||
# KEY_FILE="/usr/share/keyrings/debian-archive-buster-stable.gpg"
|
||||
# REPO_FILE="/etc/apt/sources.list.d/buster.list"
|
||||
|
||||
# Asegurarse de que el usuario exista
|
||||
USER="opengnsys"
|
||||
|
@ -20,10 +30,17 @@ echo "Añadiendo el repositorio de Debian Buster en $REPO_FILE..."
|
|||
mkdir -p "$(dirname "$REPO_FILE")"
|
||||
|
||||
# Crear el archivo de repositorio si no existe
|
||||
if [ ! -f "$REPO_FILE" ]; then
|
||||
echo "deb [signed-by=$KEY_FILE] http://ftp.de.debian.org/debian buster main" > "$REPO_FILE"
|
||||
else
|
||||
echo "El repositorio ya está configurado en $REPO_FILE"
|
||||
fi
|
||||
# if [ ! -f "$REPO_FILE" ]; then
|
||||
# echo "deb [signed-by=$KEY_FILE] http://ftp.de.debian.org/debian buster main" > "$REPO_FILE"
|
||||
# else
|
||||
# echo "El repositorio ya está configurado en $REPO_FILE"
|
||||
# fi
|
||||
|
||||
backup_file_if_exists "/opt/opengnsys/ogrepository/etc/ogAdmRepo.cfg"
|
||||
backup_file_if_exists "/opt/opengnsys/ogrepository/etc/repoinfo.json"
|
||||
backup_file_if_exists "/opt/opengnsys/ogrepository/etc/trashinfo.json"
|
||||
backup_file_if_exists "/etc/samba/smb.conf"
|
||||
backup_file_if_exists "/etc/samba/ogrepo-smb.conf"
|
||||
backup_file_if_exists "/etc/sudoers.d/ogrepository"
|
||||
|
||||
exit 0
|
||||
|
|
|
@ -25,5 +25,7 @@ Cmnd_Alias KILL_BT = \
|
|||
/usr/bin/pkill -9 bttrack, \
|
||||
/usr/bin/kill -9 *
|
||||
|
||||
Cmnd_Alias PYTHON_OGREPO = /usr/bin/python3 /opt/opengnsys/ogrepository/bin/*
|
||||
|
||||
# Permitir al usuario opengnsys ejecutar estos comandos sin contraseña
|
||||
opengnsys ALL=(root) NOPASSWD: MOUNT_RECOVERY, CHROOT_GRUB, LOOP_KPARTX, KILL_BT
|
||||
opengnsys ALL=(root) NOPASSWD: MOUNT_RECOVERY, CHROOT_GRUB, LOOP_KPARTX, KILL_BT, PYTHON_OGREPO
|
||||
|
|
Loading…
Reference in New Issue