mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
fix(jobs): a live clone that recovery cannot define ends uncertain
After a successful copy, recovery defined the clone; a define that failed raised, and recovery retried it with the same result. One case is certain: a worker killed after define_clone copied the UEFI variables but before it defined the VM leaves <clone>_VARS.fd, and every retry is refused because the volume exists. The job then waited for recovery with its claims on the source VM and the clone's name. A libvirt error now ends it uncertain, naming the error and the copied volumes; an unreachable host still waits.
This commit is contained in:
parent
50c6e1f0fe
commit
e3e32f6b90
6 changed files with 98 additions and 64 deletions
|
|
@ -714,7 +714,14 @@ class CloneInstance(Kind):
|
|||
if not success:
|
||||
_delete_created(proxy, op)
|
||||
return Outcome(ended, error=say(errmsg or _("The copy failed")))
|
||||
proxy.define_clone(op.intent["clone"], op.intent["uuid"], {c["dev"]: c["path"] for c in created})
|
||||
try:
|
||||
proxy.define_clone(op.intent["clone"], op.intent["uuid"], {c["dev"]: c["path"] for c in created})
|
||||
except util.ConnectionFailed:
|
||||
raise # unreachable: recovery waits and retries
|
||||
except libvirtError as err: # it would fail the same way at every retry
|
||||
return Outcome(Operation.UNCERTAIN, error=say(_(
|
||||
"The disks were copied, but the clone could not be defined: %(error)s; check these volumes, "
|
||||
"then resolve this job: %(volumes)s"), error=err, volumes=volumes))
|
||||
return Outcome(Operation.SUCCEEDED, result=_clone_made(op, _finish_clone(op, op.intent["clone"], [])))
|
||||
|
||||
def log_entry(self, op, state):
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ from instances.jobs import CloneInstance
|
|||
from instances.models import Instance
|
||||
from operations.utils import words
|
||||
from operations.jobs import Cancelled, Context
|
||||
from vrtManager.util import OperationError
|
||||
from vrtManager.util import ConnectionFailed, OperationError
|
||||
from operations.models import Claim, Operation, acquire
|
||||
|
||||
|
||||
|
|
@ -601,6 +601,17 @@ class LiveCloneJobTestCase(TransactionTestCase):
|
|||
Instance.objects.filter(uuid=op.intent["uuid"]).delete()
|
||||
op.delete()
|
||||
|
||||
def test_recovery_that_cannot_define_the_clone_ends_uncertain(self):
|
||||
# the worker stopped after define_clone copied the UEFI variables: a retry finds the copy there
|
||||
self.track("define_clone", libvirt_error(libvirt.VIR_ERR_STORAGE_VOL_EXIST))
|
||||
outcome, _op = self.recovered(copy_result=[True, ""])
|
||||
self.assertEqual(outcome.state, Operation.UNCERTAIN)
|
||||
self.assertIn("/real/copy-vda.qcow2", words(outcome.error))
|
||||
self.assertEqual(self.deleted(), [])
|
||||
self.track("define_clone", ConnectionFailed("host down"))
|
||||
with self.assertRaises(ConnectionFailed):
|
||||
self.recovered(copy_result=[True, ""])
|
||||
|
||||
def test_recovery_gives_the_clone_the_size_asked_and_starts_it(self):
|
||||
clone = {"name": "copy", "disk-vda": "copy-vda.qcow2", "disk_owner_uid": 107, "disk_owner_gid": 107,
|
||||
"vcpu": 2, "memory": None, "start": True}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -2857,7 +2857,7 @@ msgstr ""
|
|||
msgid "Clone VM"
|
||||
msgstr "Sanal makineyi klonla"
|
||||
|
||||
#: instances/jobs.py:559 instances/jobs.py:566 instances/jobs.py:834
|
||||
#: instances/jobs.py:559 instances/jobs.py:566 instances/jobs.py:841
|
||||
msgid "Copying disks"
|
||||
msgstr "Diskler kopyalanıyor"
|
||||
|
||||
|
|
@ -2922,140 +2922,149 @@ msgstr ""
|
|||
"libvirt'te kopyanın sonucu yok; şu birimleri kontrol edin, sonra bu işi "
|
||||
"çözün: %(volumes)s"
|
||||
|
||||
#: instances/jobs.py:739 instances/templates/create_instance_w1.html:60
|
||||
#: instances/jobs.py:723
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The disks were copied, but the clone could not be defined: %(error)s; check "
|
||||
"these volumes, then resolve this job: %(volumes)s"
|
||||
msgstr ""
|
||||
"Diskler kopyalandı, ancak klon tanımlanamadı: %(error)s; şu birimleri kontrol"
|
||||
" edin, sonra bu işi çözün: %(volumes)s"
|
||||
|
||||
#: instances/jobs.py:746 instances/templates/create_instance_w1.html:60
|
||||
#: instances/templates/create_instance_w2.html:356
|
||||
msgid "Create VM"
|
||||
msgstr "Sanal makine oluştur"
|
||||
|
||||
#: instances/jobs.py:763 instances/jobs.py:808 instances/views.py:2504
|
||||
#: instances/jobs.py:770 instances/jobs.py:815 instances/views.py:2504
|
||||
msgid "A virtual machine with this name already exists"
|
||||
msgstr "Bu isimde bir sanal makine mevcut"
|
||||
|
||||
#: instances/jobs.py:765 instances/jobs.py:805
|
||||
#: instances/jobs.py:772 instances/jobs.py:812
|
||||
msgid "There is an instance with same name. Remove it and try again!"
|
||||
msgstr "Aynı isimde başka bir sanal makine var. Onu silip yeniden deneyin!"
|
||||
|
||||
#: instances/jobs.py:768
|
||||
#: instances/jobs.py:775
|
||||
msgid "First you need to create or select an image"
|
||||
msgstr "Öncelikle bir imaj oluşturun ya da mevcut bir imajı seçin"
|
||||
|
||||
#: instances/jobs.py:770
|
||||
#: instances/jobs.py:777
|
||||
msgid "Choose one disk source: a new disk, existing volumes or a template"
|
||||
msgstr ""
|
||||
"Tek bir disk kaynağı seçin: yeni bir disk, mevcut birimler ya da bir şablon"
|
||||
|
||||
#: instances/jobs.py:772
|
||||
#: instances/jobs.py:779
|
||||
msgid "Image has already exist. Please check volumes or change instance name"
|
||||
msgstr ""
|
||||
"İmaj zaten mevcut. Lütfen ya makine adını değişin ya da disk alanlarını "
|
||||
"kontrol edin"
|
||||
|
||||
#: instances/jobs.py:774
|
||||
#: instances/jobs.py:781
|
||||
msgid "Invalid cache mode"
|
||||
msgstr "Geçersiz önbellek modu"
|
||||
|
||||
#: instances/jobs.py:776
|
||||
#: instances/jobs.py:783
|
||||
#, python-format
|
||||
msgid "This host offers no CPU mode or model %(mode)s"
|
||||
msgstr "Bu sunucu %(mode)s CPU modunu veya modelini sunmuyor"
|
||||
|
||||
#: instances/jobs.py:778
|
||||
#: instances/jobs.py:785
|
||||
#, python-format
|
||||
msgid "A CD-ROM cannot use the %(bus)s bus"
|
||||
msgstr "CD-ROM %(bus)s veri yolunu kullanamaz"
|
||||
|
||||
#: instances/jobs.py:781
|
||||
#: instances/jobs.py:788
|
||||
msgid "The cloud-init seed is read from a CD-ROM: choose its bus"
|
||||
msgstr "cloud-init tohumu bir CD-ROM'dan okunur: veri yolunu seçin"
|
||||
|
||||
#: instances/jobs.py:784
|
||||
#: instances/jobs.py:791
|
||||
msgid "The cloud-init seed needs a directory storage pool for the disk"
|
||||
msgstr "cloud-init tohumu, disk için bir dizin depolama havuzu gerektirir"
|
||||
|
||||
#: instances/jobs.py:790
|
||||
#: instances/jobs.py:797
|
||||
#, python-format
|
||||
msgid "This host offers no firmware %(firmware)s"
|
||||
msgstr "Bu sunucu %(firmware)s firmware'ini sunmuyor"
|
||||
|
||||
#: instances/jobs.py:792 vrtManager/instance.py:3023
|
||||
#: instances/jobs.py:799 vrtManager/instance.py:3023
|
||||
msgid "This host offers no TPM 2.0: install swtpm on it"
|
||||
msgstr "Bu sunucu TPM 2.0 sunmuyor: üzerine swtpm kurun"
|
||||
|
||||
#: instances/jobs.py:853
|
||||
#: instances/jobs.py:860
|
||||
msgid "Writing the cloud-init seed"
|
||||
msgstr "cloud-init tohumu yazılıyor"
|
||||
|
||||
#: instances/jobs.py:860
|
||||
#: instances/jobs.py:867
|
||||
msgid "Defining the VM"
|
||||
msgstr "Sanal makine tanımlanıyor"
|
||||
|
||||
#: instances/jobs.py:893
|
||||
#: instances/jobs.py:900
|
||||
#, python-format
|
||||
msgid "%(error)s. Remove these volumes by hand: %(volumes)s"
|
||||
msgstr "%(error)s. Şu birimleri elle silin: %(volumes)s"
|
||||
|
||||
#: instances/jobs.py:918
|
||||
#: instances/jobs.py:925
|
||||
#, python-format
|
||||
msgid "The instance is already on %(compute)s"
|
||||
msgstr "Sanal makine zaten %(compute)s üzerinde"
|
||||
|
||||
#: instances/jobs.py:920
|
||||
#: instances/jobs.py:927
|
||||
#, python-format
|
||||
msgid "%(compute)s is not reachable"
|
||||
msgstr "%(compute)s sunucusuna ulaşılamıyor"
|
||||
|
||||
#: instances/jobs.py:922
|
||||
#: instances/jobs.py:929
|
||||
#, python-format
|
||||
msgid "%(compute)s is the VM's own host under another name"
|
||||
msgstr "%(compute)s, sanal makinenin kendi sunucusunun başka bir adı"
|
||||
|
||||
#: instances/jobs.py:940
|
||||
#: instances/jobs.py:947
|
||||
msgid "Migrate VM"
|
||||
msgstr "Sanal makineyi taşı"
|
||||
|
||||
#: instances/jobs.py:984
|
||||
#: instances/jobs.py:991
|
||||
msgid "Migrating the VM"
|
||||
msgstr "Sanal makine taşınıyor"
|
||||
|
||||
#: instances/jobs.py:1031
|
||||
#: instances/jobs.py:1038
|
||||
msgid "libvirt is still migrating the VM"
|
||||
msgstr "libvirt sanal makineyi hâlâ taşıyor"
|
||||
|
||||
#: instances/jobs.py:1038
|
||||
#: instances/jobs.py:1045
|
||||
msgid "The VM stayed on the source host"
|
||||
msgstr "Sanal makine kaynak sunucuda kaldı"
|
||||
|
||||
#: instances/jobs.py:1040
|
||||
#: instances/jobs.py:1047
|
||||
msgid ""
|
||||
"The VM is on both computes or on neither; check them, then resolve this job."
|
||||
msgstr ""
|
||||
"Sanal makine ya iki sunucuda da var ya da hiçbirinde yok; kontrol edin, sonra"
|
||||
" bu işi çözün."
|
||||
|
||||
#: instances/jobs.py:1088
|
||||
#: instances/jobs.py:1095
|
||||
msgid "Move disk"
|
||||
msgstr "Diski taşı"
|
||||
|
||||
#: instances/jobs.py:1095
|
||||
#: instances/jobs.py:1102
|
||||
msgid "Choose a disk of the VM"
|
||||
msgstr "Sanal makinenin bir diskini seçin"
|
||||
|
||||
#: instances/jobs.py:1119
|
||||
#: instances/jobs.py:1126
|
||||
msgid "Copying the disk"
|
||||
msgstr "Disk kopyalanıyor"
|
||||
|
||||
#: instances/jobs.py:1162
|
||||
#: instances/jobs.py:1169
|
||||
#, python-format
|
||||
msgid "Another block job runs on %(dev)s; check the VM"
|
||||
msgstr ""
|
||||
"%(dev)s üzerinde başka bir blok işi çalışıyor; sanal makineyi kontrol edin"
|
||||
|
||||
#: instances/jobs.py:1168
|
||||
#: instances/jobs.py:1175
|
||||
#, python-format
|
||||
msgid "The disk stayed in %(path)s; remove %(dest)s if it is there"
|
||||
msgstr "Disk %(path)s içinde kaldı; varsa %(dest)s dosyasını silin"
|
||||
|
||||
#: instances/jobs.py:1170
|
||||
#: instances/jobs.py:1177
|
||||
#, python-format
|
||||
msgid "The definitions of %(dev)s name %(paths)s; check the VM"
|
||||
msgstr "%(dev)s tanımları %(paths)s gösteriyor; sanal makineyi kontrol edin"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -2752,7 +2752,7 @@ msgstr "无法解冻客户机的文件系统(%(error)s);请用以下命令
|
|||
msgid "Clone VM"
|
||||
msgstr "克隆虚拟机"
|
||||
|
||||
#: instances/jobs.py:559 instances/jobs.py:566 instances/jobs.py:834
|
||||
#: instances/jobs.py:559 instances/jobs.py:566 instances/jobs.py:841
|
||||
msgid "Copying disks"
|
||||
msgstr "正在复制磁盘"
|
||||
|
||||
|
|
@ -2807,134 +2807,141 @@ msgid ""
|
|||
"job: %(volumes)s"
|
||||
msgstr "libvirt 没有复制的结果;请检查这些卷,然后处理此任务:%(volumes)s"
|
||||
|
||||
#: instances/jobs.py:739 instances/templates/create_instance_w1.html:60
|
||||
#: instances/jobs.py:723
|
||||
#, python-format
|
||||
msgid ""
|
||||
"The disks were copied, but the clone could not be defined: %(error)s; check "
|
||||
"these volumes, then resolve this job: %(volumes)s"
|
||||
msgstr "磁盘已复制,但无法定义克隆:%(error)s;请检查这些卷,然后处理此任务:%(volumes)s"
|
||||
|
||||
#: instances/jobs.py:746 instances/templates/create_instance_w1.html:60
|
||||
#: instances/templates/create_instance_w2.html:356
|
||||
msgid "Create VM"
|
||||
msgstr "创建虚拟机"
|
||||
|
||||
#: instances/jobs.py:763 instances/jobs.py:808 instances/views.py:2504
|
||||
#: instances/jobs.py:770 instances/jobs.py:815 instances/views.py:2504
|
||||
msgid "A virtual machine with this name already exists"
|
||||
msgstr "同名虚拟机已存在"
|
||||
|
||||
#: instances/jobs.py:765 instances/jobs.py:805
|
||||
#: instances/jobs.py:772 instances/jobs.py:812
|
||||
msgid "There is an instance with same name. Remove it and try again!"
|
||||
msgstr "已存在同名虚拟机。请删除后重试!"
|
||||
|
||||
#: instances/jobs.py:768
|
||||
#: instances/jobs.py:775
|
||||
msgid "First you need to create or select an image"
|
||||
msgstr "请先创建或选择一个镜像"
|
||||
|
||||
#: instances/jobs.py:770
|
||||
#: instances/jobs.py:777
|
||||
msgid "Choose one disk source: a new disk, existing volumes or a template"
|
||||
msgstr "请选择一种磁盘来源:新磁盘、现有卷或模板"
|
||||
|
||||
#: instances/jobs.py:772
|
||||
#: instances/jobs.py:779
|
||||
msgid "Image has already exist. Please check volumes or change instance name"
|
||||
msgstr "镜像已存在。请检查卷或更改虚拟机名称"
|
||||
|
||||
#: instances/jobs.py:774
|
||||
#: instances/jobs.py:781
|
||||
msgid "Invalid cache mode"
|
||||
msgstr "无效的缓存模式"
|
||||
|
||||
#: instances/jobs.py:776
|
||||
#: instances/jobs.py:783
|
||||
#, python-format
|
||||
msgid "This host offers no CPU mode or model %(mode)s"
|
||||
msgstr "此主机不提供 CPU 模式或型号 %(mode)s"
|
||||
|
||||
#: instances/jobs.py:778
|
||||
#: instances/jobs.py:785
|
||||
#, python-format
|
||||
msgid "A CD-ROM cannot use the %(bus)s bus"
|
||||
msgstr "CD-ROM 不能使用 %(bus)s 总线"
|
||||
|
||||
#: instances/jobs.py:781
|
||||
#: instances/jobs.py:788
|
||||
msgid "The cloud-init seed is read from a CD-ROM: choose its bus"
|
||||
msgstr "cloud-init 种子从 CD-ROM 读取:请选择其总线"
|
||||
|
||||
#: instances/jobs.py:784
|
||||
#: instances/jobs.py:791
|
||||
msgid "The cloud-init seed needs a directory storage pool for the disk"
|
||||
msgstr "cloud-init 种子需要为磁盘使用目录类型的存储池"
|
||||
|
||||
#: instances/jobs.py:790
|
||||
#: instances/jobs.py:797
|
||||
#, python-format
|
||||
msgid "This host offers no firmware %(firmware)s"
|
||||
msgstr "此主机不提供固件 %(firmware)s"
|
||||
|
||||
#: instances/jobs.py:792 vrtManager/instance.py:3023
|
||||
#: instances/jobs.py:799 vrtManager/instance.py:3023
|
||||
msgid "This host offers no TPM 2.0: install swtpm on it"
|
||||
msgstr "此主机不提供 TPM 2.0:请在主机上安装 swtpm"
|
||||
|
||||
#: instances/jobs.py:853
|
||||
#: instances/jobs.py:860
|
||||
msgid "Writing the cloud-init seed"
|
||||
msgstr "正在写入 cloud-init 种子"
|
||||
|
||||
#: instances/jobs.py:860
|
||||
#: instances/jobs.py:867
|
||||
msgid "Defining the VM"
|
||||
msgstr "正在定义虚拟机"
|
||||
|
||||
#: instances/jobs.py:893
|
||||
#: instances/jobs.py:900
|
||||
#, python-format
|
||||
msgid "%(error)s. Remove these volumes by hand: %(volumes)s"
|
||||
msgstr "%(error)s。请手动删除这些卷:%(volumes)s"
|
||||
|
||||
#: instances/jobs.py:918
|
||||
#: instances/jobs.py:925
|
||||
#, python-format
|
||||
msgid "The instance is already on %(compute)s"
|
||||
msgstr "虚拟机已在 %(compute)s 上"
|
||||
|
||||
#: instances/jobs.py:920
|
||||
#: instances/jobs.py:927
|
||||
#, python-format
|
||||
msgid "%(compute)s is not reachable"
|
||||
msgstr "无法连接 %(compute)s"
|
||||
|
||||
#: instances/jobs.py:922
|
||||
#: instances/jobs.py:929
|
||||
#, python-format
|
||||
msgid "%(compute)s is the VM's own host under another name"
|
||||
msgstr "%(compute)s 是该虚拟机所在主机的另一个名称"
|
||||
|
||||
#: instances/jobs.py:940
|
||||
#: instances/jobs.py:947
|
||||
msgid "Migrate VM"
|
||||
msgstr "迁移虚拟机"
|
||||
|
||||
#: instances/jobs.py:984
|
||||
#: instances/jobs.py:991
|
||||
msgid "Migrating the VM"
|
||||
msgstr "正在迁移虚拟机"
|
||||
|
||||
#: instances/jobs.py:1031
|
||||
#: instances/jobs.py:1038
|
||||
msgid "libvirt is still migrating the VM"
|
||||
msgstr "libvirt 仍在迁移虚拟机"
|
||||
|
||||
#: instances/jobs.py:1038
|
||||
#: instances/jobs.py:1045
|
||||
msgid "The VM stayed on the source host"
|
||||
msgstr "虚拟机留在了源主机上"
|
||||
|
||||
#: instances/jobs.py:1040
|
||||
#: instances/jobs.py:1047
|
||||
msgid ""
|
||||
"The VM is on both computes or on neither; check them, then resolve this job."
|
||||
msgstr "虚拟机同时位于两个计算节点上,或都不在;请检查后处理此任务。"
|
||||
|
||||
#: instances/jobs.py:1088
|
||||
#: instances/jobs.py:1095
|
||||
msgid "Move disk"
|
||||
msgstr "移动磁盘"
|
||||
|
||||
#: instances/jobs.py:1095
|
||||
#: instances/jobs.py:1102
|
||||
msgid "Choose a disk of the VM"
|
||||
msgstr "请选择虚拟机的一个磁盘"
|
||||
|
||||
#: instances/jobs.py:1119
|
||||
#: instances/jobs.py:1126
|
||||
msgid "Copying the disk"
|
||||
msgstr "正在复制磁盘"
|
||||
|
||||
#: instances/jobs.py:1162
|
||||
#: instances/jobs.py:1169
|
||||
#, python-format
|
||||
msgid "Another block job runs on %(dev)s; check the VM"
|
||||
msgstr "%(dev)s 上正在运行另一个块任务;请检查虚拟机"
|
||||
|
||||
#: instances/jobs.py:1168
|
||||
#: instances/jobs.py:1175
|
||||
#, python-format
|
||||
msgid "The disk stayed in %(path)s; remove %(dest)s if it is there"
|
||||
msgstr "磁盘仍在 %(path)s;如果 %(dest)s 存在,请将其删除"
|
||||
|
||||
#: instances/jobs.py:1170
|
||||
#: instances/jobs.py:1177
|
||||
#, python-format
|
||||
msgid "The definitions of %(dev)s name %(paths)s; check the VM"
|
||||
msgstr "%(dev)s 的定义指向 %(paths)s;请检查虚拟机"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue