fix: re-download cached import images when checksum is provided
volume_exists() only checked file presence, not content. A stale image from a previous download (different URL/version) would be silently reused, causing templates and VMs to be created from unpatched images even when the mirror's checksum pointed to a newer patched build. Add delete_volume() to ProxmoxClient storage mixin, and update both _do_image_download_sync and _do_image_template_sync to delete the cached volume and re-download whenever a checksum is provided, letting Proxmox verify the new download server-side.
This commit is contained in:
@@ -886,12 +886,18 @@ def _do_image_download_sync(task_id: int, server_id: int, node: str, storage: st
|
||||
else:
|
||||
dl_filename = filename
|
||||
|
||||
# Идемпотентность: если файл уже есть в хранилище — не качаем повторно
|
||||
# Идемпотентность: если файл уже есть в хранилище — не качаем повторно,
|
||||
# но при наличии контрольной суммы удаляем кэш и перекачиваем, чтобы
|
||||
# Proxmox проверил актуальность образа.
|
||||
existing_volid = f'{storage}:{content}/{dl_filename}'
|
||||
if client.volume_exists(node, storage, existing_volid):
|
||||
_update_deploy_task(task_id, 'completed', f'Образ {dl_filename} уже в хранилище', 100, node=node)
|
||||
logger.info(f"[IMG DL #{task_id}] {dl_filename} already present on {node}:{storage}")
|
||||
return
|
||||
if checksum:
|
||||
logger.info(f"[IMG DL #{task_id}] Removing cached {existing_volid} to re-verify checksum")
|
||||
client.delete_volume(node, storage, existing_volid)
|
||||
else:
|
||||
_update_deploy_task(task_id, 'completed', f'Образ {dl_filename} уже в хранилище', 100, node=node)
|
||||
logger.info(f"[IMG DL #{task_id}] {dl_filename} already present on {node}:{storage}")
|
||||
return
|
||||
|
||||
_update_deploy_task(task_id, 'running', f'Старт загрузки {dl_filename}...', 15, node=node)
|
||||
try:
|
||||
@@ -1057,10 +1063,19 @@ def _do_image_template_sync(task_id: int, server_id: int, node: str,
|
||||
filename = _normalize_import_filename(filename)
|
||||
import_volid = f'{import_storage}:import/{filename}'
|
||||
|
||||
need_download = True
|
||||
if client.volume_exists(node, import_storage, import_volid):
|
||||
# Образ уже скачан прошлой попыткой — пропускаем загрузку (идемпотентность)
|
||||
_update_deploy_task(task_id, 'running', 'Образ уже загружен, пропуск...', 40, node=node)
|
||||
else:
|
||||
if checksum:
|
||||
# Есть кэшированный файл, но задана контрольная сумма — удаляем
|
||||
# и перекачиваем: Proxmox проверит сумму при новой загрузке.
|
||||
logger.info(f"[IMG TPL #{task_id}] Removing cached {import_volid} to re-verify checksum")
|
||||
client.delete_volume(node, import_storage, import_volid)
|
||||
else:
|
||||
# Без контрольной суммы доверяем кэшу (чистая идемпотентность)
|
||||
need_download = False
|
||||
_update_deploy_task(task_id, 'running', 'Образ уже загружен, пропуск...', 40, node=node)
|
||||
|
||||
if need_download:
|
||||
_update_deploy_task(task_id, 'running', f'Загрузка образа {filename}...', 10, node=node)
|
||||
try:
|
||||
dl_upid = client.download_url(node, import_storage, url, 'import', filename,
|
||||
|
||||
@@ -170,6 +170,21 @@ class StorageMixin:
|
||||
logger.debug(f"volume_exists check failed {storage}/{volid}: {e}")
|
||||
return False
|
||||
|
||||
def delete_volume(self, node: str, storage: str, volid: str) -> bool:
|
||||
"""Удалить том из хранилища. volid вида 'storage:content/filename'.
|
||||
Возвращает True при успехе, False при ошибке."""
|
||||
if not self.proxmox:
|
||||
return False
|
||||
# proxmoxer принимает volume без префикса хранилища
|
||||
volume = volid.split(':', 1)[1] if ':' in volid else volid
|
||||
try:
|
||||
self.proxmox.nodes(node).storage(storage).content(volume).delete()
|
||||
logger.info(f"Deleted volume {volid} from {node}:{storage}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(f"delete_volume failed {node}:{storage}/{volume}: {e}")
|
||||
return False
|
||||
|
||||
def get_download_target_storages(self, node: str, content: str) -> List[Dict]:
|
||||
"""
|
||||
Получить активные хранилища ноды, поддерживающие указанный тип контента
|
||||
|
||||
Reference in New Issue
Block a user