mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-11-04 20:02:07 +00:00
fix(oci): refuse an HA-managed container before downloading the image and explain how to proceed
This commit is contained in:
+2
-1
@@ -9014,5 +9014,6 @@
|
||||
"⚠ Disk data will NOT be erased.": "⚠ Festplattendaten werden NICHT gelöscht.",
|
||||
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ Die Festplatte wird ausgehängt und aus /etc/fstab entfernt.",
|
||||
"⚠ The /etc/fstab entry will be removed.": "⚠ Der /etc/fstab-Eintrag wird entfernt.",
|
||||
"⚠ The disk will be unmounted.": "⚠ Die Festplatte wird ausgehängt."
|
||||
"⚠ The disk will be unmounted.": "⚠ Die Festplatte wird ausgehängt.",
|
||||
"This container is managed by high availability. Remove ct:{vmid} from HA (Datacenter → HA, or ha-manager remove ct:{vmid}), repeat the operation and add it back to HA with the same settings.": "Dieser Container wird von der Hochverfügbarkeit verwaltet. Entfernen Sie ct:{vmid} aus HA (Rechenzentrum → HA oder ha-manager remove ct:{vmid}), wiederholen Sie den Vorgang und fügen Sie ihn mit denselben Einstellungen wieder zu HA hinzu."
|
||||
}
|
||||
|
||||
+2
-1
@@ -8984,5 +8984,6 @@
|
||||
"⚠ Disk data will NOT be erased.": "⚠ Los datos del disco NO se borrarán.",
|
||||
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ El disco se desmontará y se eliminará de /etc/fstab.",
|
||||
"⚠ The /etc/fstab entry will be removed.": "⚠ Se eliminará la entrada /etc/fstab.",
|
||||
"⚠ The disk will be unmounted.": "⚠ El disco se desmontará."
|
||||
"⚠ The disk will be unmounted.": "⚠ El disco se desmontará.",
|
||||
"This container is managed by high availability. Remove ct:{vmid} from HA (Datacenter → HA, or ha-manager remove ct:{vmid}), repeat the operation and add it back to HA with the same settings.": "Este contenedor está gestionado por alta disponibilidad. Elimina ct:{vmid} de HA (Centro de datos → HA, o ha-manager remove ct:{vmid}), repite la operación y vuelve a añadirlo a HA con la misma configuración."
|
||||
}
|
||||
|
||||
+2
-1
@@ -9013,5 +9013,6 @@
|
||||
"⚠ Disk data will NOT be erased.": "⚠ Les données du disque ne seront PAS effacées.",
|
||||
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ Le disque sera démonté et supprimé de /etc/fstab.",
|
||||
"⚠ The /etc/fstab entry will be removed.": "⚠ L'entrée /etc/fstab sera supprimée.",
|
||||
"⚠ The disk will be unmounted.": "⚠ Le disque sera démonté."
|
||||
"⚠ The disk will be unmounted.": "⚠ Le disque sera démonté.",
|
||||
"This container is managed by high availability. Remove ct:{vmid} from HA (Datacenter → HA, or ha-manager remove ct:{vmid}), repeat the operation and add it back to HA with the same settings.": "Ce conteneur est géré par la haute disponibilité. Retirez ct:{vmid} de HA (Centre de données → HA, ou ha-manager remove ct:{vmid}), relancez l'opération et rajoutez-le à HA avec les mêmes paramètres."
|
||||
}
|
||||
|
||||
+2
-1
@@ -9014,5 +9014,6 @@
|
||||
"⚠ Disk data will NOT be erased.": "⚠ I dati del disco NON verranno cancellati.",
|
||||
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ Il disco verrà smontato e rimosso da /etc/fstab.",
|
||||
"⚠ The /etc/fstab entry will be removed.": "⚠ La voce /etc/fstab verrà rimossa.",
|
||||
"⚠ The disk will be unmounted.": "⚠ Il disco verrà smontato."
|
||||
"⚠ The disk will be unmounted.": "⚠ Il disco verrà smontato.",
|
||||
"This container is managed by high availability. Remove ct:{vmid} from HA (Datacenter → HA, or ha-manager remove ct:{vmid}), repeat the operation and add it back to HA with the same settings.": "Questo container è gestito dall'alta disponibilità. Rimuovi ct:{vmid} da HA (Datacenter → HA, oppure ha-manager remove ct:{vmid}), ripeti l'operazione e aggiungilo di nuovo a HA con le stesse impostazioni."
|
||||
}
|
||||
|
||||
+2
-1
@@ -9014,5 +9014,6 @@
|
||||
"⚠ Disk data will NOT be erased.": "⚠ Os dados do disco NÃO serão apagados.",
|
||||
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ O disco será desmontado e removido de /etc/fstab.",
|
||||
"⚠ The /etc/fstab entry will be removed.": "⚠ A entrada /etc/fstab será removida.",
|
||||
"⚠ The disk will be unmounted.": "⚠ O disco será desmontado."
|
||||
"⚠ The disk will be unmounted.": "⚠ O disco será desmontado.",
|
||||
"This container is managed by high availability. Remove ct:{vmid} from HA (Datacenter → HA, or ha-manager remove ct:{vmid}), repeat the operation and add it back to HA with the same settings.": "Este contentor é gerido pela alta disponibilidade. Remova ct:{vmid} da HA (Datacenter → HA, ou ha-manager remove ct:{vmid}), repita a operação e volte a adicioná-lo à HA com as mesmas definições."
|
||||
}
|
||||
|
||||
+2
-1
@@ -9014,5 +9014,6 @@
|
||||
"⚠ Disk data will NOT be erased.": "⚠ Dáta na disku sa NEVYMAŽÚ.",
|
||||
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ Disk sa odpojí a odstráni z /etc/fstab.",
|
||||
"⚠ The /etc/fstab entry will be removed.": "⚠ Záznam v /etc/fstab bude odstránený.",
|
||||
"⚠ The disk will be unmounted.": "⚠ Disk bude odpojený."
|
||||
"⚠ The disk will be unmounted.": "⚠ Disk bude odpojený.",
|
||||
"This container is managed by high availability. Remove ct:{vmid} from HA (Datacenter → HA, or ha-manager remove ct:{vmid}), repeat the operation and add it back to HA with the same settings.": "Tento kontajner spravuje vysoká dostupnosť. Odstráňte ct:{vmid} z HA (Dátové centrum → HA alebo ha-manager remove ct:{vmid}), zopakujte operáciu a potom ho znova pridajte do HA s rovnakými nastaveniami."
|
||||
}
|
||||
|
||||
+4
-1
@@ -9012,5 +9012,8 @@
|
||||
"⚠ Disk data will NOT be erased.": "⚠ Diskdata kommer INTE att raderas.",
|
||||
"⚠ Disk will be unmounted and removed from /etc/fstab.": "⚠ Disken kommer att avmonteras och tas bort från /etc/fstab.",
|
||||
"⚠ The /etc/fstab entry will be removed.": "⚠ /etc/fstab-posten kommer att tas bort.",
|
||||
"⚠ The disk will be unmounted.": "⚠ Disken kommer att avmonteras."
|
||||
"⚠ The disk will be unmounted.": "⚠ Disken kommer att avmonteras.",
|
||||
"This container is managed by high availability. Remove ct:{vmid} from HA (Datacenter → HA, or ha-manager remove ct:{vmid}), repeat the operation and add it back to HA with the same settings.": "Den här containern hanteras av hög tillgänglighet. Ta bort ct:{vmid} från HA (Datacenter → HA, eller ha-manager remove ct:{vmid}), upprepa åtgärden och lägg sedan tillbaka den i HA med samma inställningar.",
|
||||
"Krusader Web UI": "Krusaders webbgränssnitt",
|
||||
"Z-Wave JS UI admin login": "Administratörsinloggning för Z-Wave JS UI"
|
||||
}
|
||||
|
||||
@@ -621,6 +621,17 @@ def without_public_routes(config, vmid):
|
||||
return b'\n'.join(line for line in config.splitlines() if not public_routes.own(line, vmid)) + b'\n'
|
||||
|
||||
|
||||
def refuse_high_availability(vmid):
|
||||
"""Recreating a container that HA manages would race the HA manager, which
|
||||
restarts or relocates it in the middle of the replacement."""
|
||||
resources = json.loads(run('pvesh', 'get', '/cluster/ha/resources', '--output-format', 'json'))
|
||||
if any(r.get('sid') == f'ct:{vmid}' for r in resources):
|
||||
raise ValueError(translate(
|
||||
'This container is managed by high availability. Remove ct:{vmid} from HA (Datacenter → HA, '
|
||||
'or ha-manager remove ct:{vmid}), repeat the operation and add it back to HA with the same settings.'
|
||||
).replace('{vmid}', str(vmid)))
|
||||
|
||||
|
||||
def preflight(record, candidate, config, coordinated=None, in_place=False, baseline=True):
|
||||
deployment = record['deployment']
|
||||
desired = candidate['deployment']
|
||||
@@ -1202,9 +1213,7 @@ def apply(root, vmid, archive, operation, proposal=None, registry_digest=None, i
|
||||
runtime_settings.file_binds(before))
|
||||
original_gpu = gpu_devices.planned(record['deployment'])
|
||||
desired_gpu = gpu_devices.planned(candidate['deployment'])
|
||||
resources = json.loads(run('pvesh', 'get', '/cluster/ha/resources', '--output-format', 'json'))
|
||||
if any(r.get('sid') == f'ct:{vmid}' for r in resources):
|
||||
raise ValueError(translate('High availability resources are not supported by this profile'))
|
||||
refuse_high_availability(vmid)
|
||||
archive = archive.resolve(strict=True)
|
||||
check_archive(archive)
|
||||
image = image_from_archive(str(archive))
|
||||
|
||||
@@ -233,6 +233,8 @@ def update(vmid, acknowledge_external_data=False, proposal=None, keep_backup=Non
|
||||
# the route before changing anything; actual validation/API failures
|
||||
# must not silently switch to a destructive fallback.
|
||||
transaction.preflight(record, desired, config)
|
||||
# Refused before the image is downloaded, not after.
|
||||
transaction.refuse_high_availability(vmid)
|
||||
msg_ok(translate('Container checked'))
|
||||
current = record['observed']['image'] if operation == 'update' else None
|
||||
check = lambda: work_backup.locate(
|
||||
|
||||
@@ -151,6 +151,7 @@ class NativeApplyTests(unittest.TestCase):
|
||||
self.commands.append(args)
|
||||
if args[:2]==('pct','status'):return b'status: running' if self.state['running'] else b'status: stopped'
|
||||
if args[:2]==('pct','start'):self.state['running']=True
|
||||
if args[:3]==('pvesh','get','/cluster/ha/resources'):return b'[]'
|
||||
return b''
|
||||
def stop(vmid):self.state['running']=False
|
||||
def setter(vmid,identity,expected,values,delete=()):
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
"""A container that HA manages is refused before its new image is downloaded."""
|
||||
import contextlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'remote'))
|
||||
import oci_instance_transaction as transaction
|
||||
import oci_update_current as update
|
||||
|
||||
|
||||
def ha_resources(*vmids):
|
||||
answer = json.dumps([{'sid': f'ct:{vmid}', 'state': 'started'} for vmid in vmids]).encode()
|
||||
return patch.object(transaction, 'run', return_value=answer)
|
||||
|
||||
|
||||
class HighAvailabilityTests(unittest.TestCase):
|
||||
def test_the_refusal_names_the_resource_and_how_to_proceed(self):
|
||||
with ha_resources(101), self.assertRaises(ValueError) as refused:
|
||||
transaction.refuse_high_availability(101)
|
||||
self.assertIn('ha-manager remove ct:101', str(refused.exception))
|
||||
|
||||
def test_a_container_outside_ha_is_not_refused(self):
|
||||
with ha_resources(200):
|
||||
transaction.refuse_high_availability(101)
|
||||
|
||||
def test_an_update_stops_before_downloading_the_image(self):
|
||||
record = {'status': 'installed', 'observed': {'image': {}}}
|
||||
resolve = Mock()
|
||||
with contextlib.ExitStack() as stack:
|
||||
stack.enter_context(patch.object(update.instances, 'locked', return_value=contextlib.nullcontext()))
|
||||
stack.enter_context(patch.object(update.instances, 'read', return_value=record))
|
||||
stack.enter_context(patch.object(update.instances, 'command', return_value=b''))
|
||||
stack.enter_context(patch.object(update.transaction, 'candidate_contract', return_value={}))
|
||||
stack.enter_context(patch.object(update.transaction, 'external_changes', return_value={}))
|
||||
stack.enter_context(patch.object(update.transaction, 'preflight'))
|
||||
stack.enter_context(patch.object(update, 'resolve_archive', resolve))
|
||||
stack.enter_context(patch.object(update, 'msg_info'))
|
||||
stack.enter_context(patch.object(update, 'msg_ok'))
|
||||
stack.enter_context(ha_resources(101))
|
||||
with self.assertRaises(ValueError):
|
||||
update.update(101)
|
||||
resolve.assert_not_called()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user