mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
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.
This commit is contained in:
parent
d1fb9bd2d4
commit
432b1505b3
10 changed files with 375 additions and 277 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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": ""},
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -11,7 +11,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE 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: 2020-11-04 12:00+0000\n"
|
||||
"Last-Translator: catborise <muhammetalisag@gmail.com>, 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"
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue