From 432b1505b3526def7867226bb466fc01d692a590 Mon Sep 17 00:00:00 2001 From: catborise Date: Fri, 6 Nov 2026 23:10:59 +0300 Subject: [PATCH] fix(operations): a job's unexpected error is not shown raw; the log has its traceback A job that failed on an exception that is not libvirt's or a refusal showed its raw text to users (a SQL error such as "UNIQUE constraint failed: instances_instance.uuid", a KeyError's key), and the worker logged only that text. Users now read "The panel failed unexpectedly; its log has the details." and the worker logs the exception with its traceback. A live clone whose recovery found the clone made but could not thaw the source's file systems kept that in the error of a succeeded job, which the job panel does not show. It is a warning of the clone's result, as when the job itself made the clone. --- instances/jobs.py | 11 +- instances/tests/test_clone_job.py | 10 ++ instances/tests/test_create_job.py | 18 ++ locale/tr/LC_MESSAGES/django.mo | Bin 192542 -> 192936 bytes locale/tr/LC_MESSAGES/django.po | 279 +++++++++++++++-------------- locale/zh/LC_MESSAGES/django.mo | Bin 180056 -> 180396 bytes locale/zh/LC_MESSAGES/django.po | 276 ++++++++++++++-------------- operations/tests/test_worker.py | 19 +- operations/utils.py | 22 +++ operations/worker.py | 17 +- 10 files changed, 375 insertions(+), 277 deletions(-) diff --git a/instances/jobs.py b/instances/jobs.py index 1a22ca17..1956a0bf 100644 --- a/instances/jobs.py +++ b/instances/jobs.py @@ -31,7 +31,7 @@ from instances import utils from instances.models import Instance from logs.audit import write from operations import claims -from operations.utils import safe_text, say +from operations.utils import REPORTED, safe_text, say from operations.jobs import Cancelled, Kind, Outcome, Plan, register from operations.models import Claim, Operation @@ -666,7 +666,10 @@ class CloneInstance(Kind): except libvirtError as err: thawed = say(THAW_FAILED, error=err, vm=op.resource_label.rpartition("/")[2]) outcome = self._live_outcome(proxy, op) - outcome.error += thawed + if thawed and outcome.state == Operation.SUCCEEDED: # a warning of the clone, as when the job made it + outcome.result["warning"] = [*outcome.result.get("warning", []), *thawed] + else: + outcome.error += thawed return outcome def _live_outcome(self, proxy, op): @@ -899,6 +902,10 @@ class CreateInstance(Kind): conn.delete_volume(path) except libvirtError: leftovers.append(path) + if leftovers and not isinstance(err, REPORTED): # a fault of the panel is not shown as it is + raise util.OperationError(_("The panel failed unexpectedly; its log has the details. " + "Remove these volumes by hand: %(volumes)s"), + volumes=", ".join(leftovers)) from err if leftovers: raise util.OperationError(_("%(error)s. Remove these volumes by hand: %(volumes)s"), error=err, volumes=", ".join(leftovers)) from err diff --git a/instances/tests/test_clone_job.py b/instances/tests/test_clone_job.py index c3cd21b4..bbcd6eeb 100644 --- a/instances/tests/test_clone_job.py +++ b/instances/tests/test_clone_job.py @@ -621,6 +621,16 @@ class LiveCloneJobTestCase(TransactionTestCase): self.proxy.resize_mem.assert_not_called() self.proxy.start.assert_called_once_with() + def test_a_thaw_that_fails_in_the_recovery_of_a_made_clone_is_a_warning_of_the_clone(self): + # the job panel shows a succeeded job's warning; an error of it was not shown + self.proxy.get_status.return_value = 1 + self.proxy.fs_thaw.side_effect = libvirt_error(libvirt.VIR_ERR_AGENT_UNRESPONSIVE) + self.proxy.backup_result.return_value = None + self.proxy.backup_targets.return_value = {"/other/x.qcow2"} + outcome, _op = self.recovered(defined=True, frozen=True) + self.assertEqual((outcome.state, outcome.error), (Operation.SUCCEEDED, [])) + self.assertIn("virsh domfsthaw", words(outcome.result["warning"])) + def test_recovery_of_a_defined_clone_succeeds(self): self.proxy.backup_result.return_value = None # libvirtd restarted after the clone was defined self.proxy.backup_targets.return_value = {"/other/x.qcow2"} # checked after it diff --git a/instances/tests/test_create_job.py b/instances/tests/test_create_job.py index dbb25923..49ed0926 100644 --- a/instances/tests/test_create_job.py +++ b/instances/tests/test_create_job.py @@ -16,6 +16,8 @@ from instances.models import Instance from instances.tests.create_page import BODY from operations.jobs import Context from operations.models import Operation, acquire +from operations.utils import traceback_of +from vrtManager.util import OperationError class CreateJobTestCase(TransactionTestCase): @@ -100,6 +102,22 @@ class CreateJobTestCase(TransactionTestCase): self.assertEqual(response.status_code, 409) self.assertEqual(Operation.objects.count(), 1) + def test_a_fault_of_the_panel_with_volumes_left_is_not_shown_as_it_is(self): + # its text names nothing users can act on; the volumes to remove are + self.client.post(f"/api/v1/computes/{self.compute.pk}/instances/create/x86_64/q35/", BODY, + content_type="application/json") + op = Operation.objects.get() + acquire("wvc-test:1:a", "wvc-test") + Operation.objects.filter(pk=op.pk).update(state=Operation.RUNNING, worker="wvc-test:1:a") + op.refresh_from_db() + self.conn.create_instance.side_effect = RuntimeError("no such bus") + self.conn.delete_volume.side_effect = libvirt.libvirtError("volume is busy") + with self.assertRaises(OperationError) as raised: + CreateInstance().run(op, Context(op, SimpleNamespace(identity="wvc-test:1:a"))) + self.assertEqual(str(raised.exception), "The panel failed unexpectedly; its log has the details. " + "Remove these volumes by hand: /srv/default/api-vm.qcow2") + self.assertIn("RuntimeError: no such bus", traceback_of(raised.exception)) + @patch("instances.jobs.wvmConnect") def test_a_create_that_left_nothing_failed(self, conn): op = Operation(params={**BODY, "template": ""}, diff --git a/locale/tr/LC_MESSAGES/django.mo b/locale/tr/LC_MESSAGES/django.mo index 17c8e0667c3ba65fb2cfb3f4aa6f476a949c8def..459b4e794b7c16da5692ab1fe32fa9ea331c9212 100644 GIT binary patch delta 35997 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 delta 35696 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%0Dgx`%cExtoTG@vs@VL!? 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, 2020\n" "Language-Team: Turkish (https://www.transifex.com/catborise/teams/110663/tr/)\n" @@ -162,13 +162,13 @@ msgid "User Profile" msgstr "Kullanıcı Profili" #: accounts/templates/account.html:17 accounts/templates/profile.html:18 -#: admin/forms.py:73 admin/templates/admin/user_list.html:24 +#: admin/forms.py:74 admin/templates/admin/user_list.html:24 #: admin/templates/admin/user_list.html:30 msgid "Superuser" msgstr "Süperkullanıcı" #: accounts/templates/account.html:19 accounts/templates/profile.html:20 -#: admin/forms.py:73 admin/templates/admin/user_list.html:24 +#: admin/forms.py:74 admin/templates/admin/user_list.html:24 #: admin/templates/admin/user_list.html:32 msgid "Template editor" msgstr "Şablon düzenleyici" @@ -201,7 +201,7 @@ msgid "User sections" msgstr "Kullanıcı bölümleri" #: accounts/templates/account.html:44 accounts/templates/account.html:52 -#: admin/forms.py:185 computes/templates/computes/list.html:30 +#: admin/forms.py:188 computes/templates/computes/list.html:30 #: computes/templates/computes/list.html:57 computes/templates/overview.html:46 msgid "VMs" msgstr "Sanal makineler" @@ -654,11 +654,11 @@ msgstr "OTP QR kodu %(user)s kullanıcısına gönderildi" msgid "User email not set, failed to send QR code" msgstr "Kullanıcı e-postası girilmemiş, QR kod gönderimi başarısız" -#: admin/forms.py:20 +#: admin/forms.py:21 msgid "Change their own password on their profile page" msgstr "Profil sayfasında kendi parolasını değiştirme" -#: admin/forms.py:21 +#: admin/forms.py:22 msgid "" "Clone the VMs they may change and the templates they may view, within their " "quota" @@ -666,21 +666,21 @@ msgstr "" "Kotası dahilinde, değiştirebildiği sanal makineleri ve görebildiği şablonları" " klonlama" -#: admin/forms.py:22 +#: admin/forms.py:23 msgid "Open a console without the VM's console password" msgstr "Sanal makinenin konsol parolası olmadan konsol aç" -#: admin/forms.py:23 +#: admin/forms.py:24 msgid "Take, revert and delete snapshots of the VMs they may change" msgstr "" "Değiştirebildiği sanal makinelerin anlık görüntülerini alma, geri yükleme ve " "silme" -#: admin/forms.py:24 +#: admin/forms.py:25 msgid "See every VM and host in the lists, read-only" msgstr "Listelerde tüm sanal makineleri ve sunucuları salt okunur görme" -#: admin/forms.py:73 admin/templates/admin/logs.html:39 +#: admin/forms.py:74 admin/templates/admin/logs.html:39 #: admin/templates/admin/user_list.html:24 #: admin/templates/admin/user_list.html:34 #: computes/templates/computes/instances.html:46 @@ -692,24 +692,24 @@ msgstr "Listelerde tüm sanal makineleri ve sunucuları salt okunur görme" msgid "User" msgstr "Kullanıcı" -#: admin/forms.py:80 admin/templates/admin/group_form.html:30 +#: admin/forms.py:81 admin/templates/admin/group_form.html:30 msgid "Permissions" msgstr "İzinler" -#: admin/forms.py:87 admin/templates/admin/group_list.html:6 +#: admin/forms.py:88 admin/templates/admin/group_list.html:6 #: admin/templates/admin/group_list.html:8 #: admin/templates/admin/group_list.html:24 #: admin/templates/admin/user_form.html:123 templates/navbar.html:33 msgid "Groups" msgstr "Gruplar" -#: admin/forms.py:139 +#: admin/forms.py:142 #, python-format msgid "NEW_USER_DEFAULT_INSTANCES: %(name)s is not exactly one VM" msgstr "" "NEW_USER_DEFAULT_INSTANCES: %(name)s tam olarak tek bir sanal makine değil" -#: admin/forms.py:186 computes/templates/computes/list.html:58 +#: admin/forms.py:189 computes/templates/computes/list.html:58 #: computes/templates/overview.html:58 instances/forms.py:14 #: instances/templates/allinstances_index_grouped.html:16 #: instances/templates/allinstances_index_nongrouped.html:14 @@ -719,7 +719,7 @@ msgstr "" msgid "vCPUs" msgstr "vCPU" -#: admin/forms.py:187 computes/templates/computes/instances.html:49 +#: admin/forms.py:190 computes/templates/computes/instances.html:49 #: computes/templates/computes/list.html:59 computes/templates/overview.html:66 #: computes/templates/overview.html:150 #: instances/templates/allinstances_index_grouped.html:17 @@ -731,34 +731,34 @@ msgstr "vCPU" msgid "Memory" msgstr "Bellek" -#: admin/forms.py:188 instances/models.py:235 +#: admin/forms.py:191 instances/models.py:235 #: instances/templates/create_instance_w2.html:118 #: instances/templates/instances/settings_tab.html:25 #: instances/templates/instances/stats_tab.html:51 msgid "Disk" msgstr "Disk" -#: admin/forms.py:198 +#: admin/forms.py:201 msgid "No limit" msgstr "Sınır yok" -#: admin/forms.py:214 +#: admin/forms.py:217 msgid "Enter a limit or choose No limit." msgstr "Bir sınır girin ya da Sınır yok'u seçin." -#: admin/forms.py:226 +#: admin/forms.py:229 msgid "The user must change it at their next login" msgstr "Kullanıcı bir sonraki girişinde onu değiştirmek zorundadır" -#: admin/forms.py:232 +#: admin/forms.py:235 msgid "With a password" msgstr "Parolayla" -#: admin/forms.py:232 +#: admin/forms.py:235 msgid "Without a password" msgstr "Parolasız" -#: admin/forms.py:238 +#: admin/forms.py:241 msgid "A user without a password cannot be made to change it" msgstr "Parolası olmayan bir kullanıcıya parola değiştirme zorunluluğu konamaz" @@ -2590,23 +2590,23 @@ msgstr "%%(name)s tarafından devralındı" msgid "Connected. If the VM shows nothing, press Enter." msgstr "Bağlandı. Sanal makine hiçbir şey göstermiyorsa Enter'a basın." -#: console/views.py:43 +#: console/views.py:48 msgid "" "User does not have permission to access console or host/instance not exist" msgstr "" "Kullanıcının konsola erişim izni yok ya da sunucu/sanal makine mevcut değil" -#: console/views.py:69 +#: console/views.py:78 msgid "Fail to get console. Please check the console configuration of your VM." msgstr "" "Konsola erişim başarısız. Lütfen sanal makinenizin konsol yapılandırmasını " "kontrol ediniz." -#: console/views.py:71 +#: console/views.py:80 msgid "The VM is not running: start it to open its console." msgstr "Sanal makine çalışmıyor: konsolunu açmak için başlatın." -#: console/views.py:74 +#: console/views.py:83 msgid "" "This console listens only on its host, which the panel reaches over TCP or " "TLS. Let the console listen on all interfaces in the VM's console settings, " @@ -2617,7 +2617,7 @@ msgstr "" "arabirimlerde dinlemesini sağlayın ya da sunucuyu SSH sunucusu olarak " "ekleyin." -#: console/views.py:80 +#: console/views.py:89 msgid "" "Serial console is disabled on this server. Please switch VM graphics to VNC " "or ask an administrator." @@ -2625,7 +2625,7 @@ msgstr "" "Seri konsol bu sunucuda devre dışı. Lütfen sanal makinenin grafiklerini " "VNC'ye çevirin ya da bir yöneticiye başvurun." -#: console/views.py:85 +#: console/views.py:94 #, python-format msgid "" "Console type '%(type)s' is not supported. Please switch the VM graphics to " @@ -2856,7 +2856,7 @@ msgstr "" msgid "Clone VM" msgstr "Sanal makineyi klonla" -#: instances/jobs.py:562 instances/jobs.py:569 instances/jobs.py:844 +#: instances/jobs.py:562 instances/jobs.py:569 instances/jobs.py:847 msgid "Copying disks" msgstr "Diskler kopyalanıyor" @@ -2873,7 +2873,7 @@ msgstr "" "Kopyalama başarısız oldu: %(error)s. Konuğun dosya sistemleri çözülemedi " "(%(thaw)s); şununla çözün: virsh domfsthaw %(vm)s" -#: instances/jobs.py:635 instances/jobs.py:719 +#: instances/jobs.py:635 instances/jobs.py:722 msgid "The copy failed" msgstr "Kopyalama başarısız oldu" @@ -2886,7 +2886,7 @@ msgstr "" "Sanal makine artık işin çalıştığı sunucuda değil; şu birimleri kontrol edin, " "sonra bu işi çözün: %(volumes)s" -#: instances/jobs.py:695 +#: instances/jobs.py:698 #, python-format msgid "" "A volume of the clone was being created; check these volumes, then resolve " @@ -2895,15 +2895,15 @@ msgstr "" "Klonun bir birimi oluşturuluyordu; şu birimleri kontrol edin, sonra bu işi " "çözün: %(volumes)s" -#: instances/jobs.py:699 +#: instances/jobs.py:702 msgid "The job stopped before the copy started" msgstr "İş, kopyalama başlamadan durdu" -#: instances/jobs.py:706 +#: instances/jobs.py:709 msgid "libvirt is still copying the disks" msgstr "libvirt diskleri hâlâ kopyalıyor" -#: instances/jobs.py:709 +#: instances/jobs.py:712 #, python-format msgid "" "Another backup runs on the VM; check these volumes, then resolve this job: " @@ -2912,7 +2912,7 @@ msgstr "" "Sanal makinede başka bir yedekleme çalışıyor; şu birimleri kontrol edin, " "sonra bu işi çözün: %(volumes)s" -#: instances/jobs.py:714 +#: instances/jobs.py:717 #, python-format msgid "" "libvirt has no result of the copy; check these volumes, then resolve this " @@ -2921,7 +2921,7 @@ msgstr "" "libvirt'te kopyanın sonucu yok; şu birimleri kontrol edin, sonra bu işi " "çözün: %(volumes)s" -#: instances/jobs.py:726 +#: instances/jobs.py:729 #, python-format msgid "" "The disks were copied, but the clone could not be defined: %(error)s; check " @@ -2930,181 +2930,191 @@ msgstr "" "Diskler kopyalandı, ancak klon tanımlanamadı: %(error)s; şu birimleri kontrol" " edin, sonra bu işi çözün: %(volumes)s" -#: instances/jobs.py:749 instances/templates/create_instance_w1.html:60 +#: instances/jobs.py:752 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:773 instances/jobs.py:818 instances/views.py:2463 +#: instances/jobs.py:776 instances/jobs.py:821 instances/views.py:2463 msgid "A virtual machine with this name already exists" msgstr "Bu isimde bir sanal makine mevcut" -#: instances/jobs.py:775 instances/jobs.py:815 +#: instances/jobs.py:778 instances/jobs.py:818 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:778 +#: instances/jobs.py:781 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:780 +#: instances/jobs.py:783 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:782 +#: instances/jobs.py:785 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:784 +#: instances/jobs.py:787 msgid "Invalid cache mode" msgstr "Geçersiz önbellek modu" -#: instances/jobs.py:786 +#: instances/jobs.py:789 #, 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:788 +#: instances/jobs.py:791 #, python-format msgid "A CD-ROM cannot use the %(bus)s bus" msgstr "CD-ROM %(bus)s veri yolunu kullanamaz" -#: instances/jobs.py:791 +#: instances/jobs.py:794 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:794 +#: instances/jobs.py:797 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:800 +#: instances/jobs.py:803 #, python-format msgid "This host offers no firmware %(firmware)s" msgstr "Bu sunucu %(firmware)s firmware'ini sunmuyor" -#: instances/jobs.py:802 vrtManager/instance.py:3011 +#: instances/jobs.py:805 vrtManager/instance.py:3015 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:863 +#: instances/jobs.py:866 msgid "Writing the cloud-init seed" msgstr "cloud-init tohumu yazılıyor" -#: instances/jobs.py:870 +#: instances/jobs.py:873 msgid "Defining the VM" msgstr "Sanal makine tanımlanıyor" -#: instances/jobs.py:903 +#: instances/jobs.py:906 +#, python-format +#| msgid "The panel failed unexpectedly; its log has the details." +msgid "" +"The panel failed unexpectedly; its log has the details. Remove these volumes " +"by hand: %(volumes)s" +msgstr "" +"Panel beklenmedik bir hatayla karşılaştı; ayrıntılar panelin günlüğünde. Bu " +"birimleri elle kaldırın: %(volumes)s" + +#: instances/jobs.py:910 #, python-format msgid "%(error)s. Remove these volumes by hand: %(volumes)s" msgstr "%(error)s. Şu birimleri elle silin: %(volumes)s" -#: instances/jobs.py:928 +#: instances/jobs.py:935 #, python-format msgid "The instance is already on %(compute)s" msgstr "Sanal makine zaten %(compute)s üzerinde" -#: instances/jobs.py:930 +#: instances/jobs.py:937 #, python-format msgid "%(compute)s is not reachable" msgstr "%(compute)s sunucusuna ulaşılamıyor" -#: instances/jobs.py:932 +#: instances/jobs.py:939 #, 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:966 +#: instances/jobs.py:973 #, python-format msgid "" "The VM migrated, but autostart could not be set on the destination: %(error)s" msgstr "" "Sanal makine taşındı, ancak hedefte otomatik başlatma ayarlanamadı: %(error)s" -#: instances/jobs.py:972 +#: instances/jobs.py:979 #, python-format msgid "The VM migrated, but its NVRAM file stays on the source: %(error)s" msgstr "Sanal makine taşındı, ancak NVRAM dosyası kaynakta kaldı: %(error)s" -#: instances/jobs.py:979 +#: instances/jobs.py:986 msgid "Migrate VM" msgstr "Sanal makineyi taşı" -#: instances/jobs.py:1026 +#: instances/jobs.py:1033 msgid "Migrating the VM" msgstr "Sanal makine taşınıyor" -#: instances/jobs.py:1073 +#: instances/jobs.py:1080 msgid "libvirt is still migrating the VM" msgstr "libvirt sanal makineyi hâlâ taşıyor" -#: instances/jobs.py:1084 +#: instances/jobs.py:1091 msgid "The VM stayed on the source host" msgstr "Sanal makine kaynak sunucuda kaldı" -#: instances/jobs.py:1086 +#: instances/jobs.py:1093 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:1134 +#: instances/jobs.py:1141 msgid "Move disk" msgstr "Diski taşı" -#: instances/jobs.py:1141 +#: instances/jobs.py:1148 msgid "Choose a disk of the VM" msgstr "Sanal makinenin bir diskini seçin" -#: instances/jobs.py:1165 +#: instances/jobs.py:1172 msgid "Copying the disk" msgstr "Disk kopyalanıyor" -#: instances/jobs.py:1208 +#: instances/jobs.py:1215 #, 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:1214 +#: instances/jobs.py:1221 #, 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:1216 +#: instances/jobs.py:1223 #, 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" -#: instances/jobs.py:1223 +#: instances/jobs.py:1230 #, python-format msgid "Disk %(path)s was kept: a disk file that stays needs it" msgstr "%(path)s diski korundu: kalan bir disk dosyası ona ihtiyaç duyuyor" -#: instances/jobs.py:1224 +#: instances/jobs.py:1231 #, python-format msgid "The VM is removed, but disk %(path)s was not deleted: %(err)s" msgstr "Sanal makine kaldırıldı, ancak %(path)s diski silinmedi: %(err)s" -#: instances/jobs.py:1225 +#: instances/jobs.py:1232 #, python-format msgid "Disk %(path)s is used by another VM and was kept" msgstr "" "%(path)s diski başka bir sanal makine tarafından kullanılıyor ve korundu" -#: instances/jobs.py:1279 +#: instances/jobs.py:1286 msgid "Delete VM" msgstr "Sanal makineyi sil" -#: instances/jobs.py:1309 +#: instances/jobs.py:1316 msgid "Deleting the VM" msgstr "Sanal makine siliniyor" -#: instances/jobs.py:1321 +#: instances/jobs.py:1328 msgid "The VM was not deleted; it may have been shut off" msgstr "Sanal makine silinmedi; kapatılmış olabilir" @@ -6258,7 +6268,7 @@ msgstr "Bir ağ arabirimi ve bir QoS yönü seçin" msgid "QoS rates must be whole numbers" msgstr "QoS hızları tam sayı olmalıdır" -#: instances/views.py:2197 networks/views.py:229 +#: instances/views.py:2197 networks/views.py:230 #, python-format msgid "%(qos_dir)s QoS is set" msgstr "%(qos_dir)s QoS ayarlandı" @@ -6271,7 +6281,7 @@ msgstr "" "%(qos_dir)s QoS ayarlandı. Çalışan bir sanal makine, kapatılıp açıldıktan " "sonra bunu alır." -#: instances/views.py:2224 networks/views.py:255 +#: instances/views.py:2224 networks/views.py:256 #, python-format msgid "%(qos_dir)s QoS is deleted" msgstr "%(qos_dir)s QoS silindi" @@ -6460,7 +6470,7 @@ msgstr "" "katılabilir." #: interfaces/templates/create_iface_block.html:30 -#: interfaces/templates/create_iface_block.html:75 interfaces/views.py:31 +#: interfaces/templates/create_iface_block.html:75 interfaces/views.py:32 msgid "Ethernet" msgstr "Ethernet" @@ -6694,19 +6704,19 @@ msgstr "Bağlantı %(link)s" msgid "Link unknown" msgstr "Bağlantı durumu bilinmiyor" -#: interfaces/views.py:30 +#: interfaces/views.py:31 msgid "Bridges" msgstr "Köprüler" -#: interfaces/views.py:30 +#: interfaces/views.py:31 msgid "Bonds" msgstr "Bond'lar" -#: interfaces/views.py:31 +#: interfaces/views.py:32 msgid "VLANs" msgstr "VLAN'lar" -#: interfaces/views.py:45 +#: interfaces/views.py:46 #, python-format msgid "The network devices of this host could not be read: %(error)s" msgstr "Bu sunucunun ağ aygıtları okunamadı: %(error)s" @@ -7260,35 +7270,35 @@ msgstr "SR-IOV" msgid "VMs get a virtual function of the host's network card." msgstr "Sanal makineler sunucunun ağ kartının bir sanal işlevini alır." -#: networks/views.py:166 +#: networks/views.py:167 msgid "The fixed address is unchanged" msgstr "Sabit adres değişmedi" -#: networks/views.py:168 +#: networks/views.py:169 #, python-format msgid "The fixed address %(address)s is set" msgstr "%(address)s sabit adresi ayarlandı" -#: networks/views.py:177 +#: networks/views.py:178 #, python-format msgid "The fixed address %(address)s is deleted" msgstr "%(address)s sabit adresi silindi" -#: networks/views.py:185 +#: networks/views.py:186 msgid "The DHCP range is changed" msgstr "DHCP aralığı değiştirildi" -#: networks/views.py:202 +#: networks/views.py:203 msgid "Network XML is changed. Stop and start network to activate new config." msgstr "" "Ağ XML'i değiştirildi. Yeni yapılandırmayı etkinleştirmek için ağı durdurup " "başlatın." -#: networks/views.py:207 +#: networks/views.py:208 msgid "Network XML is changed." msgstr "Ağ XML i değiştirildi." -#: networks/views.py:222 +#: networks/views.py:223 #, python-format msgid "" "%(qos_dir)s QoS is updated. Network XML is changed. Stop and start network to" @@ -7297,7 +7307,7 @@ msgstr "" "%(qos_dir)s QoS is updated.Ağ XML i değiştirildi. \\ Aktifleştirmek için " "durdurun ve yeniden başlatın." -#: networks/views.py:247 +#: networks/views.py:248 #, python-format msgid "" "%(qos_dir)s QoS is deleted. Network XML is changed. Stop and start network to" @@ -7824,11 +7834,11 @@ msgstr "İptal edilemedi (HTTP %(status)s)." msgid "Cancel failed: the server could not be reached." msgstr "İptal edilemedi: sunucuya ulaşılamadı." -#: operations/utils.py:54 +#: operations/utils.py:55 msgid "The host of this virtual machine cannot be reached right now." msgstr "Bu sanal makinenin sunucusuna şu anda ulaşılamıyor." -#: operations/utils.py:55 +#: operations/utils.py:56 msgid "" "The host of this virtual machine is busy with other requests right now: try " "again in a moment." @@ -7836,20 +7846,25 @@ msgstr "" "Bu sanal makinenin sunucusu şu anda başka isteklerle meşgul: biraz sonra " "yeniden deneyin." -#: operations/utils.py:57 +#: operations/utils.py:58 msgid "You may no longer do this." msgstr "Bunu artık yapamazsınız." -#: operations/utils.py:58 +#: operations/utils.py:59 msgid "The virtual machine is no longer in the panel." msgstr "Sanal makine artık panelde yok." -#: operations/utils.py:169 +#: operations/utils.py:127 +msgid "The panel failed unexpectedly; its log has the details." +msgstr "" +"Panel beklenmedik bir hatayla karşılaştı; ayrıntılar panelin günlüğünde." + +#: operations/utils.py:191 msgid "" "A short operation is in progress on this resource; try again in a moment." msgstr "Bu kaynakta kısa bir işlem sürüyor; birazdan yeniden deneyin." -#: operations/utils.py:172 +#: operations/utils.py:194 #, python-format msgid "" "%(label)s is %(state)s on this resource (started by %(user)s, %(since)s ago);" @@ -7858,12 +7873,12 @@ msgstr "" "%(label)s bu kaynakta %(state)s (%(user)s başlattı, %(since)s önce); İşler " "sayfasına bakın." -#: operations/utils.py:174 +#: operations/utils.py:196 #, python-format msgid "%(label)s is %(state)s on this resource (since %(since)s)." msgstr "%(label)s bu kaynakta %(state)s (%(since)s beri)." -#: operations/worker.py:42 +#: operations/worker.py:43 msgid "" "libvirt's merge finished copying but never completed (for example after a " "libvirtd restart); check the VM before resolving" @@ -7872,7 +7887,7 @@ msgstr "" "libvirtd yeniden başlatıldıktan sonra); çözmeden önce sanal makineyi kontrol " "edin" -#: operations/worker.py:44 +#: operations/worker.py:45 msgid "" "The worker that ran this job stopped responding; an administrator must make " "sure it is no longer running, then resolve this job" @@ -7880,11 +7895,11 @@ msgstr "" "Bu işi çalıştıran worker yanıt vermeyi bıraktı; bir yönetici artık " "çalışmadığından emin olmalı, sonra bu işi çözmeli" -#: operations/worker.py:46 +#: operations/worker.py:47 msgid "Waiting for recovery" msgstr "Kurtarma bekleniyor" -#: operations/worker.py:48 +#: operations/worker.py:49 msgid "" "Recovery could not read the job's state for an hour; check the VM, then " "resolve this job" @@ -7892,7 +7907,7 @@ msgstr "" "Kurtarma bir saat boyunca işin durumunu okuyamadı; sanal makineyi kontrol " "edin, sonra bu işi çözün" -#: operations/worker.py:473 +#: operations/worker.py:474 msgid "The worker stopped before the job changed anything" msgstr "Worker, iş herhangi bir şeyi değiştirmeden önce durdu" @@ -8446,12 +8461,12 @@ msgstr "Yükleme oturumu meşgul. Lütfen yeniden deneyin." msgid "ISO image already exists" msgstr "ISO imajı zaten mevcut" -#: storages/views.py:178 +#: storages/views.py:179 #, python-format msgid "Volume: %(vol)s is deleted." msgstr "Birim: %(vol)s silindi." -#: storages/views.py:196 +#: storages/views.py:197 #, python-format msgid "Image file %(name)s is created successfully" msgstr "İmaj dosyası %(name)s başarıyla oluşturuldu" @@ -9240,64 +9255,64 @@ msgstr "" msgid "Shut the VM down to revert to an internal snapshot" msgstr "Dahili bir anlık görüntüye geri dönmek için sanal makineyi kapatın" -#: vrtManager/instance.py:2403 +#: vrtManager/instance.py:2407 msgid "Cannot clone a VM whose NVRAM is not a file" msgstr "NVRAM'i dosya olmayan bir sanal makine klonlanamaz" -#: vrtManager/instance.py:2471 +#: vrtManager/instance.py:2475 #, python-format msgid "Clone failed (%(err)s); remove these copies by hand: %(path)s" msgstr "" "Klonlama başarısız oldu (%(err)s); bu kopyaları elle kaldırın: %(path)s" -#: vrtManager/instance.py:2481 +#: vrtManager/instance.py:2485 msgid "Shut the VM down before cloning it" msgstr "Klonlamadan önce sanal makineyi kapatın" -#: vrtManager/instance.py:2535 +#: vrtManager/instance.py:2539 #, python-format msgid "Clone failed (%(err)s); remove these copies by hand: %(leftovers)s" msgstr "" "Klonlama başarısız oldu (%(err)s); bu kopyaları elle kaldırın: %(leftovers)s" -#: vrtManager/instance.py:2546 +#: vrtManager/instance.py:2550 msgid "Live clone needs libvirt 11.10 or later; shut the VM down to clone it" msgstr "" "Canlı klonlama libvirt 11.10 veya sonrasını gerektirir; klonlamak için sanal " "makineyi kapatın" -#: vrtManager/instance.py:2549 +#: vrtManager/instance.py:2553 msgid "A VM with a TPM is cloned only shut down" msgstr "TPM'i olan bir sanal makine yalnızca kapalıyken klonlanır" -#: vrtManager/instance.py:2552 +#: vrtManager/instance.py:2556 #, python-format msgid "Disk %(dev)s is not a local file; shut the VM down to clone it" msgstr "" "Disk %(dev)s yerel bir dosya değil; klonlamak için sanal makineyi kapatın" -#: vrtManager/instance.py:2554 +#: vrtManager/instance.py:2558 #, python-format msgid "Disk %(dev)s is shareable; shut the VM down to clone it" msgstr "Disk %(dev)s paylaşılabilir; klonlamak için sanal makineyi kapatın" -#: vrtManager/instance.py:2559 +#: vrtManager/instance.py:2563 #, python-format msgid "Disk %(dev)s changes at the next start; shut the VM down to clone it" msgstr "" "Disk %(dev)s sonraki başlatmada değişiyor; klonlamak için sanal makineyi " "kapatın" -#: vrtManager/instance.py:2561 +#: vrtManager/instance.py:2565 msgid "Another job is running on the VM; clone it when that ends" msgstr "Sanal makinede başka bir iş çalışıyor; o bittiğinde klonlayın" -#: vrtManager/instance.py:2574 +#: vrtManager/instance.py:2578 #, python-format msgid "Volume %(name)s already exists in storage pool %(pool)s" msgstr "%(name)s birimi %(pool)s depolama havuzunda zaten var" -#: vrtManager/instance.py:2593 +#: vrtManager/instance.py:2597 #, python-format msgid "" "Storage pool %(pool)s has %(free).1f GiB free; the clone needs %(size).1f GiB" @@ -9307,20 +9322,20 @@ msgstr "" "gerektiriyor (kopyalanan diskler, artı bunların %%%(percent)g kadarı, en az " "%(minimum)g GiB)" -#: vrtManager/instance.py:2732 +#: vrtManager/instance.py:2736 msgid "A network interface that is a host device is removed in the XML editor" msgstr "Sunucu aygıtı olan bir ağ arabirimi XML düzenleyicide kaldırılır" -#: vrtManager/instance.py:2748 +#: vrtManager/instance.py:2752 #, python-format msgid "No network interface with MAC %(old_mac)s" msgstr "MAC adresi %(old_mac)s olan ağ arabirimi yok" -#: vrtManager/instance.py:2751 +#: vrtManager/instance.py:2755 msgid "A network interface that is a host device is changed in the XML editor" msgstr "Sunucu aygıtı olan bir ağ arabirimi XML düzenleyicide değiştirilir" -#: vrtManager/instance.py:2842 +#: vrtManager/instance.py:2846 msgid "" "A VM changes its PCI devices while it runs, or is shut off without a saved " "state" @@ -9328,14 +9343,14 @@ msgstr "" "Sanal makine PCI aygıtlarını çalışırken veya kaydedilmiş durumu olmadan " "kapalıyken değiştirir" -#: vrtManager/instance.py:2854 +#: vrtManager/instance.py:2858 #, python-format msgid "%(err)s; whether the VM has PCI device %(address)s now is not known" msgstr "" "%(err)s; sanal makinede şu anda %(address)s PCI aygıtının olup olmadığı " "bilinmiyor" -#: vrtManager/instance.py:2856 +#: vrtManager/instance.py:2860 #, python-format msgid "" "%(err)s; PCI device %(address)s: the VM is not running, its next start has it" @@ -9343,7 +9358,7 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: sanal makine çalışmıyor, sonraki başlatmada " "var" -#: vrtManager/instance.py:2858 +#: vrtManager/instance.py:2862 #, python-format msgid "" "%(err)s; PCI device %(address)s: the VM is not running, its next start does " @@ -9352,7 +9367,7 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: sanal makine çalışmıyor, sonraki başlatmada " "yok" -#: vrtManager/instance.py:2859 +#: vrtManager/instance.py:2863 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM has it, its next start has it" @@ -9360,7 +9375,7 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: çalışan sanal makinede var, sonraki " "başlatmada var" -#: vrtManager/instance.py:2861 +#: vrtManager/instance.py:2865 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM has it, its next start does " @@ -9369,7 +9384,7 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: çalışan sanal makinede var, sonraki " "başlatmada yok" -#: vrtManager/instance.py:2863 +#: vrtManager/instance.py:2867 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM does not have it, its next " @@ -9378,7 +9393,7 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: çalışan sanal makinede yok, sonraki " "başlatmada var" -#: vrtManager/instance.py:2865 +#: vrtManager/instance.py:2869 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM does not have it, its next " @@ -9387,29 +9402,29 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: çalışan sanal makinede yok, sonraki " "başlatmada yok" -#: vrtManager/instance.py:2899 +#: vrtManager/instance.py:2903 #, python-format msgid "The VM has no PCI device %(address)s" msgstr "Sanal makinede %(address)s PCI aygıtı yok" -#: vrtManager/instance.py:2917 +#: vrtManager/instance.py:2921 msgid "The VM has no USB controller" msgstr "Sanal makinede USB denetleyicisi yok" -#: vrtManager/instance.py:2936 +#: vrtManager/instance.py:2940 msgid "The VM has no such USB device" msgstr "Sanal makinede böyle bir USB aygıtı yok" -#: vrtManager/instance.py:2977 +#: vrtManager/instance.py:2981 msgid "The VM has its own RNG device: change it in the XML editor" msgstr "" "Sanal makinenin kendi RNG aygıtı var: bunu XML düzenleyicide değiştirin" -#: vrtManager/instance.py:3004 +#: vrtManager/instance.py:3008 msgid "The VM has its own TPM: change it in the XML editor" msgstr "Sanal makinenin kendi TPM'i var: bunu XML düzenleyicide değiştirin" -#: vrtManager/instance.py:3023 +#: vrtManager/instance.py:3027 #, python-format msgid "Unknown crash action %(action)s" msgstr "Bilinmeyen çökme eylemi %(action)s" diff --git a/locale/zh/LC_MESSAGES/django.mo b/locale/zh/LC_MESSAGES/django.mo index 710c2baafc33ff1296f2d5ef91924fd21c908581..17aeed852272b95731dabea43b79cb827d0b9317 100644 GIT binary patch delta 35930 zcmb8&Wpq_X|Ns4Sf(4fVAp}SuK!6ZJu;A_%+$BhGcRx7AWfMHOv`BF%4n>PQT*cbr zUbH}I`M*DBrfdBk-uGE6ea+0CJ@TEIy-&DGubclS+c+k<=We=$aV|dllek=2@M{^D zt7$Tq>-KP!x?IKAxLhT%1Qx~tSO>qyVEl-A(0{GVl^@Ha%6noFoPqv$6xIGMR6CzA zhs))0QcK~(Y6V$+y|6tm! ziUH)?q3#=wh3Vh*J&95j+{V0^X}uXxMQl#KJEp+nsOy(8BYs6c^xI$t7K%aSt72B{ zgq3kTs-0i37lv#!5uAff=->4l2{jnCiSS`vY>G2cp?-|*u;`Dbe7^NH>Uy=!bcS(Q z3BRI3Uw(_rRT>9kG;TxH_u1-lwZVGmX-Hx-357htHkT_URz!uW9%{|HVHi$Ag>*Z{ z;46&8=F`NQFT#j1f z9as+UqGpoqCzmS%tDtTih`KKx)zQzW5WhrizA}3_F&Kl*a1pk^cc^-G_nK3&)I&m{ z-G#yU2Pz^7_L(I}i&}y(RL9j(9rr;-nDtZ<0|*C+euXALSO4osE)tkLM(oQ@Zn`tC?8@q%zl#Pz^%uMy0`Q8h_!707 zlU+0e2*w2DLs0__!_-&|Q(;wWW7NPpVsh+Z9b&JKM@`7Ve7NW$@%JThoC3}4JgS4+ zsPf0Cf&GbUIN2pLvvio0d?>1;NLyY8wO1No3XH`}*bgIcDu&}e)csFAB-GJ6RL5UY z9VNMJW|kUNF`LcjLDi4KSS*i<%vw}O>#avok-3e!|2Zn6A5i@yzha&ro{S_iQ&0r+ zVl;-}P}Ca6+w0pt^IdQ6sC13SDzls5)UzoQv8kdoU4R#|(HI6XILc68?o6V4@p#i7+ksNSm*Oif|oF zt@GcQL}vhHw85`t;B8O?>4zHF zFx2(YsJ$``72#Rv(M;k=XaGN=LiHP}gSV(P{*2na`EQvJw?Z}44KGkrn==kI z(50v)I)a(-25LZmqVD^6i}?GKaNjnYE&vt!GN>8XM-8MU24j2FK*ph#WIJZTqZo$2 zp$3rRjxhsjrrA*Kg`px*6gBY*cZk0(G@w8uYlUjKJ!&)cLk(~=2IB(M%=Vz_-L}54 zenr(!ao5Z^Cu+cDPy^|S`EVGP!8IORa33pCkm{ZZSp#bqOi%eJRL72W7is|iLv{ER zL(%=48F*e)B%`n**1}vk12f|eER3EDB!WmJ_}xSz#2SuzfJCA8L{(Hn%}{H)7}Mca zR0NNqB6!|<6}1$Du&F)KDf4SWD90^?Ba&c_P464l=W^ws(Q(^mM5IyMO(m>H!&g*GD=!~&>> z+FHAzHs3%jhjXwIUdH?w`p~@n8leW>9~J3148Wb3i~d~~NN6S>Pyj0W+Wei z+KeSpOHmy)!xpGr+!eL^hoK_27Nc=HYO^JHYzA5Ybzd!PjxEp=OkxKKb#M*U;Cwg_NcGgLX;xGRk*NF1*nBNi#G0b^LNC-nr&;Hs>Mub}Z2eQ>pOD0U z3Un-vpc=l7TI(ma{2gkhsh*j)S_W)Pz6a|5pHVYCi8@xdF(0ORZkDnX>Uw?5jh#?S zKHWpYmqa|OgSDt#y2(~}jhfLn48e>qOhihecP%j~WG@*Ak^j^k47uDfN)Ulb1C2RBWfTM-4Uitg4#?4u`(9LDmV?Dy652HqS1+@gf+58JkMgFtZ_mkPp z{+OEb{HWtv8jE3L)cw;iBQC&1xEcL%Co0nCJ`sO)e2oGP5T^N&dw=M>2dN{s9!^r9dODgsKp2D>TO( z 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 DszNwH delta 35696 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 UkbC?3K|Wz=w*NT6r)1Rs0Xxx+*8l(j diff --git a/locale/zh/LC_MESSAGES/django.po b/locale/zh/LC_MESSAGES/django.po index ab1a8108..07d063bc 100644 --- a/locale/zh/LC_MESSAGES/django.po +++ b/locale/zh/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-11-05 15:43+0000\n" +"POT-Creation-Date: 2026-11-06 20:48+0000\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -159,13 +159,13 @@ msgid "User Profile" msgstr "用户资料" #: accounts/templates/account.html:17 accounts/templates/profile.html:18 -#: admin/forms.py:73 admin/templates/admin/user_list.html:24 +#: admin/forms.py:74 admin/templates/admin/user_list.html:24 #: admin/templates/admin/user_list.html:30 msgid "Superuser" msgstr "超级用户" #: accounts/templates/account.html:19 accounts/templates/profile.html:20 -#: admin/forms.py:73 admin/templates/admin/user_list.html:24 +#: admin/forms.py:74 admin/templates/admin/user_list.html:24 #: admin/templates/admin/user_list.html:32 msgid "Template editor" msgstr "模板编辑者" @@ -198,7 +198,7 @@ msgid "User sections" msgstr "用户页面导航" #: accounts/templates/account.html:44 accounts/templates/account.html:52 -#: admin/forms.py:185 computes/templates/computes/list.html:30 +#: admin/forms.py:188 computes/templates/computes/list.html:30 #: computes/templates/computes/list.html:57 computes/templates/overview.html:46 msgid "VMs" msgstr "虚拟机" @@ -641,29 +641,29 @@ msgstr "OTP 二维码已通过邮件发送给用户 %(user)s" msgid "User email not set, failed to send QR code" msgstr "未设置用户邮箱,无法发送二维码" -#: admin/forms.py:20 +#: admin/forms.py:21 msgid "Change their own password on their profile page" msgstr "在个人资料页修改自己的密码" -#: admin/forms.py:21 +#: admin/forms.py:22 msgid "" "Clone the VMs they may change and the templates they may view, within their " "quota" msgstr "在配额范围内克隆其可修改的虚拟机和可查看的模板" -#: admin/forms.py:22 +#: admin/forms.py:23 msgid "Open a console without the VM's console password" msgstr "无需虚拟机的控制台密码即可打开控制台" -#: admin/forms.py:23 +#: admin/forms.py:24 msgid "Take, revert and delete snapshots of the VMs they may change" msgstr "为其可修改的虚拟机创建、恢复和删除快照" -#: admin/forms.py:24 +#: admin/forms.py:25 msgid "See every VM and host in the lists, read-only" msgstr "在列表中查看所有虚拟机和主机(只读)" -#: admin/forms.py:73 admin/templates/admin/logs.html:39 +#: admin/forms.py:74 admin/templates/admin/logs.html:39 #: admin/templates/admin/user_list.html:24 #: admin/templates/admin/user_list.html:34 #: computes/templates/computes/instances.html:46 @@ -675,23 +675,23 @@ msgstr "在列表中查看所有虚拟机和主机(只读)" msgid "User" msgstr "用户" -#: admin/forms.py:80 admin/templates/admin/group_form.html:30 +#: admin/forms.py:81 admin/templates/admin/group_form.html:30 msgid "Permissions" msgstr "权限" -#: admin/forms.py:87 admin/templates/admin/group_list.html:6 +#: admin/forms.py:88 admin/templates/admin/group_list.html:6 #: admin/templates/admin/group_list.html:8 #: admin/templates/admin/group_list.html:24 #: admin/templates/admin/user_form.html:123 templates/navbar.html:33 msgid "Groups" msgstr "用户组" -#: admin/forms.py:139 +#: admin/forms.py:142 #, python-format msgid "NEW_USER_DEFAULT_INSTANCES: %(name)s is not exactly one VM" msgstr "NEW_USER_DEFAULT_INSTANCES:%(name)s 不是唯一的一台虚拟机" -#: admin/forms.py:186 computes/templates/computes/list.html:58 +#: admin/forms.py:189 computes/templates/computes/list.html:58 #: computes/templates/overview.html:58 instances/forms.py:14 #: instances/templates/allinstances_index_grouped.html:16 #: instances/templates/allinstances_index_nongrouped.html:14 @@ -701,7 +701,7 @@ msgstr "NEW_USER_DEFAULT_INSTANCES:%(name)s 不是唯一的一台虚拟机" msgid "vCPUs" msgstr "vCPU" -#: admin/forms.py:187 computes/templates/computes/instances.html:49 +#: admin/forms.py:190 computes/templates/computes/instances.html:49 #: computes/templates/computes/list.html:59 computes/templates/overview.html:66 #: computes/templates/overview.html:150 #: instances/templates/allinstances_index_grouped.html:17 @@ -713,34 +713,34 @@ msgstr "vCPU" msgid "Memory" msgstr "内存" -#: admin/forms.py:188 instances/models.py:235 +#: admin/forms.py:191 instances/models.py:235 #: instances/templates/create_instance_w2.html:118 #: instances/templates/instances/settings_tab.html:25 #: instances/templates/instances/stats_tab.html:51 msgid "Disk" msgstr "磁盘" -#: admin/forms.py:198 +#: admin/forms.py:201 msgid "No limit" msgstr "不限" -#: admin/forms.py:214 +#: admin/forms.py:217 msgid "Enter a limit or choose No limit." msgstr "请输入限制值,或选择“不限”。" -#: admin/forms.py:226 +#: admin/forms.py:229 msgid "The user must change it at their next login" msgstr "用户必须在下次登录时修改密码" -#: admin/forms.py:232 +#: admin/forms.py:235 msgid "With a password" msgstr "使用密码" -#: admin/forms.py:232 +#: admin/forms.py:235 msgid "Without a password" msgstr "不使用密码" -#: admin/forms.py:238 +#: admin/forms.py:241 msgid "A user without a password cannot be made to change it" msgstr "没有密码的用户无法被要求修改密码" @@ -2507,20 +2507,20 @@ msgstr "已被 %%(name)s 接管" msgid "Connected. If the VM shows nothing, press Enter." msgstr "已连接。如果虚拟机没有显示任何内容,请按 Enter。" -#: console/views.py:43 +#: console/views.py:48 msgid "" "User does not have permission to access console or host/instance not exist" msgstr "用户无权访问控制台,或主机/虚拟机不存在" -#: console/views.py:69 +#: console/views.py:78 msgid "Fail to get console. Please check the console configuration of your VM." msgstr "无法获取控制台。请检查虚拟机的控制台配置。" -#: console/views.py:71 +#: console/views.py:80 msgid "The VM is not running: start it to open its console." msgstr "虚拟机未运行:请启动它以打开控制台。" -#: console/views.py:74 +#: console/views.py:83 msgid "" "This console listens only on its host, which the panel reaches over TCP or " "TLS. Let the console listen on all interfaces in the VM's console settings, " @@ -2528,13 +2528,13 @@ msgid "" msgstr "" "此控制台只在其主机上监听,而面板通过 TCP 或 TLS 连接该主机。请在虚拟机的控制台设置中让控制台监听所有接口,或将该主机添加为 SSH 主机。" -#: console/views.py:80 +#: console/views.py:89 msgid "" "Serial console is disabled on this server. Please switch VM graphics to VNC " "or ask an administrator." msgstr "此服务器已禁用串行控制台。请将虚拟机图形切换为 VNC,或联系管理员。" -#: console/views.py:85 +#: console/views.py:94 #, python-format msgid "" "Console type '%(type)s' is not supported. Please switch the VM graphics to " @@ -2751,7 +2751,7 @@ msgstr "无法解冻客户机的文件系统(%(error)s);请用以下命令 msgid "Clone VM" msgstr "克隆虚拟机" -#: instances/jobs.py:562 instances/jobs.py:569 instances/jobs.py:844 +#: instances/jobs.py:562 instances/jobs.py:569 instances/jobs.py:847 msgid "Copying disks" msgstr "正在复制磁盘" @@ -2766,7 +2766,7 @@ msgid "" "(%(thaw)s); thaw them with: virsh domfsthaw %(vm)s" msgstr "复制失败:%(error)s。无法解冻客户机的文件系统(%(thaw)s);请用以下命令解冻:virsh domfsthaw %(vm)s" -#: instances/jobs.py:635 instances/jobs.py:719 +#: instances/jobs.py:635 instances/jobs.py:722 msgid "The copy failed" msgstr "复制失败" @@ -2777,209 +2777,217 @@ msgid "" "resolve this job: %(volumes)s" msgstr "虚拟机已不在运行该任务的计算节点上;请检查这些卷,然后处理此任务:%(volumes)s" -#: instances/jobs.py:695 +#: instances/jobs.py:698 #, python-format msgid "" "A volume of the clone was being created; check these volumes, then resolve " "this job: %(volumes)s" msgstr "克隆的一个卷正在创建中;请检查这些卷,然后处理此任务:%(volumes)s" -#: instances/jobs.py:699 +#: instances/jobs.py:702 msgid "The job stopped before the copy started" msgstr "任务在复制开始前停止" -#: instances/jobs.py:706 +#: instances/jobs.py:709 msgid "libvirt is still copying the disks" msgstr "libvirt 仍在复制磁盘" -#: instances/jobs.py:709 +#: instances/jobs.py:712 #, python-format msgid "" "Another backup runs on the VM; check these volumes, then resolve this job: " "%(volumes)s" msgstr "虚拟机上正在运行另一个备份;请检查这些卷,然后处理此任务:%(volumes)s" -#: instances/jobs.py:714 +#: instances/jobs.py:717 #, python-format msgid "" "libvirt has no result of the copy; check these volumes, then resolve this " "job: %(volumes)s" msgstr "libvirt 没有复制的结果;请检查这些卷,然后处理此任务:%(volumes)s" -#: instances/jobs.py:726 +#: instances/jobs.py:729 #, 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:749 instances/templates/create_instance_w1.html:60 +#: instances/jobs.py:752 instances/templates/create_instance_w1.html:60 #: instances/templates/create_instance_w2.html:356 msgid "Create VM" msgstr "创建虚拟机" -#: instances/jobs.py:773 instances/jobs.py:818 instances/views.py:2463 +#: instances/jobs.py:776 instances/jobs.py:821 instances/views.py:2463 msgid "A virtual machine with this name already exists" msgstr "同名虚拟机已存在" -#: instances/jobs.py:775 instances/jobs.py:815 +#: instances/jobs.py:778 instances/jobs.py:818 msgid "There is an instance with same name. Remove it and try again!" msgstr "已存在同名虚拟机。请删除后重试!" -#: instances/jobs.py:778 +#: instances/jobs.py:781 msgid "First you need to create or select an image" msgstr "请先创建或选择一个镜像" -#: instances/jobs.py:780 +#: instances/jobs.py:783 msgid "Choose one disk source: a new disk, existing volumes or a template" msgstr "请选择一种磁盘来源:新磁盘、现有卷或模板" -#: instances/jobs.py:782 +#: instances/jobs.py:785 msgid "Image has already exist. Please check volumes or change instance name" msgstr "镜像已存在。请检查卷或更改虚拟机名称" -#: instances/jobs.py:784 +#: instances/jobs.py:787 msgid "Invalid cache mode" msgstr "无效的缓存模式" -#: instances/jobs.py:786 +#: instances/jobs.py:789 #, python-format msgid "This host offers no CPU mode or model %(mode)s" msgstr "此主机不提供 CPU 模式或型号 %(mode)s" -#: instances/jobs.py:788 +#: instances/jobs.py:791 #, python-format msgid "A CD-ROM cannot use the %(bus)s bus" msgstr "CD-ROM 不能使用 %(bus)s 总线" -#: instances/jobs.py:791 +#: instances/jobs.py:794 msgid "The cloud-init seed is read from a CD-ROM: choose its bus" msgstr "cloud-init 种子从 CD-ROM 读取:请选择其总线" -#: instances/jobs.py:794 +#: instances/jobs.py:797 msgid "The cloud-init seed needs a directory storage pool for the disk" msgstr "cloud-init 种子需要为磁盘使用目录类型的存储池" -#: instances/jobs.py:800 +#: instances/jobs.py:803 #, python-format msgid "This host offers no firmware %(firmware)s" msgstr "此主机不提供固件 %(firmware)s" -#: instances/jobs.py:802 vrtManager/instance.py:3011 +#: instances/jobs.py:805 vrtManager/instance.py:3015 msgid "This host offers no TPM 2.0: install swtpm on it" msgstr "此主机不提供 TPM 2.0:请在主机上安装 swtpm" -#: instances/jobs.py:863 +#: instances/jobs.py:866 msgid "Writing the cloud-init seed" msgstr "正在写入 cloud-init 种子" -#: instances/jobs.py:870 +#: instances/jobs.py:873 msgid "Defining the VM" msgstr "正在定义虚拟机" -#: instances/jobs.py:903 +#: instances/jobs.py:906 +#, python-format +#| msgid "The panel failed unexpectedly; its log has the details." +msgid "" +"The panel failed unexpectedly; its log has the details. Remove these volumes " +"by hand: %(volumes)s" +msgstr "面板发生意外错误;详细信息见面板日志。请手动删除这些卷:%(volumes)s" + +#: instances/jobs.py:910 #, python-format msgid "%(error)s. Remove these volumes by hand: %(volumes)s" msgstr "%(error)s。请手动删除这些卷:%(volumes)s" -#: instances/jobs.py:928 +#: instances/jobs.py:935 #, python-format msgid "The instance is already on %(compute)s" msgstr "虚拟机已在 %(compute)s 上" -#: instances/jobs.py:930 +#: instances/jobs.py:937 #, python-format msgid "%(compute)s is not reachable" msgstr "无法连接 %(compute)s" -#: instances/jobs.py:932 +#: instances/jobs.py:939 #, python-format msgid "%(compute)s is the VM's own host under another name" msgstr "%(compute)s 是该虚拟机所在主机的另一个名称" -#: instances/jobs.py:966 +#: instances/jobs.py:973 #, python-format msgid "" "The VM migrated, but autostart could not be set on the destination: %(error)s" msgstr "虚拟机已迁移,但无法在目标主机上设置自动启动:%(error)s" -#: instances/jobs.py:972 +#: instances/jobs.py:979 #, python-format msgid "The VM migrated, but its NVRAM file stays on the source: %(error)s" msgstr "虚拟机已迁移,但其 NVRAM 文件仍留在源主机上:%(error)s" -#: instances/jobs.py:979 +#: instances/jobs.py:986 msgid "Migrate VM" msgstr "迁移虚拟机" -#: instances/jobs.py:1026 +#: instances/jobs.py:1033 msgid "Migrating the VM" msgstr "正在迁移虚拟机" -#: instances/jobs.py:1073 +#: instances/jobs.py:1080 msgid "libvirt is still migrating the VM" msgstr "libvirt 仍在迁移虚拟机" -#: instances/jobs.py:1084 +#: instances/jobs.py:1091 msgid "The VM stayed on the source host" msgstr "虚拟机留在了源主机上" -#: instances/jobs.py:1086 +#: instances/jobs.py:1093 msgid "" "The VM is on both computes or on neither; check them, then resolve this job." msgstr "虚拟机同时位于两个计算节点上,或都不在;请检查后处理此任务。" -#: instances/jobs.py:1134 +#: instances/jobs.py:1141 msgid "Move disk" msgstr "移动磁盘" -#: instances/jobs.py:1141 +#: instances/jobs.py:1148 msgid "Choose a disk of the VM" msgstr "请选择虚拟机的一个磁盘" -#: instances/jobs.py:1165 +#: instances/jobs.py:1172 msgid "Copying the disk" msgstr "正在复制磁盘" -#: instances/jobs.py:1208 +#: instances/jobs.py:1215 #, python-format msgid "Another block job runs on %(dev)s; check the VM" msgstr "%(dev)s 上正在运行另一个块任务;请检查虚拟机" -#: instances/jobs.py:1214 +#: instances/jobs.py:1221 #, python-format msgid "The disk stayed in %(path)s; remove %(dest)s if it is there" msgstr "磁盘仍在 %(path)s;如果 %(dest)s 存在,请将其删除" -#: instances/jobs.py:1216 +#: instances/jobs.py:1223 #, python-format msgid "The definitions of %(dev)s name %(paths)s; check the VM" msgstr "%(dev)s 的定义指向 %(paths)s;请检查虚拟机" -#: instances/jobs.py:1223 +#: instances/jobs.py:1230 #, python-format msgid "Disk %(path)s was kept: a disk file that stays needs it" msgstr "磁盘 %(path)s 已保留:某个保留的磁盘文件依赖它" -#: instances/jobs.py:1224 +#: instances/jobs.py:1231 #, python-format msgid "The VM is removed, but disk %(path)s was not deleted: %(err)s" msgstr "虚拟机已删除,但磁盘 %(path)s 未被删除:%(err)s" -#: instances/jobs.py:1225 +#: instances/jobs.py:1232 #, python-format msgid "Disk %(path)s is used by another VM and was kept" msgstr "磁盘 %(path)s 正被另一台虚拟机使用,已保留" -#: instances/jobs.py:1279 +#: instances/jobs.py:1286 msgid "Delete VM" msgstr "删除虚拟机" -#: instances/jobs.py:1309 +#: instances/jobs.py:1316 msgid "Deleting the VM" msgstr "正在删除虚拟机" -#: instances/jobs.py:1321 +#: instances/jobs.py:1328 msgid "The VM was not deleted; it may have been shut off" msgstr "虚拟机未被删除;它可能已被关闭" @@ -5931,7 +5939,7 @@ msgstr "请选择网络接口和 QoS 方向" msgid "QoS rates must be whole numbers" msgstr "QoS 速率必须为整数" -#: instances/views.py:2197 networks/views.py:229 +#: instances/views.py:2197 networks/views.py:230 #, python-format msgid "%(qos_dir)s QoS is set" msgstr "%(qos_dir)s QoS 已设置" @@ -5942,7 +5950,7 @@ msgid "" "%(qos_dir)s QoS is set. A running VM gets it after it is powered off and on." msgstr "%(qos_dir)s QoS 已设置。运行中的虚拟机需关机再开机后才能生效。" -#: instances/views.py:2224 networks/views.py:255 +#: instances/views.py:2224 networks/views.py:256 #, python-format msgid "%(qos_dir)s QoS is deleted" msgstr "%(qos_dir)s QoS 已删除" @@ -6119,7 +6127,7 @@ msgid "A new bridge over a device of the host; VMs can join it." msgstr "在主机设备上新建网桥;虚拟机可以加入。" #: interfaces/templates/create_iface_block.html:30 -#: interfaces/templates/create_iface_block.html:75 interfaces/views.py:31 +#: interfaces/templates/create_iface_block.html:75 interfaces/views.py:32 msgid "Ethernet" msgstr "以太网" @@ -6343,19 +6351,19 @@ msgstr "链路 %(link)s" msgid "Link unknown" msgstr "链路未知" -#: interfaces/views.py:30 +#: interfaces/views.py:31 msgid "Bridges" msgstr "网桥" -#: interfaces/views.py:30 +#: interfaces/views.py:31 msgid "Bonds" msgstr "绑定" -#: interfaces/views.py:31 +#: interfaces/views.py:32 msgid "VLANs" msgstr "VLAN" -#: interfaces/views.py:45 +#: interfaces/views.py:46 #, python-format msgid "The network devices of this host could not be read: %(error)s" msgstr "无法读取此主机的网络设备:%(error)s" @@ -6880,40 +6888,40 @@ msgstr "SR-IOV" msgid "VMs get a virtual function of the host's network card." msgstr "虚拟机获得主机网卡的一个虚拟功能。" -#: networks/views.py:166 +#: networks/views.py:167 msgid "The fixed address is unchanged" msgstr "固定地址未更改" -#: networks/views.py:168 +#: networks/views.py:169 #, python-format msgid "The fixed address %(address)s is set" msgstr "已设置固定地址 %(address)s" -#: networks/views.py:177 +#: networks/views.py:178 #, python-format msgid "The fixed address %(address)s is deleted" msgstr "已删除固定地址 %(address)s" -#: networks/views.py:185 +#: networks/views.py:186 msgid "The DHCP range is changed" msgstr "DHCP 范围已更改" -#: networks/views.py:202 +#: networks/views.py:203 msgid "Network XML is changed. Stop and start network to activate new config." msgstr "网络 XML 已更改。请停止并启动网络以应用新配置。" -#: networks/views.py:207 +#: networks/views.py:208 msgid "Network XML is changed." msgstr "网络 XML 已更改。" -#: networks/views.py:222 +#: networks/views.py:223 #, python-format msgid "" "%(qos_dir)s QoS is updated. Network XML is changed. Stop and start network to" " activate new config" msgstr "%(qos_dir)s QoS 已更新。网络 XML 已更改。请停止并启动网络以应用新配置" -#: networks/views.py:247 +#: networks/views.py:248 #, python-format msgid "" "%(qos_dir)s QoS is deleted. Network XML is changed. Stop and start network to" @@ -7421,64 +7429,68 @@ msgstr "取消失败(HTTP %(status)s)。" msgid "Cancel failed: the server could not be reached." msgstr "取消失败:无法连接到服务器。" -#: operations/utils.py:54 +#: operations/utils.py:55 msgid "The host of this virtual machine cannot be reached right now." msgstr "当前无法连接此虚拟机所在的主机。" -#: operations/utils.py:55 +#: operations/utils.py:56 msgid "" "The host of this virtual machine is busy with other requests right now: try " "again in a moment." msgstr "此虚拟机所在的主机正忙于处理其他请求:请稍后重试。" -#: operations/utils.py:57 +#: operations/utils.py:58 msgid "You may no longer do this." msgstr "您已无权执行此操作。" -#: operations/utils.py:58 +#: operations/utils.py:59 msgid "The virtual machine is no longer in the panel." msgstr "该虚拟机已不在面板中。" -#: operations/utils.py:169 +#: operations/utils.py:127 +msgid "The panel failed unexpectedly; its log has the details." +msgstr "面板发生意外错误;详细信息见面板日志。" + +#: operations/utils.py:191 msgid "" "A short operation is in progress on this resource; try again in a moment." msgstr "此资源上正在进行一项短时操作,请稍后重试。" -#: operations/utils.py:172 +#: operations/utils.py:194 #, python-format msgid "" "%(label)s is %(state)s on this resource (started by %(user)s, %(since)s ago);" " see the Jobs page." msgstr "此资源上的%(label)s%(state)s(由 %(user)s 于 %(since)s前发起),请查看任务页面。" -#: operations/utils.py:174 +#: operations/utils.py:196 #, python-format msgid "%(label)s is %(state)s on this resource (since %(since)s)." msgstr "此资源上的%(label)s%(state)s(自 %(since)s起)。" -#: operations/worker.py:42 +#: operations/worker.py:43 msgid "" "libvirt's merge finished copying but never completed (for example after a " "libvirtd restart); check the VM before resolving" msgstr "libvirt 的合并已完成复制但从未结束(例如 libvirtd 重启后);处理前请检查虚拟机" -#: operations/worker.py:44 +#: operations/worker.py:45 msgid "" "The worker that ran this job stopped responding; an administrator must make " "sure it is no longer running, then resolve this job" msgstr "运行此任务的工作进程已停止响应;管理员必须确认它已不再运行,然后处理此任务" -#: operations/worker.py:46 +#: operations/worker.py:47 msgid "Waiting for recovery" msgstr "等待恢复" -#: operations/worker.py:48 +#: operations/worker.py:49 msgid "" "Recovery could not read the job's state for an hour; check the VM, then " "resolve this job" msgstr "恢复在一小时内无法读取任务状态;请检查虚拟机,然后处理此任务" -#: operations/worker.py:473 +#: operations/worker.py:474 msgid "The worker stopped before the job changed anything" msgstr "工作进程在任务做出任何更改之前停止" @@ -8016,12 +8028,12 @@ msgstr "上传会话繁忙,请重试。" msgid "ISO image already exists" msgstr "ISO 镜像已存在" -#: storages/views.py:178 +#: storages/views.py:179 #, python-format msgid "Volume: %(vol)s is deleted." msgstr "卷 %(vol)s 已删除。" -#: storages/views.py:196 +#: storages/views.py:197 #, python-format msgid "Image file %(name)s is created successfully" msgstr "镜像文件 %(name)s 创建成功" @@ -8736,57 +8748,57 @@ msgstr "此虚拟机上仍有快照任务在运行;请在其结束后重试" msgid "Shut the VM down to revert to an internal snapshot" msgstr "请关闭虚拟机后再还原到内部快照" -#: vrtManager/instance.py:2403 +#: vrtManager/instance.py:2407 msgid "Cannot clone a VM whose NVRAM is not a file" msgstr "NVRAM 不是文件的虚拟机无法克隆" -#: vrtManager/instance.py:2471 +#: vrtManager/instance.py:2475 #, python-format msgid "Clone failed (%(err)s); remove these copies by hand: %(path)s" msgstr "克隆失败(%(err)s);请手动删除这些副本:%(path)s" -#: vrtManager/instance.py:2481 +#: vrtManager/instance.py:2485 msgid "Shut the VM down before cloning it" msgstr "请先关闭虚拟机再克隆" -#: vrtManager/instance.py:2535 +#: vrtManager/instance.py:2539 #, python-format msgid "Clone failed (%(err)s); remove these copies by hand: %(leftovers)s" msgstr "克隆失败(%(err)s);请手动删除这些副本:%(leftovers)s" -#: vrtManager/instance.py:2546 +#: vrtManager/instance.py:2550 msgid "Live clone needs libvirt 11.10 or later; shut the VM down to clone it" msgstr "在线克隆需要 libvirt 11.10 或更高版本;请关闭虚拟机后再克隆" -#: vrtManager/instance.py:2549 +#: vrtManager/instance.py:2553 msgid "A VM with a TPM is cloned only shut down" msgstr "带 TPM 的虚拟机只能在关机时克隆" -#: vrtManager/instance.py:2552 +#: vrtManager/instance.py:2556 #, python-format msgid "Disk %(dev)s is not a local file; shut the VM down to clone it" msgstr "磁盘 %(dev)s 不是本地文件;请关闭虚拟机后再克隆" -#: vrtManager/instance.py:2554 +#: vrtManager/instance.py:2558 #, python-format msgid "Disk %(dev)s is shareable; shut the VM down to clone it" msgstr "磁盘 %(dev)s 是可共享的;请关闭虚拟机后再克隆" -#: vrtManager/instance.py:2559 +#: vrtManager/instance.py:2563 #, python-format msgid "Disk %(dev)s changes at the next start; shut the VM down to clone it" msgstr "磁盘 %(dev)s 在下次启动时会改变;请关闭虚拟机后再克隆" -#: vrtManager/instance.py:2561 +#: vrtManager/instance.py:2565 msgid "Another job is running on the VM; clone it when that ends" msgstr "虚拟机上有另一个任务正在运行;请在其结束后再克隆" -#: vrtManager/instance.py:2574 +#: vrtManager/instance.py:2578 #, python-format msgid "Volume %(name)s already exists in storage pool %(pool)s" msgstr "卷 %(name)s 已存在于存储池 %(pool)s 中" -#: vrtManager/instance.py:2593 +#: vrtManager/instance.py:2597 #, python-format msgid "" "Storage pool %(pool)s has %(free).1f GiB free; the clone needs %(size).1f GiB" @@ -8795,92 +8807,92 @@ msgstr "" "存储池 %(pool)s 可用 %(free).1f GiB;克隆需要 %(size).1f GiB(复制的磁盘,再加其 %(percent)g%%,至少" " %(minimum)g GiB)" -#: vrtManager/instance.py:2732 +#: vrtManager/instance.py:2736 msgid "A network interface that is a host device is removed in the XML editor" msgstr "作为主机设备的网络接口需在 XML 编辑器中删除" -#: vrtManager/instance.py:2748 +#: vrtManager/instance.py:2752 #, python-format msgid "No network interface with MAC %(old_mac)s" msgstr "没有 MAC 为 %(old_mac)s 的网络接口" -#: vrtManager/instance.py:2751 +#: vrtManager/instance.py:2755 msgid "A network interface that is a host device is changed in the XML editor" msgstr "作为主机设备的网络接口需在 XML 编辑器中修改" -#: vrtManager/instance.py:2842 +#: vrtManager/instance.py:2846 msgid "" "A VM changes its PCI devices while it runs, or is shut off without a saved " "state" msgstr "虚拟机只能在运行时或无保存的状态的关机时更改其 PCI 设备" -#: vrtManager/instance.py:2854 +#: vrtManager/instance.py:2858 #, python-format msgid "%(err)s; whether the VM has PCI device %(address)s now is not known" msgstr "%(err)s;虚拟机现在是否有 PCI 设备 %(address)s 未知" -#: vrtManager/instance.py:2856 +#: vrtManager/instance.py:2860 #, python-format msgid "" "%(err)s; PCI device %(address)s: the VM is not running, its next start has it" msgstr "%(err)s;PCI 设备 %(address)s:虚拟机未运行,下次启动时有它" -#: vrtManager/instance.py:2858 +#: vrtManager/instance.py:2862 #, python-format msgid "" "%(err)s; PCI device %(address)s: the VM is not running, its next start does " "not have it" msgstr "%(err)s;PCI 设备 %(address)s:虚拟机未运行,下次启动时没有它" -#: vrtManager/instance.py:2859 +#: vrtManager/instance.py:2863 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM has it, its next start has it" msgstr "%(err)s;PCI 设备 %(address)s:运行中的虚拟机有它,下次启动时有它" -#: vrtManager/instance.py:2861 +#: vrtManager/instance.py:2865 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM has it, its next start does " "not have it" msgstr "%(err)s;PCI 设备 %(address)s:运行中的虚拟机有它,下次启动时没有它" -#: vrtManager/instance.py:2863 +#: vrtManager/instance.py:2867 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM does not have it, its next " "start has it" msgstr "%(err)s;PCI 设备 %(address)s:运行中的虚拟机没有它,下次启动时有它" -#: vrtManager/instance.py:2865 +#: vrtManager/instance.py:2869 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM does not have it, its next " "start does not have it" msgstr "%(err)s;PCI 设备 %(address)s:运行中的虚拟机没有它,下次启动时没有它" -#: vrtManager/instance.py:2899 +#: vrtManager/instance.py:2903 #, python-format msgid "The VM has no PCI device %(address)s" msgstr "虚拟机没有 PCI 设备 %(address)s" -#: vrtManager/instance.py:2917 +#: vrtManager/instance.py:2921 msgid "The VM has no USB controller" msgstr "虚拟机没有 USB 控制器" -#: vrtManager/instance.py:2936 +#: vrtManager/instance.py:2940 msgid "The VM has no such USB device" msgstr "虚拟机没有此 USB 设备" -#: vrtManager/instance.py:2977 +#: vrtManager/instance.py:2981 msgid "The VM has its own RNG device: change it in the XML editor" msgstr "虚拟机有自己的 RNG 设备:请在 XML 编辑器中修改" -#: vrtManager/instance.py:3004 +#: vrtManager/instance.py:3008 msgid "The VM has its own TPM: change it in the XML editor" msgstr "虚拟机有自己的 TPM:请在 XML 编辑器中修改" -#: vrtManager/instance.py:3023 +#: vrtManager/instance.py:3027 #, python-format msgid "Unknown crash action %(action)s" msgstr "未知的崩溃操作 %(action)s" diff --git a/operations/tests/test_worker.py b/operations/tests/test_worker.py index 582ee827..3595e6a9 100644 --- a/operations/tests/test_worker.py +++ b/operations/tests/test_worker.py @@ -21,7 +21,7 @@ from operations.utils import words from operations import jobs from operations.models import Claim, Operation, WorkerLease from operations.tests import fakes -from operations.worker import Worker, data_dir, host_identity, housekeeping +from operations.worker import Worker, data_dir, host_identity, housekeeping, traceback_of from vrtManager.util import ConnectionFailed @@ -250,12 +250,25 @@ class WorkerTestCase(TransactionTestCase): def test_a_job_thread_that_raised_before_its_effects_fails(self): op = self.submit("test.noop", {}, "key-00000001") - with patch("operations.jobs.Context", side_effect=RuntimeError("no context")): + with patch("operations.jobs.Context", side_effect=RuntimeError("no context")), \ + self.assertLogs("operations.worker", "WARNING") as logs: self.start() self.assertTrue(wait_for(lambda: state(op) == Operation.FAILED)) - self.assertIn("no context", words(Operation.objects.get(pk=op.pk).error)) + # a fault of the panel: users read that, the log has the exception with its traceback + self.assertEqual(words(Operation.objects.get(pk=op.pk).error), "The panel failed unexpectedly; its log has the details.") + self.assertTrue(any("no context" in line and "Traceback" in line for line in logs.output)) self.assertFalse(Claim.objects.filter(operation=op).exists()) + def test_a_traceback_in_the_log_has_no_secret(self): + # as the message: the exception's text is written again at its end + try: + raise RuntimeError("password=review-dummy-secret") + except RuntimeError as err: + trace = traceback_of(err) + self.assertIn("Traceback", trace) + self.assertIn("password=***", trace) + self.assertNotIn("review-dummy-secret", trace) + def test_a_database_error_skips_a_tick(self): directory = tempfile.TemporaryDirectory() self.addCleanup(directory.cleanup) diff --git a/operations/utils.py b/operations/utils.py index f5240e5e..0a3bc845 100644 --- a/operations/utils.py +++ b/operations/utils.py @@ -7,6 +7,7 @@ the Settings page. The worker reads them itself (the settings middleware only runs in gunicorn).""" import re +import traceback import libvirt from django.core.exceptions import PermissionDenied @@ -121,6 +122,27 @@ def public_error_text(exception): return words(public_error(exception)) +# not libvirt's error or a refusal (whose text is for users) but a fault of +# the panel: its text (a SQL error, a KeyError's key) tells users nothing +UNEXPECTED = gettext_noop("The panel failed unexpectedly; its log has the details.") +REPORTED = (libvirtError, PermissionDenied, Http404, ValueError) + + +def traceback_of(err): + """A fault of the panel, also one a reported error wraps, goes to the log + with its traceback, without secrets as the message (exc_info would write + them); a reported error says enough.""" + fault = err.__cause__ if isinstance(err, REPORTED) else err + if fault is None or isinstance(fault, REPORTED): + return "" + return "\n" + safe_text("".join(traceback.format_exception(err))) + + +def job_error(err): + """What users read of a job's exception.""" + return public_error(err) if isinstance(err, REPORTED) else say(UNEXPECTED) + + def check_params(params): if isinstance(params, dict): for key, value in params.items(): diff --git a/operations/worker.py b/operations/worker.py index 9e9efd07..05113064 100644 --- a/operations/worker.py +++ b/operations/worker.py @@ -28,6 +28,7 @@ from logs.models import Logs from . import claims, jobs, utils from .models import Claim, LeaseLost, Operation, acquire, fenced, renew +from .utils import job_error, traceback_of logger = logging.getLogger(__name__) @@ -220,8 +221,8 @@ class Worker: self.progress_asked.pop(op_id, None) if (err := future.exception()) is not None: # execute raised before it could finish the job itself - logger.error("job %s ended unfinished: %s", op_id, utils.safe_text(err)) - self.recovery.inspect_now(op_id, utils.public_error(err)) + logger.error("job %s ended unfinished: %s%s", op_id, utils.safe_text(err), traceback_of(err)) + self.recovery.inspect_now(op_id, job_error(err)) def _concurrency(self): return self.fixed_concurrency or utils.concurrency() @@ -357,13 +358,13 @@ def execute(worker, op_id): except jobs.Cancelled: jobs.finish(op, jobs.Outcome(Operation.CANCELLED), worker=worker) except Exception as err: - logger.warning("job %s %s raised: %s", op.pk, op.kind, utils.safe_text(err)) + logger.warning("job %s %s raised: %s%s", op.pk, op.kind, utils.safe_text(err), traceback_of(err)) try: # jobs have no request: the error users see never names a host if ctx.effects_started: - worker.recovery.inspect_now(op.pk, error=utils.public_error(err)) + worker.recovery.inspect_now(op.pk, error=job_error(err)) else: - jobs.finish(op, jobs.Outcome(Operation.FAILED, error=utils.public_error(err)), worker=worker) + jobs.finish(op, jobs.Outcome(Operation.FAILED, error=job_error(err)), worker=worker) except LeaseLost: pass finally: @@ -478,13 +479,13 @@ class Scheduler: now = time.monotonic() if now - self.failing_since.setdefault(op_id, now) >= RECOVERY_LIMIT: self._finish(op, jobs.Outcome(Operation.UNCERTAIN, error=self._error( - op_id, [*utils.public_error(err), *utils.say(UNREACHABLE)]))) + op_id, [*job_error(err), *utils.say(UNREACHABLE)]))) return n = self.attempts.get(op_id, 0) self.attempts[op_id] = n + 1 self.next_try[op_id] = now + BACKOFF[min(n, len(BACKOFF) - 1)] self._phase(op_id, WAITING) - logger.warning("recovery of job %s waits: %s", op_id, utils.safe_text(err)) + logger.warning("recovery of job %s waits: %s%s", op_id, utils.safe_text(err), traceback_of(err)) return self.failing_since.pop(op_id, None) if outcome.state == Operation.RUNNING: @@ -507,7 +508,7 @@ class Scheduler: except LeaseLost: self._done(op_id) except Exception as err: - logger.error("recovery of job %s failed: %s", op_id, utils.safe_text(err)) + logger.error("recovery of job %s failed: %s%s", op_id, utils.safe_text(err), traceback_of(err)) self.next_try[op_id] = time.monotonic() + BACKOFF[-1] finally: self.inflight.discard(op_id)