Skip to content

Commit c94ae49

Browse files
abkrimclaude
andcommitted
Add GitHub Actions CI and update project metadata
- Add test workflow: matrix Python 3.11/3.12/3.13 on push and PR - Bump version to 0.2.0 (sync pyproject.toml with __init__.py) - Update Python requirement from >=3.9 to >=3.11 - Document lessons learned: manageBackupJob API, -D param format, disabled field - Add JetBackup5 API quick reference table Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 98eeaa1 commit c94ae49

3 files changed

Lines changed: 70 additions & 5 deletions

File tree

.github/workflows/tests.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: ["3.11", "3.12", "3.13"]
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Set up Python ${{ matrix.python-version }}
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: ${{ matrix.python-version }}
23+
24+
- name: Run tests
25+
run: PYTHONPATH=src python -m unittest discover -s tests -v

CLAUDE.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ server/
5050
git push
5151
# 2. Pull en raspxer
5252
ssh raspxer 'cd /opt/jetbackup-remote && git pull origin main'
53-
# 3. Si cambió el SSH gate, desplegar a los 4 servidores
53+
# 3. Si cambió el SSH gate, desplegar a los 4 servidores:
54+
# - servidor02, servidor20, servidor30: root directo (sed o scp)
55+
# - central: root por puerto 51514 (centralxer conecta como secxer sin sudo)
5456
# 4. Si cambió el systemd service:
5557
ssh raspxer 'cp /opt/jetbackup-remote/systemd/jetbackup-remote.service /etc/systemd/system/ && systemctl daemon-reload'
5658
```
@@ -86,3 +88,42 @@ PYTHONPATH=src python3 -m unittest discover -s tests
8688
**Causa raíz:** El código buscaba `group["job_id"]` pero JetBackup5 almacena la referencia al job en `group["data"]["_id"]`
8789
**Solución:** Cambiar a `group.get("data", {}).get("_id")` para el matching
8890
**Regla derivada:** Las fixtures de test DEBEN reflejar la estructura real de la API. Usar respuestas capturadas de producción como base para fixtures.
91+
92+
### 2026-02-25 — editBackupJob no existe, usar manageBackupJob
93+
94+
**Contexto:** jetbackup_api.py — `set_job_enabled`
95+
**Problema:** Jobs con `disabled=1` nunca arrancaban. El orquestador enviaba `editBackupJob -D "enabled=1"` (luego corregido a `disabled=0`), JetBackup devolvía rc=0 pero el campo `disabled` no cambiaba. El job se triggeaba con `runBackupJobManually` pero nunca pasaba a `running=true`, causando startup timeout de 120s.
96+
**Causa raíz:** `editBackupJob` no existe en la API de JetBackup5. La API la acepta silenciosamente (rc=0, 267 bytes) sin hacer nada. La función correcta es **`manageBackupJob`** con `action=modify`.
97+
**Evidencia:** servidor20 funcionaba por casualidad (sus jobs ya tenían `disabled=0`). servidor30 fallaba (jobs con `disabled=1`). El `runBackupJobManually` devolvía 219 bytes (error silencioso) vs 3098 bytes cuando el job realmente arranca.
98+
**Solución:** Cambiar a `manageBackupJob` con params `_id`, `action=modify`, `disabled=0/1`
99+
**Regla derivada:** Listar funciones disponibles con `jetbackup5api -F ""` antes de asumir nombres. El patrón de la API es `manage*` para modificar estado (no `edit*`).
100+
101+
### 2026-02-25 — Formato de parámetros -D en jetbackup5api
102+
103+
**Contexto:** jetbackup_api.py — `_api_call`, `_api_call_no_json`
104+
**Problema:** Múltiples flags `-D "key=value"` funcionaban para algunas funciones pero no para `manageBackupJob` (ignoraba `action=modify` silenciosamente).
105+
**Causa raíz:** El formato documentado de JetBackup5 es un solo `-D` con parámetros separados por `&`: `-D "key1=value1&key2=value2"`. El formato con múltiples `-D` es un comportamiento no documentado que funciona para funciones simples pero no para todas.
106+
**Solución:** Cambiar ambos helpers (`_api_call` y `_api_call_no_json`) para usar `&`-separated params en un solo `-D`.
107+
**Regla derivada:** Usar SIEMPRE el formato canónico `&`-separated. Nunca múltiples `-D`, aunque parezca funcionar.
108+
109+
### 2026-02-25 — JetBackup5 usa campo disabled (no enabled) para jobs
110+
111+
**Contexto:** jetbackup_api.py, fixtures de test
112+
**Problema:** Las fixtures usaban `"enabled": true/false` pero la API real devuelve `"disabled": 0/1`.
113+
**Causa raíz:** Se asumió la estructura del campo sin verificar con la API real.
114+
**Solución:** Fixtures actualizadas a `"disabled": 0` / `"disabled": 1`. El campo `enabled` no existe en la respuesta de `getBackupJob`.
115+
**Regla derivada:** Para destinos Y para jobs, el campo de estado es `disabled` (0/1 o true/false). Nunca `enabled`.
116+
117+
## Referencia rápida API JetBackup5
118+
119+
| Acción | Función API | Params clave |
120+
|--------|-------------|--------------|
121+
| Listar funciones | `jetbackup5api -F ""` ||
122+
| Estado destino | `manageDestinationState` | `_id`, `disabled=0/1` |
123+
| Modificar job | `manageBackupJob` | `_id`, `action=modify`, `disabled=0/1` |
124+
| Trigger job | `runBackupJobManually` | `_id` |
125+
| Info job | `getBackupJob` | `_id` |
126+
| Info destino | `getDestination` | `_id` |
127+
| Queue groups | `listQueueGroups` | `type=1` (backups) |
128+
129+
**Formato de parámetros:** siempre `&`-separated en un solo `-D`: `-D "_id=xxx&action=modify&disabled=0"`

pyproject.toml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ build-backend = "setuptools.backends._legacy:_Backend"
44

55
[project]
66
name = "jetbackup-remote"
7-
version = "0.1.0"
7+
version = "0.2.0"
88
description = "Remote orchestrator for JetBackup5 backup serialization"
99
readme = "README.md"
1010
license = "AGPL-3.0-or-later"
11-
requires-python = ">=3.9"
11+
requires-python = ">=3.11"
1212
authors = [
1313
{name = "Abdelkarim Mateos", email = "abdelkarim@aichadigital.es"},
1414
]
@@ -20,10 +20,9 @@ classifiers = [
2020
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
2121
"Operating System :: POSIX :: Linux",
2222
"Programming Language :: Python :: 3",
23-
"Programming Language :: Python :: 3.9",
24-
"Programming Language :: Python :: 3.10",
2523
"Programming Language :: Python :: 3.11",
2624
"Programming Language :: Python :: 3.12",
25+
"Programming Language :: Python :: 3.13",
2726
"Topic :: System :: Archiving :: Backup",
2827
]
2928

0 commit comments

Comments
 (0)