paramsx 2.5.0__tar.gz → 2.5.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {paramsx-2.5.0 → paramsx-2.5.1}/CHANGELOG.md +6 -0
  2. {paramsx-2.5.0/paramsx.egg-info → paramsx-2.5.1}/PKG-INFO +1 -1
  3. paramsx-2.5.1/paramsx/__init__.py +1 -0
  4. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/web/ssm.py +24 -0
  5. {paramsx-2.5.0 → paramsx-2.5.1/paramsx.egg-info}/PKG-INFO +1 -1
  6. {paramsx-2.5.0 → paramsx-2.5.1}/tests/test_web.py +65 -0
  7. paramsx-2.5.0/paramsx/__init__.py +0 -1
  8. {paramsx-2.5.0 → paramsx-2.5.1}/LICENSE +0 -0
  9. {paramsx-2.5.0 → paramsx-2.5.1}/MANIFEST.in +0 -0
  10. {paramsx-2.5.0 → paramsx-2.5.1}/README.md +0 -0
  11. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/core/__init__.py +0 -0
  12. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/core/config.py +0 -0
  13. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/core/rutas.py +0 -0
  14. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/funcions.py +0 -0
  15. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/main.py +0 -0
  16. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/paramsx_config.py +0 -0
  17. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/text.py +0 -0
  18. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/web/__init__.py +0 -0
  19. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/web/app.py +0 -0
  20. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/web/static/ajustes.js +0 -0
  21. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/web/static/app.css +0 -0
  22. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/web/static/comun.js +0 -0
  23. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/web/static/paramsx.js +0 -0
  24. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx/web/templates/index.html +0 -0
  25. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx.egg-info/SOURCES.txt +0 -0
  26. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx.egg-info/dependency_links.txt +0 -0
  27. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx.egg-info/entry_points.txt +0 -0
  28. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx.egg-info/requires.txt +0 -0
  29. {paramsx-2.5.0 → paramsx-2.5.1}/paramsx.egg-info/top_level.txt +0 -0
  30. {paramsx-2.5.0 → paramsx-2.5.1}/setup.cfg +0 -0
  31. {paramsx-2.5.0 → paramsx-2.5.1}/setup.py +0 -0
  32. {paramsx-2.5.0 → paramsx-2.5.1}/tests/test_core.py +0 -0
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.5.1
4
+
5
+ ### Corregido
6
+
7
+ - **Un borrado ya no pisa el cambio de otro**: justo antes de borrar se vuelve a leer la versión de cada parámetro (sin valores). Si alguien lo ha cambiado desde la revisión (también mientras se creaba la copia de un renombrado), no se borra y se avisa; en un renombrado, se dice que la copia se creó con el valor de antes. Si el rol no puede leer la versión, se borra como antes; si la lectura falla por otro motivo, no se borra.
8
+
3
9
  ## 2.5.0
4
10
 
5
11
  ### Añadido
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paramsx
3
- Version: 2.5.0
3
+ Version: 2.5.1
4
4
  Summary: Librería para gestionar y respaldar parámetros de AWS SSM de manera sencilla y eficiente.
5
5
  Home-page: https://github.com/pistatxos/paramsx
6
6
  Author: Mariox
@@ -0,0 +1 @@
1
+ __version__ = "2.5.1"
@@ -440,6 +440,30 @@ def aplicar(ssm, items, cfg):
440
440
  borrar.remove(b)
441
441
  resultados.append(b)
442
442
 
443
+ # Justo antes de borrar, otra vez la versión de cada uno (sin valores ni descifrar): si alguien lo ha cambiado desde
444
+ # la revisión (también mientras se creaban los renombrados), no se borra. SSM no tiene «borrar solo si sigue en la
445
+ # versión N»: entre esta lectura y el borrado queda una ventana de milisegundos que no se puede cerrar desde aquí.
446
+ esperada = {it.get("name"): it.get("version") for it in items if it.get("accion") == "borrar" and it.get("version")}
447
+ copia_de = {it.get("de"): it.get("name") for it in items if it.get("accion") == "nuevo" and it.get("de")}
448
+ try:
449
+ ahora = describir(ssm, "", [b["name"] for b in borrar]) if borrar else {}
450
+ except (ClientError, BotoCoreError) as exc:
451
+ if not denegado(exc):
452
+ # Otro fallo (red, límite de llamadas...): sin comprobar no se borra, pero lo ya aplicado se devuelve
453
+ for b in borrar:
454
+ b["error"] = f"No se pudo comprobar la versión antes de borrar ({motivo(exc)}): no se borra."
455
+ resultados += borrar
456
+ return resultados
457
+ ahora = None # sin permiso para describir: se borra como antes (ya se comprobó al revisar)
458
+ for b in [b for b in borrar if ahora is not None and b["name"] in ahora and b["name"] in esperada
459
+ and ahora[b["name"]].get("version") != esperada[b["name"]]]:
460
+ b["error"] = (f"Ha cambiado en AWS mientras se aplicaba (versión {esperada[b['name']]} → "
461
+ f"{ahora[b['name']].get('version')}): no se borra. "
462
+ + (f"Su copia «{copia_de[b['name']]}» se creó con el valor de antes: revisa cuál dejar."
463
+ if b["name"] in copia_de else "Recarga el grupo."))
464
+ borrar.remove(b)
465
+ resultados.append(b)
466
+
443
467
  # Borrados de 10 en 10 (el máximo de DeleteParameters)
444
468
  for i in range(0, len(borrar), 10):
445
469
  lote = borrar[i:i + 10]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paramsx
3
- Version: 2.5.0
3
+ Version: 2.5.1
4
4
  Summary: Librería para gestionar y respaldar parámetros de AWS SSM de manera sencilla y eficiente.
5
5
  Home-page: https://github.com/pistatxos/paramsx
6
6
  Author: Mariox
@@ -333,6 +333,71 @@ def test_renombrar_conserva_la_clave_kms_y_nunca_pierde_el_viejo(cliente, ssm, m
333
333
  assert "/dev/app/url" in ssm.params and not [o for o in ssm.ops("DeleteParameters") if "/dev/app/url" in o["Names"]]
334
334
 
335
335
 
336
+ def test_si_el_original_cambia_mientras_se_aplica_no_se_borra(cliente, ssm, monkeypatch):
337
+ ssm.poner("/dev/app/url", "https://x", tipo="String", tags=TAGS)
338
+ ssm.poner("/dev/app/b", "b", tipo="String", tags=TAGS)
339
+ ps = cargar(cliente)
340
+ aplicar = lambda items: {x["name"]: x for x in cliente.post("/api/aplicar", json={ # noqa: E731
341
+ "items": items, "confirmacion": CONFIRMA, "borrados": "1"}).get_json()["resultados"]}
342
+
343
+ # Mientras se crea la copia renombrada, otro cambia el original
344
+ real = ssm.put_parameter
345
+
346
+ def y_otro_cambia_el_original(**kw):
347
+ r = real(**kw)
348
+ if kw["Name"] == "/dev/app/url2":
349
+ real(Name="/dev/app/url", Value="https://nuevo", Overwrite=True)
350
+ return r
351
+ monkeypatch.setattr(ssm, "put_parameter", y_otro_cambia_el_original)
352
+ r = aplicar(renombrar(ps["/dev/app/url"], "/dev/app/url2"))
353
+ assert r["/dev/app/url2"]["ok"] and not r["/dev/app/url"]["ok"]
354
+ assert "Ha cambiado en AWS mientras se aplicaba (versión 1 → 2)" in r["/dev/app/url"]["error"]
355
+ assert "«/dev/app/url2»" in r["/dev/app/url"]["error"] # avisa de la copia con el valor de antes
356
+ assert ssm.params["/dev/app/url"]["value"] == "https://nuevo" # el cambio del otro no se pierde
357
+ assert ssm.ops("DeleteParameters") == []
358
+ monkeypatch.setattr(ssm, "put_parameter", real)
359
+
360
+ # Un borrado normal: lo cambian entre la revisión y el borrado
361
+ revisar_real = ssm_web._revisar
362
+
363
+ def revisa_y_cambia(*a, **k):
364
+ out = revisar_real(*a, **k)
365
+ ssm.poner("/dev/app/b", "b-de-otro", tipo="String")
366
+ return out
367
+ monkeypatch.setattr(ssm_web, "_revisar", revisa_y_cambia)
368
+ r = aplicar([item(ps["/dev/app/b"], accion="borrar")])
369
+ assert not r["/dev/app/b"]["ok"] and "Recarga el grupo" in r["/dev/app/b"]["error"]
370
+ assert "/dev/app/b" in ssm.params and ssm.ops("DeleteParameters") == []
371
+
372
+ # Sin permiso para volver a leerla: se borra como antes (ya se comprobó al revisar)
373
+ def revisa_y_quita_describe(*a, **k):
374
+ out = revisar_real(*a, **k)
375
+ ssm.sin_describe = True
376
+ return out
377
+ monkeypatch.setattr(ssm_web, "_revisar", revisa_y_quita_describe)
378
+ ssm.poner("/dev/app/c", "c", tipo="String")
379
+ r = aplicar([{"name": "/dev/app/c", "accion": "borrar", "version": 1}])
380
+ assert r["/dev/app/c"]["ok"] and "/dev/app/c" not in ssm.params
381
+ ssm.sin_describe = False
382
+
383
+ # Si falla de otra forma al leerla, no se borra (sin comprobar no se toca)
384
+ def revisa_y_rompe(*a, **k):
385
+ out = revisar_real(*a, **k)
386
+ monkeypatch.setattr(ssm, "describe_parameters", lambda **kw: (_ for _ in ()).throw(
387
+ ssm_web.ClientError({"Error": {"Code": "ThrottlingException", "Message": "Rate exceeded"}}, "Op")))
388
+ return out
389
+ monkeypatch.setattr(ssm_web, "_revisar", revisa_y_rompe)
390
+ ssm.poner("/dev/app/d", "d", tipo="String")
391
+ r = aplicar([{"name": "/dev/app/d", "accion": "borrar", "version": 1}])
392
+ assert not r["/dev/app/d"]["ok"] and "No se pudo comprobar" in r["/dev/app/d"]["error"]
393
+ assert "/dev/app/d" in ssm.params
394
+ monkeypatch.undo()
395
+
396
+ # Sin cambios, se borra como siempre (b va ya por la versión 2)
397
+ r = aplicar([{"name": "/dev/app/b", "accion": "borrar", "version": 2}])
398
+ assert r["/dev/app/b"]["ok"] and "/dev/app/b" not in ssm.params
399
+
400
+
336
401
  # ---------------------------------------------------------------- nombre sin barra final
337
402
 
338
403
  def test_nuevo_con_barra_final_se_quita(cliente, ssm):
@@ -1 +0,0 @@
1
- __version__ = "2.5.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes