Compare commits

..

No commits in common. "main" and "ticket-2610" have entirely different histories.

8 changed files with 242 additions and 551 deletions

View File

@ -1,50 +1,17 @@
# Changelog # Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.10.4] - 2025-09-30
### Fixed
- Set safe.directory just once
## [0.10.3] - 2025-09-18
### Changed
- Create tags via a query to the forgejo API
## [0.10.2] - 2025-09-01
### Fixed
- Corregida la logica en el endpoint create torrent sum
- Mejoras en los mensajes de logs
- Mejoras en la validación de los archivos info e info.checked
## [0.10.1] - 2025-08-25
### Fixed
- Import images problems when there is not info.checked file (#2723, #2726)
- Improves logging (#2727)
## [0.10.0] - 2025-07-07 ## [0.10.0] - 2025-07-07
### Added ### Added
- OgGit functionality (#2371, #2363, #2363, #2317) - OgGit functionality (#2371, #2363, #2363, #2317)
### Removed ### Removed
- Removed unused BitTorrent-related packages and logic
- Removed unused BitTorrent-related packages and logic
## [0.9.0] - 2025-06-25 ## [0.9.0] - 2025-06-25
### Added ## Added
- Changed old tools for tools non dependant of Pyhton2 in repo - Changed old tools for tools non dependant of Pyhton2 in repo
- mktorrent to handle creation of torrent files - mktorrent to handle creation of torrent files

View File

@ -99,22 +99,15 @@ pipeline {
} }
} }
post { post {
success {
script {
// Solo lanzar cuando el build sea exitoso y en la rama main
if (env.BRANCH_NAME == 'main') {
build job: 'Aptly publish nightly repository',
wait: false,
parameters: [
string(name: 'TRIGGERED_BY', value: "${env.JOB_NAME}-${env.BUILD_NUMBER}")
]
}
}
}
always { always {
notifyBuildStatus('opengnsys@qindel.com') notifyBuildStatus('narenas@qindel.com')
} }
} }
} }
// stage ('Publish to Debian Repository') {
// agent { label 'debian-repo' }
// steps {
// sh "aptly repo add opengnsys-devel /var/tmp/opengnsys/debian-repo/*.deb"
// }
// }

File diff suppressed because it is too large Load Diff

View File

@ -2087,203 +2087,6 @@ paths:
error: error:
type: string type: string
example: "Parameters missing" example: "Parameters missing"
/ogrepository/v1/git/repositories/{repository}:
delete:
summary: "Eliminar repositorio"
description: |
Elimina un repositorio de Git
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
responses:
"200":
description: "Repositorio eliminado"
schema:
type: object
properties:
status:
type: string
example: deleted
"404":
description: "Repositorio no encontrado"
schema:
type: object
properties:
status:
type: string
example: not found
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
/ogrepository/v1/git/repositories/{repository}/sync:
post:
summary: "Sincronizar con repositorio remoto"
description: |
Sincroniza un repositorio de Git con uno remoto.
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
- name: JSON
in: body
required: true
description: |
* **remote_repository** - Reposition remoto al que hacer push
responses:
"200":
description: "Repositorio en proceso de sincronización"
schema:
type: object
properties:
success:
type: boolean
example: True
output:
type: string
example: "Synchronizing..."
job_id:
type: string
example: "GitSync_02345"
"404":
description: "Repositorio no encontrado"
schema:
type: object
properties:
status:
type: string
example: not found
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
/ogrepository/v1/git/repositories/{repository}/backup:
post:
summary: "Sincronizar con repositorio remoto"
description: |
Sincroniza un repositorio de Git con uno remoto.
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
- name: JSON
in: body
required: true
description: |
* **ssh_server** - Servidor SSH al que enviar el backup
* **ssh_port** - Puerto del servidor SSH al que enviar el backup
* **ssh_user** - Usuario del servidor SSH al que enviar el backup
* **filename** - Nombre de archivo del backup
responses:
"200":
description: "Repositorio en proceso de sincronización"
schema:
type: object
properties:
success:
type: boolean
example: True
output:
type: string
example: "Backing up..."
job_id:
type: string
example: "GitBackup_02345"
"404":
description: "Repositorio no encontrado"
schema:
type: object
properties:
status:
type: string
example: not found
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
/ogrepository/v1/git/repositories/{repository}/compact:
post:
summary: "Compactar repositorio"
description: |
Compacta un repositorio de Git para optimizar el rendimiento y liberar espacio
tags:
- "Git"
parameters:
- name: repository
in: path
required: true
type: string
description: "Nombre de repositorio"
responses:
"200":
description: "Repositorio en proceso de compactación"
schema:
type: object
properties:
success:
type: boolean
example: True
output:
type: string
example: "Compacting..."
job_id:
type: string
example: "GitGC_02345"
"404":
description: "Repositorio no encontrado"
schema:
type: object
properties:
status:
type: string
example: not found
"500":
description: "Excepción"
schema:
type: object
properties:
success:
type: boolean
example: false
exception:
type: string
example: "(Exception description)"
/ogrepository/v1/git/repositories/{repository}/tags: /ogrepository/v1/git/repositories/{repository}/tags:
get: get:
summary: "Obtener lista de tags" summary: "Obtener lista de tags"

View File

@ -184,16 +184,11 @@ def main():
# Obtenemos la ruta completa de la imagen: # Obtenemos la ruta completa de la imagen:
file_path = build_file_path() file_path = build_file_path()
# Si no existe el archivo de imagen o el .info, imprimimos un mensaje de error y salimos del script: # Si no existe el archivo de imagen, imprimimos un mensaje de error y salimos del script:
if not os.path.exists(file_path) or not (os.path.exists(f"{file_path}.info.checked") or os.path.exists(f"{file_path}.info")): if not os.path.exists(file_path):
if not os.path.exists(file_path): journal.send("createTorrentSum.py: Image not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
journal.send(f"createTorrentSum.py: Image file '{file_path}' not found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG") print("Image file doesn't exist")
print(f"Image file '{file_path}' doesn't exist")
if not os.path.exists(f"{file_path}.info.checked") and not os.path.exists(f"{file_path}.info"):
journal.send(f"createTorrentSum.py: Neither '{file_path}.info.checked' nor '{file_path}.info' found", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
print(f"Neither info file '{file_path}.info.checked' nor '{file_path}.info' exists")
sys.exit(2) sys.exit(2)
# Si la imagen está bloqueada, imprimimos un mensaje de error y salimos del script: # Si la imagen está bloqueada, imprimimos un mensaje de error y salimos del script:
if os.path.exists(f"{file_path}.lock"): if os.path.exists(f"{file_path}.lock"):
@ -262,8 +257,7 @@ def main():
# Actualizamos la información del repositorio, ejecutando el script "updateRepoInfo.py": # Actualizamos la información del repositorio, ejecutando el script "updateRepoInfo.py":
journal.send("createTorrentSum.py: Updating repository info...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG") journal.send("createTorrentSum.py: Updating repository info...", PRIORITY=journal.LOG_INFO, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
print("Updating Repository Info...") print("Updating Repository Info...")
if os.path.exists(f"{file_path}.info"): update_repo_info()
update_repo_info()

View File

@ -67,50 +67,33 @@ def check_files():
continue continue
# Comprobamos si existe un archivo ".info" asociado a la imagen actual: # Comprobamos si existe un archivo ".info" asociado a la imagen actual:
info_file = f"{img_path}.info" info_file = f"{img_path}.info"
try: if os.path.exists(info_file):
if os.path.exists(info_file): # Si la fecha de modificación del archivo ".info" es anterior a la de la imagen, lo eliminamos (porque estará desactualizado):
# Si la fecha de modificación del archivo ".info" es anterior a la de la imagen, lo eliminamos (porque estará desactualizado): if os.path.getmtime(info_file) < os.path.getmtime(img_path):
if os.path.getmtime(info_file) < os.path.getmtime(img_path): os.remove(info_file)
os.remove(info_file) print(f"Warning: Deleted outdated file {info_file}")
print(f"Warning: Deleted outdated file {info_file}")
# En caso contrario, almacenamos el contenido del archivo ".info" (del tipo "PARTCLONE:LZOP:EXTFS:8500000:Ubuntu_20") en la variable "data": # En caso contrario, almacenamos el contenido del archivo ".info" (del tipo "PARTCLONE:LZOP:EXTFS:8500000:Ubuntu_20") en la variable "data":
else: else:
with open(info_file, 'r') as file: with open(info_file, 'r') as file:
info_data = file.read() info_data = file.read()
# Almacenamos el contenido de los archivos ".size", ".sum" y ".full.sum": # Almacenamos el contenido de los archivos ".size", ".sum" y ".full.sum":
with open(f"{img_path}.size", 'r') as file: with open(f"{img_path}.size", 'r') as file:
size = file.read().strip('\n') size = file.read().strip('\n')
with open(f"{img_path}.sum", 'r') as file: with open(f"{img_path}.sum", 'r') as file:
sum = file.read().strip('\n') _sum = file.read().strip('\n')
with open(f"{img_path}.full.sum", 'r') as file: with open(f"{img_path}.full.sum", 'r') as file:
fullsum = file.read().strip('\n') fullsum = file.read().strip('\n')
# Llamamos a la función "add_to_json", para que inserte la información de la imagen en el archivo json
# (pasándole el nombre de la imagen, la extensión, y los datos extraídos del archivo ".info"):
img_name = os.path.relpath(img_path, repo_path)
add_to_json(os.path.splitext(img_name)[0], os.path.splitext(img_name)[1][1:], info_data, size, _sum, fullsum)
# Renombramos el archivo ".info" a ".info.checked", para que ya no se añada la información que contiene # Renombramos el archivo ".info" a ".info.checked", para que ya no se añada la información que contiene
# (originalmente se eliminaba el archivo, pero creo que es mejor mantenerlo): # (originalmente se eliminaba el archivo, pero creo que es mejor mantenerlo):
os.rename(info_file, f"{info_file}.checked") os.rename(info_file, f"{info_file}.checked")
# Llamamos a la función "add_to_json", para que inserte la información de la imagen en el archivo json
# (pasándole el nombre de la imagen, la extensión, y los datos extraídos del archivo ".info"):
img_name = os.path.relpath(img_path, repo_path)
add_to_json(os.path.splitext(img_name)[0], os.path.splitext(img_name)[1][1:], info_data, size, sum, fullsum)
except (IOError, OSError, PermissionError) as e:
# Si hay algún error leyendo los archivos, registramos el error y continuamos con la siguiente imagen def add_to_json(image_name, image_type, data, size, _sum, fullsum):
journal.send(f"updateRepoInfo.py: Error processing files for {img_path}: {str(e)}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
print(f"Warning: Could not process files for {item}: {str(e)}")
continue
except ValueError as e:
# Si hay algún error con el formato de los datos en los archivos
journal.send(f"updateRepoInfo.py: Data format error for {img_path}: {str(e)}", PRIORITY=journal.LOG_WARNING, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
print(f"Warning: Data format error for {item}: {str(e)}")
continue
except Exception as e:
# Para cualquier otra excepción inesperada
journal.send(f"updateRepoInfo.py: Unexpected error processing {img_path}: {str(e)}", PRIORITY=journal.LOG_ERR, SYSLOG_IDENTIFIER="ogrepo-api_DEBUG")
print(f"Error: Unexpected error processing {item}: {str(e)}")
continue
def add_to_json(image_name, image_type, data, size, sum, fullsum):
""" Esta función añade al archivo "repoinfo.json" la información de las imágenes que aun no ha sido introducida en él (imágenes nuevas, básicamente). """ Esta función añade al archivo "repoinfo.json" la información de las imágenes que aun no ha sido introducida en él (imágenes nuevas, básicamente).
""" """
# Almacenamos el contenido de la variable "data" (del tipo "PARTCLONE:LZOP:EXTFS:8500000:Ubuntu_20") en variables separadas: # Almacenamos el contenido de la variable "data" (del tipo "PARTCLONE:LZOP:EXTFS:8500000:Ubuntu_20") en variables separadas:
@ -126,7 +109,7 @@ def add_to_json(image_name, image_type, data, size, sum, fullsum):
"filesystem": fstype.upper(), "filesystem": fstype.upper(),
"datasize": int(datasize) * 1024, # Convertimos el valor a bytes (desde KB) "datasize": int(datasize) * 1024, # Convertimos el valor a bytes (desde KB)
"size": int(size), "size": int(size),
"sum": sum, "sum": _sum,
"fullsum": fullsum "fullsum": fullsum
} }
# Almacenamos el contenido del archivo "repoinfo.json" en la variable "info_data" # Almacenamos el contenido del archivo "repoinfo.json" en la variable "info_data"

View File

@ -42,6 +42,7 @@ USER="opengnsys"
if [ "$1" = "configure" ] && [ -z "$2" ]; then if [ "$1" = "configure" ] && [ -z "$2" ]; then
sed -i "s/%%OGREPOSITORY_USER%%/$SAMBA_USER/g" /etc/systemd/system/ogrepo-api.service sed -i "s/%%OGREPOSITORY_USER%%/$SAMBA_USER/g" /etc/systemd/system/ogrepo-api.service
sed -i "s/%%OGREPOSITORY_USER%%/$SAMBA_USER/g" /etc/samba/ogrepo-smb.conf sed -i "s/%%OGREPOSITORY_USER%%/$SAMBA_USER/g" /etc/samba/ogrepo-smb.conf
@ -128,8 +129,5 @@ systemctl daemon-reload
systemctl enable ogrepo-api systemctl enable ogrepo-api
systemctl restart ogrepo-api systemctl restart ogrepo-api
systemctl restart smbd systemctl restart smbd
systemctl enable --now opentracker || true
systemctl restart opentracker || true
exit 0 exit 0

View File

@ -10,25 +10,6 @@ Cmnd_Alias MOUNT_RECOVERY = \
/usr/bin/umount /mnt/recovery/sys, \ /usr/bin/umount /mnt/recovery/sys, \
/usr/bin/umount -l /mnt/recovery /usr/bin/umount -l /mnt/recovery
Cmnd_Alias OGBOOT = \
/opt/bin/oglivecli, \
/usr/bin/chmod, \
/usr/bin/chown, \
/usr/bin/md5sum, \
/usr/bin/smbpasswd, \
/usr/bin/cat, \
/usr/bin/tee, \
/usr/bin/sed, \
/usr/bin/gzip, \
/usr/bin/lz4, \
/usr/bin/cpio, \
/usr/bin/find, \
/bin/tee, \
/usr/bin/dd, \
/usr/bin/mkfs.ext4, \
/usr/bin/rsync, \
/opt/opengnsys/ogboot/lib/*.iso /mnt
Cmnd_Alias CHROOT_GRUB = \ Cmnd_Alias CHROOT_GRUB = \
/usr/sbin/chroot /mnt/recovery /usr/sbin/grub-install --target=i386-pc *, \ /usr/sbin/chroot /mnt/recovery /usr/sbin/grub-install --target=i386-pc *, \
/usr/sbin/chroot /mnt/recovery /usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg /usr/sbin/chroot /mnt/recovery /usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg
@ -47,4 +28,4 @@ Cmnd_Alias KILL_BT = \
Cmnd_Alias PYTHON_OGREPO = /usr/bin/python3 /opt/opengnsys/ogrepository/bin/* Cmnd_Alias PYTHON_OGREPO = /usr/bin/python3 /opt/opengnsys/ogrepository/bin/*
# Permitir al usuario opengnsys ejecutar estos comandos sin contraseña # Permitir al usuario opengnsys ejecutar estos comandos sin contraseña
opengnsys ALL=(root) NOPASSWD: MOUNT_RECOVERY, CHROOT_GRUB, LOOP_KPARTX, OGBOOT, KILL_BT, PYTHON_OGREPO opengnsys ALL=(root) NOPASSWD: MOUNT_RECOVERY, CHROOT_GRUB, LOOP_KPARTX, KILL_BT, PYTHON_OGREPO