mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-10-07 22:16:39 +00:00
Adds the OCI manager: an engine that turns a Docker Compose file into an LXC definition, a catalog of 365 applications drawn from LinuxServer.io and other container image sources, and a per-instance registry recording what each container was built from. Reachable from the main menu. Catalog text is translated like every other string in the project: the taglines go through translate() and land in lang/*.json, so the entries read in all eight languages instead of only English. Translation cache builder: - a failed translation leaves the key absent rather than writing English, which previously made the string count as translated forever - a result identical to a 3+ word source is rejected, catching a provider that silently returns the text it was given - strings that are nothing but glossary terms keep their source spelling instead of being discarded as failures - no backoff between attempts when the provider is deterministic - application names are protected so "HAOS One" survives translation - argos joins the provider list, and the workflow reads the OCI sources Audit & Report: - findings that moved in the wrong direction between runs are reported alongside the ones that improved - an accepted risk can carry a review date and is flagged when it falls due - backup checks explain in plain language what they looked at and what to do next Monitor: - disks can be excluded from periodic reads, and an idle disk says so instead of showing a stale temperature - per-disk identity survives a controller or enclosure change - scheduled Borg backups resolve their SSH key from the repository entry - PVE upgrades log the package list and the resulting dpkg changes The web build no longer copies scripts/ into public/: the documentation links to GitHub, so nothing read that folder. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
36 lines
2.2 KiB
Python
36 lines
2.2 KiB
Python
"""Build separate update/recreate proposals without mutating live contracts."""
|
|
import copy
|
|
|
|
|
|
def propose(instance, operation, current_template=None, edited_deployment=None):
|
|
if operation not in ('update', 'recreate'):
|
|
raise ValueError('Operacion no soportada')
|
|
if instance.get('status') != 'installed':
|
|
raise ValueError('La instancia no esta completada')
|
|
if operation == 'update' and (current_template is not None or edited_deployment is not None):
|
|
raise ValueError('Actualizar no puede modificar la configuracion; usa Recrear')
|
|
candidate = copy.deepcopy(instance)
|
|
if operation == 'recreate':
|
|
if current_template is None or edited_deployment is None:
|
|
raise ValueError('Recrear requiere la plantilla actual y la configuracion confirmada')
|
|
if current_template['id'] != instance['template']['id']:
|
|
raise ValueError('No se puede sustituir silenciosamente la aplicacion')
|
|
if edited_deployment.get('vmid') != instance['vmid']:
|
|
raise ValueError('Recrear conserva la identidad y el VMID')
|
|
candidate['template'] = copy.deepcopy(current_template)
|
|
candidate['deployment'] = copy.deepcopy(edited_deployment)
|
|
old = {m['container_path']: m for m in instance['deployment'].get('mounts', [])}
|
|
new = {m['container_path']: m for m in candidate['deployment'].get('mounts', [])}
|
|
if len(new) != len(candidate['deployment'].get('mounts', [])):
|
|
raise ValueError('Rutas duplicadas')
|
|
changed_storage = [p for p in old.keys() & new.keys()
|
|
if (old[p].get('type'), old[p].get('source')) !=
|
|
(new[p].get('type'), new[p].get('source'))]
|
|
return {'operation': operation, 'installation_id': instance['installation_id'],
|
|
'candidate': candidate, 'requires_confirmation': True,
|
|
'mounts': {'reuse': sorted(old.keys() & new.keys() - set(changed_storage)),
|
|
'add': sorted(new.keys() - old.keys()),
|
|
'detach_without_delete': sorted(old.keys() - new.keys()),
|
|
'storage_change_requires_migration': sorted(changed_storage)},
|
|
'execution_enabled': False}
|