From 02412b7ea50074264457aac7a72cd047fc81ca7a Mon Sep 17 00:00:00 2001 From: catborise Date: Fri, 6 Nov 2026 09:49:31 +0300 Subject: [PATCH] feat(jobs): deleting a VM is a job that recovery finishes The delete ran in the request: undefine, then the VM's record, then its disk files. A request that died in between (a gunicorn worker past its timeout, OOM, a restart), or a database write that failed after the undefine, left a record that later showed as removed outside the panel, and the disk files the user asked to delete were never deleted. Deleting a VM is now an instance.delete job. It holds the compute exclusively, as the request did, so no other VM attaches a file it is about to delete. The job chooses the files before it stops the VM (a host that cannot be checked still stops nothing) and records them first. It then stops and undefines the VM, removes its record, and deletes the files, each with its own Logs row. Recovery decides from libvirt: a VM still on its host means the delete failed; a VM gone means libvirt did it, so recovery removes the record and deletes the recorded files that are still there. The page queues the job and returns to the VM page, where the job panel follows it and opens the VM list when it ends; disks that were kept are the result's warning. The API's delete answers 202 with the job and needs a submission_key. backing_path moves to wvmConnect, as recovery has no domain to ask. --- README.md | 2 +- instances/api/serializers.py | 6 + instances/api/viewsets.py | 18 +- instances/jobs.py | 110 +++- .../instances/destroy_instance_form.html | 3 +- instances/tests/test_destroy.py | 234 +++++--- instances/tests/test_live_dataloss.py | 34 +- instances/tests/test_live_jobs.py | 19 +- instances/tests/test_moved_while_waiting.py | 26 +- instances/tests/test_security_mutations.py | 9 +- instances/tests/test_template_rules.py | 8 +- instances/tests/test_vm_audit_rows.py | 11 - instances/views.py | 69 +-- locale/tr/LC_MESSAGES/django.mo | Bin 193674 -> 193911 bytes locale/tr/LC_MESSAGES/django.po | 558 +++++++++--------- locale/zh/LC_MESSAGES/django.mo | Bin 181116 -> 181348 bytes locale/zh/LC_MESSAGES/django.po | 556 ++++++++--------- vrtManager/connection.py | 12 + vrtManager/instance.py | 12 - 19 files changed, 923 insertions(+), 764 deletions(-) diff --git a/README.md b/README.md index e9bfa054..1cee0540 100644 --- a/README.md +++ b/README.md @@ -772,7 +772,7 @@ What an update from an older version changes for operators and users: - The panel backs itself up every day ([Backups](#backups)); in Docker into a new volume, `webvirtcloud-backups`. - In Docker, the TLS client certificates of TLS computes are kept in a new volume, `webvirtcloud-pki` (`/var/www/.pki`), and backed up; put them there once ([Adding a Compute Node](#adding-a-compute-node), step 2). - The SQLite database must be on a local file system (WAL). Outside compose, stop the Docker container with `docker stop -t 95` so the worker can finish running jobs. -- Long operations run as jobs in a worker process (`manage.py run_worker`): creating, cloning and migrating VMs, cloning volumes, taking and reverting snapshots and deleting external snapshots. The page returns at once and the job panel and the Jobs page follow them; a migration can be cancelled. The API's VM create and migrate answer 202 with the job and need a new `submission_key` per request. The create form no longer takes a console password; set it on the VM page. +- Long operations run as jobs in a worker process (`manage.py run_worker`): creating, cloning, migrating and deleting VMs, cloning volumes, taking and reverting snapshots and deleting external snapshots. The page returns at once and the job panel and the Jobs page follow them; a migration can be cancelled. The API's VM create, migrate and delete answer 202 with the job and need a new `submission_key` per request. The create form no longer takes a console password; set it on the VM page. - An ISO upload is tracked as a job that can be cancelled. The browser sends the file, so stay on the page until it ends; an upload left idle for an hour is ended and its partial file deleted. - A clone of a running VM (libvirt 11.10 or later, local file disks, no TPM) locks the VM until the copy ends and can be cancelled; cancelling a clone of a shut-off VM has no effect. A job that ends uncertain keeps its VM locked until a superuser resolves it on its job page. - The job worker runs at most half of its concurrency (Settings, at least one) of one host's jobs at a time, so a host that does not answer cannot take every slot. diff --git a/instances/api/serializers.py b/instances/api/serializers.py index 33dca89e..e5b72a47 100644 --- a/instances/api/serializers.py +++ b/instances/api/serializers.py @@ -70,6 +70,12 @@ class DestroyOptionsSerializer(serializers.Serializer): delete_nvram = serializers.BooleanField(default=False) +class DestroySerializer(DestroyOptionsSerializer): + """The API's delete: a job, which a new submission key per request names.""" + + submission_key = serializers.CharField(write_only=True) + + class CreateInstanceSerializer(serializers.ModelSerializer): # BIOS, UEFI or UEFI Secure Boot, as the host offers; left out: the machine's default firmware = serializers.CharField(required=False) diff --git a/instances/api/viewsets.py b/instances/api/viewsets.py index 2b5a6cd5..1022d0c3 100644 --- a/instances/api/viewsets.py +++ b/instances/api/viewsets.py @@ -7,7 +7,6 @@ from django.shortcuts import get_object_or_404 from django.urls import reverse from instances.jobs import MIGRATE_OPTIONS from instances.models import Flavor, Instance -from instances.views import destroy as instance_destroy from instances.views import ( force_off, get_instance, @@ -28,7 +27,7 @@ from webvirtcloud.serializers import ActionStatusSerializer from .serializers import ( CreateInstanceSerializer, - DestroyOptionsSerializer, + DestroySerializer, FlavorSerializer, InstanceDetailsSerializer, InstanceSerializer, @@ -40,8 +39,8 @@ def instance_action_response(action, request, pk, message): response = action(request, pk) if response.status_code >= 400: return response - # the page's view reports a partial result (a disk that was kept) as a - # message for the page it redirects to: the API answers with them + # the page's view reports a partial result as a message for the page it + # redirects to: the API answers with them return Response({"status": message, "messages": [str(m) for m in get_messages(request)]}) @@ -124,12 +123,19 @@ class InstanceViewSet(viewsets.ViewSet): return Response(serializer.data) - @extend_schema(request=DestroyOptionsSerializer, responses=ActionStatusSerializer) + @extend_schema(request=DestroySerializer, responses={202: OperationSerializer, 400: dict}) def destroy(self, request, pk=None, compute_pk=None): queryset = get_instance(request.user, pk, perm_type="delete") if compute_pk is not None and str(queryset.compute_id) != str(compute_pk): raise Http404() - return instance_action_response(instance_destroy, request, pk, "Instance is destroyed") + serializer = DestroySerializer(data=request.data) + if not serializer.is_valid(): + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + data = dict(serializer.validated_data) + key = data.pop("submission_key") + op = jobs.submit("instance.delete", request.user, {"instance": queryset.pk, **data}, key) + return Response(OperationSerializer(op, context={"request": request}).data, status=status.HTTP_202_ACCEPTED, + headers={"Location": reverse("operation-detail", args=[op.pk])}) @extend_schema(request=None, responses=ActionStatusSerializer) @action(detail=True, methods=["post"]) diff --git a/instances/jobs.py b/instances/jobs.py index 04d61708..43536877 100644 --- a/instances/jobs.py +++ b/instances/jobs.py @@ -14,7 +14,9 @@ from django.template.loader import render_to_string from django.utils.translation import gettext_noop from django.utils.translation import gettext_noop as _ from libvirt import (VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE, VIR_DOMAIN_JOB_NONE, VIR_DOMAIN_SNAPSHOT_LIST_EXTERNAL, - VIR_DOMAIN_SHUTOFF, VIR_ERR_NO_DOMAIN, VIR_ERR_NO_STORAGE_VOL, libvirtError) + VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_MANAGED_SAVE, + VIR_DOMAIN_UNDEFINE_NVRAM, VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, VIR_ERR_NO_DOMAIN, + VIR_ERR_NO_STORAGE_VOL, libvirtError) from lxml import etree from vrtManager import util from vrtManager.connection import wvmConnect @@ -27,6 +29,7 @@ from appsettings.settings import app_settings from computes.models import Compute 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.jobs import Cancelled, Kind, Outcome, Plan, register @@ -1215,3 +1218,108 @@ class MoveDisk(Kind): def log_entry(self, op, state): return _log(op, state, f"move disk {op.params['dev']} to pool {op.params['pool']}") + + +DISK_KEPT_BELOW = _("Disk %(path)s was kept: a disk file that stays needs it") +DISK_NOT_DELETED = _("The VM is removed, but disk %(path)s was not deleted: %(err)s") +DISK_SHARED = _("Disk %(path)s is used by another VM and was kept") + + +def _deletable(user, pk): + """The delete view's rule: the VM's delete right.""" + from instances.views import get_instance + + if user is None or not user.is_active: + raise PermissionDenied + return get_instance(user, pk, perm_type="delete") + + +def _removed(op, recovering=False): + """What follows the undefine: the VM's record, then the disk files the job + chose before it stopped the VM; the job's result. Each disk has its own + Logs row; a file that stays keeps the files below it, which it needs. In + recovery a file already gone was deleted before the worker stopped.""" + Instance.objects.filter(compute_id=op.intent["compute"], uuid=op.intent["uuid"]).delete() + compute = Compute.objects.get(pk=op.intent["compute"]) + conn = wvmConnect(compute.hostname, compute.login, compute.password, compute.type) + notes, kept = [], set() + for path in op.intent["to_delete"]: + if path in kept: + notes += say(DISK_KEPT_BELOW, path=path) + continue + try: + conn.get_volume_by_path(path).delete(0) + except util.ConnectionFailed: + raise # unreachable: recovery waits and retries + except libvirtError as err: + if recovering and err.get_error_code() == VIR_ERR_NO_STORAGE_VOL: + continue + notes += say(DISK_NOT_DELETED, path=path, err=err) + write(op.username, compute.name, op.intent["name"], f"VM {op.intent['name']}: delete volume {path}: " + f"{safe_text(err)}", False, uuid=op.intent["uuid"]) + try: + while (path := conn.backing_path(path)) and path not in kept: + kept.add(path) + except libvirtError: + kept.update(op.intent["to_delete"]) # the files it needs are unknown: none of the rest goes + else: + write(op.username, compute.name, op.intent["name"], f"VM {op.intent['name']}: delete volume {path}", + True, uuid=op.intent["uuid"]) + for path in op.intent["shared"]: + notes += say(DISK_SHARED, path=path) + return {"open": reverse("instances:index"), **({"warning": notes} if notes else {})} + + +@register +class DeleteInstance(Kind): + """Undefine the VM, then remove its record and the disk files chosen + before it was stopped. Recovery finishes a delete libvirt has done.""" + + name = "instance.delete" + label = gettext_noop("Delete VM") + + def normalize(self, raw): + return {"instance": int(raw["instance"]), "delete_disk": bool(raw.get("delete_disk")), + "delete_nvram": bool(raw.get("delete_nvram"))} + + def validate(self, user, params): + _deletable(user, params["instance"]) + + def plan(self, user, params): + instance = _instance(params["instance"]) + # the whole compute: a file to delete must not be attached by another VM meanwhile + return Plan(claims={claims.compute_key(instance.compute_id): Claim.EXCLUSIVE, + claims.instance_key(instance.uuid): Claim.EXCLUSIVE}, + resource=claims.instance_key(instance.uuid), label=f"{instance.compute.name}/{instance.name}", + intent={"compute": instance.compute_id, "uuid": instance.uuid, "name": instance.name}) + + def precheck(self, op, ctx): + if _deletable(op.user, op.params["instance"]).compute_id != op.intent["compute"]: + raise util.OperationError(MOVED) + + def run(self, op, ctx): + instance = _instance(op.params["instance"]) + proxy = _proxy(instance) + to_delete, shared = [], [] + if op.params["delete_disk"]: + # known before the VM is stopped: a host that cannot be checked stops nothing + to_delete, shared = proxy.split_disk_paths_by_use( + lambda own: utils.paths_used_on_other_computes(instance.compute, own)) + ctx.record_intent(to_delete=to_delete, shared=shared) + ctx.set_phase(gettext_noop("Deleting the VM")) + # paused and other active states stop too, or the VM runs on as a transient domain + if proxy.instance.isActive(): + proxy.force_shutdown() + # snapshot metadata goes with the domain; internal snapshot data stays in kept disk images + flags = VIR_DOMAIN_UNDEFINE_MANAGED_SAVE | VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA + flags |= VIR_DOMAIN_UNDEFINE_NVRAM if op.params["delete_nvram"] else VIR_DOMAIN_UNDEFINE_KEEP_NVRAM + proxy.delete(flags) + return _removed(op) + + def reconcile(self, op): + if _domain(op.intent["compute"], op.intent["uuid"]) is not None: + return Outcome(Operation.FAILED, error=say(_("The VM was not deleted; it may have been shut off"))) + return Outcome(Operation.SUCCEEDED, result=_removed(op, recovering=True)) + + def log_entry(self, op, state): + return _log(op, state, "delete") diff --git a/instances/templates/instances/destroy_instance_form.html b/instances/templates/instances/destroy_instance_form.html index e495faef..252ae1ad 100644 --- a/instances/templates/instances/destroy_instance_form.html +++ b/instances/templates/instances/destroy_instance_form.html @@ -1,5 +1,6 @@ {% extends 'base.html' %} {% load i18n %} +{% load operations %} {% block title %}{% blocktrans with name=instance.name %}Destroy {{ name }}{% endblocktrans %}{% endblock title %} {% block page_heading %} @@ -8,7 +9,7 @@ {% block content %}

{% trans "The VM's definition, saved state and snapshot records are removed. A running VM is forced off first; what the guest has not written to disk is lost." %}

-
{% csrf_token %} +{% csrf_token %}{% submission_key %}
{% trans "What should happen to the files?" %}
diff --git a/instances/tests/test_destroy.py b/instances/tests/test_destroy.py index 80f4f3df..54adb4aa 100644 --- a/instances/tests/test_destroy.py +++ b/instances/tests/test_destroy.py @@ -1,36 +1,67 @@ from contextlib import contextmanager +from types import SimpleNamespace from unittest.mock import MagicMock, patch from computes.models import Compute from django.contrib.auth import get_user_model from django.contrib.messages import get_messages -from django.test import TestCase +from django.test import TestCase, TransactionTestCase from django.urls import reverse +from instances.jobs import DeleteInstance from instances.models import Instance from instances.utils import paths_used_on_other_computes -from libvirt import VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM, libvirtError -from operations.utils import public_error_text +from libvirt import VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM, VIR_ERR_NO_STORAGE_VOL, libvirtError +from logs.models import Logs +from operations.jobs import Context +from operations.models import Claim, Operation, acquire +from operations.utils import public_error_text, words from vrtManager.util import ConnectionFailed, OperationError +UUID = "11111111-2222-3333-4444-555555555555" -class DestroyOrderTestCase(TestCase): + +class DestroyOrderTestCase(TransactionTestCase): def setUp(self): - admin = get_user_model().objects.create_superuser("destroy_admin", "d@example.com", "pw") - self.client.force_login(admin) + self.admin = get_user_model().objects.create_superuser("destroy_admin", "d@example.com", "pw") + self.client.force_login(self.admin) self.client.raise_request_exception = False compute = Compute.objects.create(name="destroy-compute", hostname="127.0.0.1", login="", password="", type=4) - self.instance = Instance.objects.create( - compute=compute, name="destroy-vm", uuid="11111111-2222-3333-4444-555555555555" - ) + self.instance = Instance.objects.create(compute=compute, name="destroy-vm", uuid=UUID) + self.proxy = MagicMock() + self.proxy.instance.isActive.return_value = False + self.proxy.backing_path.return_value = None + self.proxy.split_disk_paths_by_use.return_value = (["/pool/own.qcow2"], ["/pool/shared.qcow2"]) + # the job's VM and its compute's connection are the same host here + for target in ("instances.jobs.wvmInstance", "instances.jobs.wvmConnect", "instances.models.wvmInstance"): + patch(target, return_value=self.proxy).start() + self.addCleanup(patch.stopall) - def destroy(self, undefine_error=None, data=None): - with patch("instances.models.wvmInstance") as wvm: - proxy = wvm.return_value - proxy.instance.isActive.return_value = False - proxy.split_disk_paths_by_use.return_value = (["/pool/own.qcow2"], ["/pool/shared.qcow2"]) - proxy.delete.side_effect = undefine_error - self.client.post(reverse("instances:destroy", args=[self.instance.id]), data or {"delete_disk": "1"}) - return proxy + def queue(self, **data): + self.client.post(reverse("instances:destroy", args=[self.instance.id]), + {"submission_key": "key-destroy01", **data}) + return Operation.objects.get() + + def run_job(self, op): + """The job as the worker runs it; its result.""" + 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() + ctx = Context(op, SimpleNamespace(identity="wvc-test:1:a")) + DeleteInstance().precheck(op, ctx) + return DeleteInstance().run(op, ctx) + + def test_the_page_queues_the_delete_and_changes_nothing(self): + response = self.client.post(reverse("instances:destroy", args=[self.instance.id]), + {"submission_key": "key-destroy01", "delete_disk": "true"}) + self.assertRedirects(response, reverse("instances:instance", args=[self.instance.id]), + fetch_redirect_response=False) + op = Operation.objects.get() + self.assertEqual((op.kind, op.params), ("instance.delete", { + "instance": self.instance.pk, "delete_disk": True, "delete_nvram": False})) + # the whole compute: a file to delete must not be attached meanwhile + self.assertEqual(set(Claim.objects.values_list("resource", "mode")), { + (f"compute:{self.instance.compute_id}", "exclusive"), (f"instance:{UUID}", "exclusive")}) + self.assertEqual(self.proxy.mock_calls, []) def test_the_nvram_goes_only_when_asked(self): for data, wanted, unwanted in ( @@ -38,47 +69,35 @@ class DestroyOrderTestCase(TestCase): ({}, VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM), ): with self.subTest(data=data): - Instance.objects.get_or_create( - compute=self.instance.compute, name="destroy-vm", uuid="11111111-2222-3333-4444-555555555555" - ) - self.instance = Instance.objects.get(uuid="11111111-2222-3333-4444-555555555555") - flags = self.destroy(data=data).delete.call_args[0][0] + self.instance = Instance.objects.get_or_create(compute=self.instance.compute, name="destroy-vm", + uuid=UUID)[0] + Operation.objects.all().delete() + self.run_job(self.queue(**data)) + flags = self.proxy.delete.call_args[0][0] self.assertTrue(flags & wanted) self.assertFalse(flags & unwanted) - def test_the_api_takes_its_options_as_booleans(self): - url = f"/api/v1/computes/{self.instance.compute_id}/instances/{self.instance.id}/" - for body, content_type, deleted in ( - ({"delete_disk": True}, "application/json", True), - ("delete_disk=false", "application/x-www-form-urlencoded", False), - ): - with self.subTest(body=body): - Instance.objects.get_or_create( - compute=self.instance.compute, name="destroy-vm", uuid="11111111-2222-3333-4444-555555555555" - ) - self.instance = Instance.objects.get(uuid="11111111-2222-3333-4444-555555555555") - with patch("instances.models.wvmInstance") as wvm: - proxy = wvm.return_value - proxy.instance.isActive.return_value = False - proxy.split_disk_paths_by_use.return_value = (["/pool/own.qcow2"], []) - url = f"/api/v1/computes/{self.instance.compute_id}/instances/{self.instance.id}/" - response = self.client.delete(url, body, content_type=content_type) - self.assertEqual(response.status_code, 200) - self.assertEqual(proxy.get_volume_by_path.called, deleted) + def test_the_files_are_checked_before_the_vm_is_stopped_and_deleted_after_the_undefine(self): + self.proxy.instance.isActive.return_value = True + op = self.queue(delete_disk="true") + result = self.run_job(op) + calls = [name for name, *_ in self.proxy.mock_calls + if name in ("split_disk_paths_by_use", "force_shutdown", "delete", "get_volume_by_path")] + self.assertEqual(calls, ["split_disk_paths_by_use", "force_shutdown", "delete", "get_volume_by_path"]) + self.proxy.get_volume_by_path.assert_called_once_with("/pool/own.qcow2") + self.assertFalse(Instance.objects.filter(pk=self.instance.pk).exists()) + self.assertEqual(Operation.objects.get().intent["to_delete"], ["/pool/own.qcow2"]) # recorded first + self.assertEqual(result["open"], reverse("instances:index")) + self.assertEqual(words(result["warning"]), "Disk /pool/shared.qcow2 is used by another VM and was kept") + self.assertEqual(list(Logs.objects.exclude(message="Login").values_list("message", "success")), + [("VM destroy-vm: delete volume /pool/own.qcow2", True)]) - def test_the_api_tells_which_disks_were_not_deleted(self): - with patch("instances.models.wvmInstance") as wvm: - proxy = wvm.return_value - proxy.instance.isActive.return_value = False - proxy.split_disk_paths_by_use.return_value = (["/pool/own.qcow2"], ["/pool/shared.qcow2"]) - proxy.backing_path.return_value = None - proxy.get_volume_by_path.return_value.delete.side_effect = libvirtError("Permission denied") - url = f"/api/v1/computes/{self.instance.compute_id}/instances/{self.instance.id}/" - response = self.client.delete(url, {"delete_disk": True}, content_type="application/json") - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json(), {"status": "Instance is destroyed", "messages": [ - "The VM is removed, but disk /pool/own.qcow2 was not deleted: Permission denied", - "Disk /pool/shared.qcow2 is used by another VM and was kept"]}) + def test_a_failed_undefine_deletes_no_disk(self): + self.proxy.delete.side_effect = libvirtError("refused") + with self.assertRaises(libvirtError): + self.run_job(self.queue(delete_disk="true")) + self.proxy.get_volume_by_path.assert_not_called() + self.assertTrue(Instance.objects.filter(pk=self.instance.pk).exists()) def test_a_disk_file_that_stays_keeps_the_files_it_needs(self): # the overlay is not deleted: the file below it would leave it broken @@ -90,64 +109,85 @@ class DestroyOrderTestCase(TestCase): vol.delete.side_effect = libvirtError("Permission denied") return vol - with patch("instances.models.wvmInstance") as wvm: - proxy = wvm.return_value - proxy.instance.isActive.return_value = False - proxy.split_disk_paths_by_use.return_value = (["/pool/vm.snap1", "/pool/vm.qcow2", "/pool/vm-data.qcow2"], []) - proxy.get_volume_by_path.side_effect = volume - proxy.backing_path.side_effect = {"/pool/vm.snap1": "/pool/vm.qcow2"}.get - response = self.client.post(reverse("instances:destroy", args=[self.instance.id]), {"delete_disk": "true"}) + self.proxy.split_disk_paths_by_use.return_value = ( + ["/pool/vm.snap1", "/pool/vm.qcow2", "/pool/vm-data.qcow2"], []) + self.proxy.get_volume_by_path.side_effect = volume + self.proxy.backing_path.side_effect = {"/pool/vm.snap1": "/pool/vm.qcow2"}.get + result = self.run_job(self.queue(delete_disk="true")) self.assertNotIn("/pool/vm.qcow2", volumes) volumes["/pool/vm-data.qcow2"].delete.assert_called_once_with(0) - self.assertEqual([str(m) for m in get_messages(response.wsgi_request)][-1], + # each disk has its own row, and the job's end the VM's (log_entry) + self.assertEqual(list(Logs.objects.exclude(message="Login").values_list("message", "success", "instance_uuid")), [ + ("VM destroy-vm: delete volume /pool/vm.snap1: Permission denied", False, UUID), + ("VM destroy-vm: delete volume /pool/vm-data.qcow2", True, UUID)]) + self.assertEqual(DeleteInstance().log_entry(Operation.objects.get(), Operation.SUCCEEDED), + ("destroy-compute", "destroy-vm", UUID, "VM destroy-vm: delete")) + self.assertEqual(words(result["warning"]), + "The VM is removed, but disk /pool/vm.snap1 was not deleted: Permission denied. " "Disk /pool/vm.qcow2 was kept: a disk file that stays needs it") def test_when_the_files_a_kept_one_needs_are_unknown_none_of_the_rest_goes(self): - with patch("instances.models.wvmInstance") as wvm: - proxy = wvm.return_value - proxy.instance.isActive.return_value = False - proxy.split_disk_paths_by_use.return_value = (["/pool/a.qcow2", "/pool/b.qcow2"], []) - proxy.get_volume_by_path.return_value.delete.side_effect = libvirtError("Permission denied") - proxy.backing_path.side_effect = libvirtError("pool unreachable") - response = self.client.post(reverse("instances:destroy", args=[self.instance.id]), {"delete_disk": "true"}) - self.assertEqual(response.status_code, 302) - proxy.get_volume_by_path.assert_called_once_with("/pool/a.qcow2") - - def test_the_files_are_checked_before_the_vm_is_stopped(self): - with patch("instances.models.wvmInstance") as wvm: - proxy = wvm.return_value - proxy.instance.isActive.return_value = True - proxy.split_disk_paths_by_use.return_value = (["/pool/own.qcow2"], []) - self.client.post(reverse("instances:destroy", args=[self.instance.id]), {"delete_disk": "true"}) - calls = [name for name, *_ in proxy.mock_calls if name in ("split_disk_paths_by_use", "force_shutdown", "delete")] - self.assertEqual(calls, ["split_disk_paths_by_use", "force_shutdown", "delete"]) + self.proxy.split_disk_paths_by_use.return_value = (["/pool/a.qcow2", "/pool/b.qcow2"], []) + self.proxy.get_volume_by_path.return_value.delete.side_effect = libvirtError("Permission denied") + self.proxy.backing_path.side_effect = libvirtError("pool unreachable") + self.run_job(self.queue(delete_disk="true")) + self.proxy.get_volume_by_path.assert_called_once_with("/pool/a.qcow2") def test_a_host_that_cannot_be_checked_stops_nothing(self): Compute.objects.create(name="other-host", hostname="192.0.2.50", login="u", password="p", type=1) + def connect(host, *args): if host == "192.0.2.50": raise libvirtError("unreachable") return MagicMock() - with patch("instances.models.wvmInstance") as wvm, patch("instances.utils.wvmConnect", side_effect=connect): - proxy = wvm.return_value - proxy.instance.isActive.return_value = True - proxy.split_disk_paths_by_use.side_effect = lambda elsewhere: elsewhere(["/pool/own.qcow2"]) - response = self.client.post(reverse("instances:destroy", args=[self.instance.id]), {"delete_disk": "true"}) - proxy.force_shutdown.assert_not_called() - proxy.delete.assert_not_called() + self.proxy.instance.isActive.return_value = True + self.proxy.split_disk_paths_by_use.side_effect = lambda elsewhere: elsewhere(["/pool/own.qcow2"]) + op = self.queue(delete_disk="true") + with patch("instances.utils.wvmConnect", side_effect=connect), \ + self.assertRaisesMessage(ConnectionFailed, "The disk files cannot be checked on other-host"): + self.run_job(op) + self.proxy.force_shutdown.assert_not_called() + self.proxy.delete.assert_not_called() + self.assertFalse(Operation.objects.get().effects_started) # the job fails without recovery self.assertTrue(Instance.objects.filter(pk=self.instance.pk).exists()) - self.assertIn("The disk files cannot be checked on other-host", str(list(get_messages(response.wsgi_request))[-1])) - def test_disks_are_deleted_after_the_undefine(self): - proxy = self.destroy() - proxy.get_volume_by_path.assert_called_once_with("/pool/own.qcow2") + def test_recovery_finishes_a_delete_libvirt_has_done(self): + op = self.queue(delete_disk="true") + Operation.objects.filter(pk=op.pk).update(intent={**op.intent, "to_delete": ["/pool/gone.qcow2", "/pool/own.qcow2"], + "shared": []}) + op.refresh_from_db() + gone = libvirtError("no volume") + gone.err = (VIR_ERR_NO_STORAGE_VOL, 0, "no volume") + self.proxy.get_volume_by_path.side_effect = lambda path: (_ for _ in ()).throw(gone) \ + if path == "/pool/gone.qcow2" else MagicMock() + with patch("instances.jobs._domain", return_value=None): + outcome = DeleteInstance().reconcile(op) + self.assertEqual((outcome.state, outcome.result), (Operation.SUCCEEDED, {"open": reverse("instances:index")})) self.assertFalse(Instance.objects.filter(pk=self.instance.pk).exists()) + self.assertEqual(list(Logs.objects.exclude(message="Login").values_list("message", flat=True)), + ["VM destroy-vm: delete volume /pool/own.qcow2"]) - def test_failed_undefine_deletes_no_disk(self): - proxy = self.destroy(undefine_error=libvirtError("refused")) - proxy.get_volume_by_path.assert_not_called() + def test_recovery_of_a_vm_still_on_its_host_fails(self): + op = self.queue(delete_disk="true") + with patch("instances.jobs._domain", return_value=MagicMock()): + self.assertEqual(DeleteInstance().reconcile(op).state, Operation.FAILED) self.assertTrue(Instance.objects.filter(pk=self.instance.pk).exists()) + self.proxy.get_volume_by_path.assert_not_called() + + def test_the_api_queues_the_delete_with_its_options_as_booleans(self): + url = f"/api/v1/computes/{self.instance.compute_id}/instances/{self.instance.id}/" + for n, (body, content_type, deleted) in enumerate(( + ({"delete_disk": True, "submission_key": "key-api00001"}, "application/json", True), + ("delete_disk=false&submission_key=key-api00002", "application/x-www-form-urlencoded", False), + )): + with self.subTest(body=body): + Operation.objects.all().delete() + response = self.client.delete(url, body, content_type=content_type) + self.assertEqual(response.status_code, 202) + self.assertEqual(Operation.objects.get().params["delete_disk"], deleted) + self.assertEqual(self.client.delete(url, {"delete_disk": True}, content_type="application/json").status_code, + 400) # no submission key def test_destroy_and_delete_vol_hold_the_compute_exclusively(self): calls = [] @@ -158,10 +198,8 @@ class DestroyOrderTestCase(TestCase): yield with patch("instances.views.libvirt_compute_lock", record): - with patch("instances.models.wvmInstance"): - self.client.post(reverse("instances:delete_vol", args=[self.instance.id]), {"dev": "vda"}) - self.destroy() - self.assertEqual(calls, [False, False]) + self.client.post(reverse("instances:delete_vol", args=[self.instance.id]), {"dev": "vda"}) + self.assertEqual(calls, [False]) def test_a_volume_the_vms_snapshots_need_is_kept_after_the_detach(self): disk = {"dev": "vdb", "path": "/pool/data.qcow2", "storage": "default", "image": "data.qcow2"} diff --git a/instances/tests/test_live_dataloss.py b/instances/tests/test_live_dataloss.py index 32c43757..088a2bbf 100644 --- a/instances/tests/test_live_dataloss.py +++ b/instances/tests/test_live_dataloss.py @@ -8,6 +8,8 @@ TEST_LIBVIRT_HOST set (see instances/tests/livetest.py). import os import unittest +from types import SimpleNamespace +from uuid import uuid4 import libvirt from computes.models import Compute @@ -18,7 +20,10 @@ from django.urls import reverse from vrtManager.connection import connection_manager from . import livetest +from instances.jobs import DeleteInstance from instances.models import Instance +from operations.jobs import Context +from operations.models import Operation, acquire from instances.utils import refr P = livetest.PREFIX @@ -75,6 +80,19 @@ class LiveDataLossTestCase(TestCase): HTTP_REFERER=reverse("instances:instance", args=[instance.id]), ) + def destroy(self, instance, data=None): + """The delete page's request, then its job as the worker runs it.""" + response = self.post("destroy", instance, {"submission_key": f"key-{uuid4().hex[:12]}", **(data or {})}) + op = Operation.objects.get(kind="instance.delete", state=Operation.QUEUED) + acquire("live-test:1:a", "live-test") + Operation.objects.filter(pk=op.pk).update(state=Operation.RUNNING, worker="live-test:1:a") + op.refresh_from_db() + ctx = Context(op, SimpleNamespace(identity="live-test:1:a")) + DeleteInstance().precheck(op, ctx) + DeleteInstance().run(op, ctx) + Operation.objects.filter(pk=op.pk).update(state=Operation.SUCCEEDED) + return response + def disk_sources(self, dom, flags=0): from lxml import etree @@ -156,7 +174,7 @@ class LiveDataLossTestCase(TestCase): _, inst = self.vm("r14-a", [shared]) self.vm("r14-b", [shared]) - response = self.post("destroy", inst, {"delete_disk": "1"}) + response = self.destroy(inst, {"delete_disk": "1"}) self.assertEqual(response.status_code, 302) self.assertTrue(livetest.volume_exists(self.conn, shared), "destroy deleted another VM's disk") @@ -175,7 +193,7 @@ class LiveDataLossTestCase(TestCase): if running: dom_b.create() - response = self.post("destroy", inst, {"delete_disk": "1"}) + response = self.destroy(inst, {"delete_disk": "1"}) self.assertEqual(response.status_code, 302) self.assertTrue(livetest.volume_exists(self.conn, base), "deleted the backing file of another VM's disk") @@ -192,7 +210,7 @@ class LiveDataLossTestCase(TestCase): dom.create() dom.managedSave(0) - self.post("destroy", inst, {"delete_disk": "1"}) + self.destroy(inst, {"delete_disk": "1"}) uuid = dom.UUIDString() self.assertFalse(self.domain_exists(uuid), "VM is still defined") @@ -204,7 +222,7 @@ class LiveDataLossTestCase(TestCase): dom.create() dom.suspend() - self.post("destroy", inst) + self.destroy(inst) self.assertFalse(self.domain_exists(dom.UUIDString()), "paused VM is still running") @@ -231,7 +249,7 @@ class LiveDataLossTestCase(TestCase): dom.destroy() self.assertIn(f"{P}r14-nvram_VARS.fd", self.nvram_files()) - self.post("destroy", inst, data) + self.destroy(inst, data) self.assertFalse(self.domain_exists(dom.UUIDString()), "VM is still defined") return f"{P}r14-nvram_VARS.fd" in self.nvram_files() @@ -267,7 +285,7 @@ class LiveDataLossTestCase(TestCase): dom, inst = self.vm("r14-chain", [overlay]) dom.snapshotCreateXML("snap", 0) - response = self.post("destroy", inst, {"delete_disk": "1"}) + response = self.destroy(inst, {"delete_disk": "1"}) self.assertEqual(response.status_code, 302) self.assertFalse(self.domain_exists(dom.UUIDString()), "VM is still defined") @@ -295,7 +313,7 @@ class LiveDataLossTestCase(TestCase): made = {name for name in pool.listVolumes() if name.startswith(P + "r14-ext.")} - {P + "r14-ext.qcow2"} self.assertEqual(len(made), 2, made) # one overlay per snapshot - response = self.post("destroy", inst, {"delete_disk": "1"}) + response = self.destroy(inst, {"delete_disk": "1"}) self.assertEqual(response.status_code, 302) self.assertFalse(self.domain_exists(dom.UUIDString()), "VM is still defined") @@ -313,7 +331,7 @@ class LiveDataLossTestCase(TestCase): inst.proxy.create_external_snapshot("b") inst.proxy.revert_external_snapshot("a") # b's overlay is off the disk's chain now - response = self.post("destroy", inst, {"delete_disk": "1"}) + response = self.destroy(inst, {"delete_disk": "1"}) self.assertEqual(response.status_code, 302) pool = self.conn.storagePoolLookupByName(livetest.POOL) diff --git a/instances/tests/test_live_jobs.py b/instances/tests/test_live_jobs.py index ae143da3..138a9485 100644 --- a/instances/tests/test_live_jobs.py +++ b/instances/tests/test_live_jobs.py @@ -20,7 +20,7 @@ from vrtManager.instance import wvmInstance from appsettings.settings import get_settings from computes.models import Compute -from instances.jobs import DeleteExternalSnapshot +from instances.jobs import DeleteExternalSnapshot, DeleteInstance from instances.models import Instance from operations import jobs from operations.models import Operation @@ -111,6 +111,23 @@ class LiveJobsTestCase(TransactionTestCase): self.assertEqual(op.state, Operation.SUCCEEDED, op.error) return op + def test_the_worker_deletes_a_running_vm_with_its_disk_and_recovery_agrees(self): + disk = livetest.create_volume(self.conn, P + "job-delete") + dom = livetest.define_vm(self.conn, P + "job-delete", [disk]) + dom.create() + instance = Instance.objects.create(compute=self.compute, name=dom.name(), uuid=dom.UUIDString()) + op = self.run_job(jobs.submit("instance.delete", self.admin, {"instance": instance.pk, "delete_disk": True}, + "key-delete01")) + self.assertEqual(op.result, {"open": reverse("instances:index")}) + self.assertFalse(Instance.objects.filter(pk=instance.pk).exists()) + self.assertFalse(livetest.volume_exists(self.conn, disk)) + with self.assertRaises(libvirt.libvirtError): + self.conn.lookupByUUIDString(op.intent["uuid"]) + # a worker that stopped after the undefine: recovery finds the work done + Operation.objects.filter(pk=op.pk).update(state=Operation.RUNNING) + op.refresh_from_db() + self.assertEqual(DeleteInstance().reconcile(op).state, Operation.SUCCEEDED) + def test_snapshot_create_and_revert_run_as_jobs(self): running, _vm = self.vm("smoke-ext", "running") stopped, _vm = self.vm("smoke-int") diff --git a/instances/tests/test_moved_while_waiting.py b/instances/tests/test_moved_while_waiting.py index 64c70fb0..a54fdb57 100644 --- a/instances/tests/test_moved_while_waiting.py +++ b/instances/tests/test_moved_while_waiting.py @@ -12,7 +12,10 @@ from django.test import TestCase from django.urls import reverse from computes.models import Compute +from instances.jobs import DeleteInstance from instances.models import Instance +from operations.models import Operation +from vrtManager.util import OperationError class MovedWhileWaitingTestCase(TestCase): @@ -54,18 +57,11 @@ class MovedWhileWaitingTestCase(TestCase): self.assertTrue(touched) def test_destroy_of_a_vm_moved_while_it_waited_is_not_run(self): - # destroy holds the whole compute; the migration moved the VM before - # releasing it - @contextmanager - def compute_lock_after_a_migration(compute, *, shared=False): - Instance.objects.filter(pk=self.vm.pk).update(compute=self.target) - yield - - with patch("instances.views.libvirt_compute_lock", compute_lock_after_a_migration), patch( - "instances.models.wvmInstance" - ) as wvm, patch.object(Compute, "status", new_callable=PropertyMock, return_value=True): - response = self.client.post(reverse("instances:destroy", args=[self.vm.id]), {"delete_disk": "on"}) - self.assertFalse(wvm.return_value.delete.called) - self.assertTrue(Instance.objects.filter(pk=self.vm.pk).exists()) - messages = [str(m) for m in response.wsgi_request._messages] - self.assertIn("The VM was moved meanwhile; try again.", messages) + # the delete job holds the whole compute; a migration moved the VM before it ran + with patch("instances.models.wvmInstance"): + self.client.post(reverse("instances:destroy", args=[self.vm.id]), + {"delete_disk": "on", "submission_key": "key-moved001"}) + op = Operation.objects.get(kind="instance.delete") + Instance.objects.filter(pk=self.vm.pk).update(compute=self.target) + with self.assertRaisesMessage(OperationError, "The VM moved to another compute"): + DeleteInstance().precheck(op, None) diff --git a/instances/tests/test_security_mutations.py b/instances/tests/test_security_mutations.py index 8b8ee757..d88f9d9a 100644 --- a/instances/tests/test_security_mutations.py +++ b/instances/tests/test_security_mutations.py @@ -9,6 +9,7 @@ from django.urls import reverse from accounts.models import UserInstance from computes.models import Compute from instances.models import Instance +from operations.models import Operation from operations import claims from instances.views import get_instance @@ -257,11 +258,11 @@ class InstanceSecurityMutationsTestCase(TestCase): # 3. Superuser can destroy VM self.client.force_login(self.superuser) - with patch("instances.models.wvmInstance") as mock_wvm_cls: - mock_wvm_cls.return_value.get_status.return_value = 5 # shutoff - res = self.client.post(reverse("instances:destroy", args=[self.instance.id]), {}) + with patch("instances.models.wvmInstance"): + res = self.client.post(reverse("instances:destroy", args=[self.instance.id]), + {"submission_key": "key-destroy01"}) self.assertEqual(res.status_code, 302) - self.assertFalse(Instance.objects.filter(id=self.instance.id).exists()) + self.assertTrue(Operation.objects.filter(kind="instance.delete").exists()) # queued def test_migration_deduplicate_instances_logic(self): import importlib diff --git a/instances/tests/test_template_rules.py b/instances/tests/test_template_rules.py index 8b589a0d..fb352086 100644 --- a/instances/tests/test_template_rules.py +++ b/instances/tests/test_template_rules.py @@ -12,6 +12,7 @@ from rest_framework.test import APIClient from accounts.models import UserInstance from computes.models import Compute from instances.models import Instance +from operations.models import Operation class TemplateRulesTestCase(TestCase): @@ -46,10 +47,9 @@ class TemplateRulesTestCase(TestCase): self.assertFalse(wvm.return_value.delete.called) self.client.force_login(self.staff) - with patch("instances.models.wvmInstance") as wvm: - wvm.return_value.instance.isActive.return_value = False - self.client.post(reverse("instances:destroy", args=[self.template.id])) - self.assertTrue(wvm.return_value.delete.called) + with patch("instances.models.wvmInstance"): + self.client.post(reverse("instances:destroy", args=[self.template.id]), {"submission_key": "key-tpldel01"}) + self.assertTrue(Operation.objects.filter(kind="instance.delete").exists()) # queued def test_the_destroy_confirmation_page_offers_the_form_to_who_may_delete(self): url = reverse("instances:destroy", args=[self.template.id]) diff --git a/instances/tests/test_vm_audit_rows.py b/instances/tests/test_vm_audit_rows.py index 6491d147..173ffd9b 100644 --- a/instances/tests/test_vm_audit_rows.py +++ b/instances/tests/test_vm_audit_rows.py @@ -143,17 +143,6 @@ class VMRowTests(TestCase): self.assertEqual(self.rows(), [("VM vm: set console password", True)]) self.proxy.set_console_listener_addr.assert_not_called() - def test_a_deleted_vm_and_each_of_its_disks_have_their_own_row(self): - self.proxy.split_disk_paths_by_use.return_value = (["/pool/a.qcow2", "/pool/b.qcow2"], []) - volume = self.proxy.get_volume_by_path.return_value - volume.delete.side_effect = [libvirtError("Permission denied"), None] - self.client.post(reverse("instances:destroy", args=[self.vm.pk]), {"delete_disk": "1"}) - self.assertFalse(Instance.objects.filter(pk=self.vm.pk).exists()) - self.assertEqual(self.rows(), [("VM vm: delete", True), - ("VM vm: delete volume /pool/a.qcow2: Permission denied", False), - ("VM vm: delete volume /pool/b.qcow2", True)]) - self.assertEqual(set(Logs.objects.values_list("instance_uuid", flat=True)), {UUID}) - def test_a_disk_delete_logs_the_detach_and_the_volume(self): disk = {"dev": "vdb", "path": "/pool/data.qcow2", "storage": "default", "image": "data.qcow2"} self.proxy.get_disk_devices.return_value = [disk] diff --git a/instances/views.py b/instances/views.py index 3e0d8af5..9a6b1bc7 100755 --- a/instances/views.py +++ b/instances/views.py @@ -42,10 +42,6 @@ from django.views.decorators.debug import sensitive_post_parameters from libvirt import (VIR_DOMAIN_PAUSED, VIR_DOMAIN_RUNNING, VIR_DOMAIN_SHUTOFF, - VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, - VIR_DOMAIN_UNDEFINE_MANAGED_SAVE, - VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, - VIR_DOMAIN_UNDEFINE_NVRAM, VIR_DOMAIN_XML_INACTIVE, VIR_ERR_NO_DOMAIN, VIR_ERR_NO_SUPPORT, @@ -861,62 +857,21 @@ def force_off(request, pk): ) -@serialize_compute_mutation def destroy(request, pk): if request.method in ["POST", "DELETE"]: - instance = get_instance(request.user, pk, perm_type="delete") - # an API request is a DRF request whose body is in .data; refused - # options stop nothing - options = DestroyOptionsSerializer(data=getattr(request, "data", request.POST)) + get_instance(request.user, pk, perm_type="delete") + options = DestroyOptionsSerializer(data=request.POST) options.is_valid(raise_exception=True) - with libvirt_instance_lock(instance): - with audit_vm(request, instance, "delete"): - proxy = instance.proxy - # the files to delete are known before the VM is stopped: a - # host that cannot be checked refuses the destruction - to_delete, shared = [], [] - if options.validated_data["delete_disk"]: - to_delete, shared = proxy.split_disk_paths_by_use( - lambda own: utils.paths_used_on_other_computes(instance.compute, own)) - - # Paused and other active states must stop too, or the VM keeps - # running as a transient domain after the undefine. - if proxy.instance.isActive(): - proxy.force_shutdown() - - # Undefine before deleting any disk: if it fails, nothing is lost. - # Snapshot metadata goes with the domain; internal snapshot data - # stays in the disk images that are kept. - flags = VIR_DOMAIN_UNDEFINE_MANAGED_SAVE | VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA - if options.validated_data["delete_nvram"]: - flags |= VIR_DOMAIN_UNDEFINE_NVRAM - else: - flags |= VIR_DOMAIN_UNDEFINE_KEEP_NVRAM - proxy.delete(flags) - instance.delete() - - # each disk has its own row: the VM is gone even if one is kept; a - # file that stays keeps the files below it, which it needs - kept = set() - for path in to_delete: - if path in kept: - messages.warning(request, _("Disk %(path)s was kept: a disk file that stays needs it") % {"path": path}) - continue - try: - with audit_vm(request, instance, f"delete volume {path}"): - proxy.get_volume_by_path(path).delete(0) - except libvirtError as err: - messages.error(request, _("The VM is removed, but disk %(path)s was not deleted: %(err)s") % { - "path": path, "err": error_text(request, err)}) - try: - while (path := proxy.backing_path(path)) and path not in kept: - kept.add(path) - except libvirtError: - # the files it needs are unknown: none of the rest goes - kept.update(to_delete) - for path in shared: - messages.warning(request, _("Disk %(path)s is used by another VM and was kept") % {"path": path}) - return redirect(reverse("instances:index")) + try: + op = jobs.submit("instance.delete", request.user, {"instance": pk, **options.validated_data}, + request.POST.get("submission_key", "")) + except claims.Busy as busy: + return _busy(request, pk, busy) + except (jobs.SubmissionConflict, libvirtError) as err: + messages.error(request, error_text(request, err)) + return redirect(reverse("instances:destroy", args=[pk])) + jobs.remember_job(request, op) + return redirect(reverse("instances:instance", args=[pk])) instance = get_instance(request.user, pk, perm_type="delete") try: diff --git a/locale/tr/LC_MESSAGES/django.mo b/locale/tr/LC_MESSAGES/django.mo index ef6aa6fd01f70e260bc728093b3780cbb696430f..4bf1a92528b1fa0ca8b78917ff05d63e84327c2f 100644 GIT binary patch delta 43256 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 H$t(RI4O8`@ diff --git a/locale/tr/LC_MESSAGES/django.po b/locale/tr/LC_MESSAGES/django.po index b9b6285b..820a44d1 100644 --- a/locale/tr/LC_MESSAGES/django.po +++ b/locale/tr/LC_MESSAGES/django.po @@ -284,7 +284,7 @@ msgstr "Burada oturumunuz açık kalır; diğer oturumlarınız kapanır." #: instances/templates/add_instance_volume.html:108 #: instances/templates/create_instance_w1.html:40 #: instances/templates/create_instance_w2.html:355 -#: instances/templates/instances/destroy_instance_form.html:51 +#: instances/templates/instances/destroy_instance_form.html:52 #: instances/templates/instances/edit_instance_volume.html:111 #: instances/templates/instances/move_disk.html:27 #: instances/templates/instances/settings_tab.html:411 @@ -915,7 +915,7 @@ msgid "IP" msgstr "IP" #: admin/templates/admin/logs.html:56 admin/views.py:286 instances/states.py:19 -#: instances/views.py:419 instances/views.py:421 logs/views.py:17 +#: instances/views.py:415 instances/views.py:417 logs/views.py:17 msgid "Unknown" msgstr "Bilinmeyen" @@ -1714,7 +1714,7 @@ msgid "New VM defaults" msgstr "Yeni sanal makine varsayılanları" #: appsettings/views.py:40 instances/templates/instance.html:64 -#: instances/templates/instances/destroy_instance_form.html:32 +#: instances/templates/instances/destroy_instance_form.html:33 #: instances/templates/instances/resize_tab.html:20 #: instances/templates/instances/settings_tab.html:197 msgid "Disks" @@ -2704,57 +2704,57 @@ msgstr "" msgid "The name of the virtual machine must not contain any special characters" msgstr "Sanal makine adı özel karakterler içeremez" -#: instances/jobs.py:69 +#: instances/jobs.py:72 msgid "The VM moved to another compute after the job was queued" msgstr "İş kuyruğa alındıktan sonra sanal makine başka bir sunucuya taşındı" -#: instances/jobs.py:137 +#: instances/jobs.py:140 msgid "Enter a whole number of vCPUs for the clone" msgstr "Klon için vCPU sayısını tam sayı olarak girin" -#: instances/jobs.py:139 +#: instances/jobs.py:142 msgid "Enter a whole number of memory (MiB) for the clone" msgstr "Klon için belleği (MiB) tam sayı olarak girin" -#: instances/jobs.py:166 +#: instances/jobs.py:169 msgid "Choose the clone's name from the list of free names" msgstr "Klonun adını boş adlar listesinden seçin" -#: instances/jobs.py:194 +#: instances/jobs.py:197 #, python-format msgid "%(quota)s: cannot create '%(clone_name)s'." msgstr "%(quota)s: '%(clone_name)s' oluşturulamıyor." -#: instances/jobs.py:197 instances/jobs.py:549 +#: instances/jobs.py:200 instances/jobs.py:552 #, python-format msgid "Instance '%(clone_name)s' already exists!" msgstr "'%(clone_name)s' sanal makinesi zaten mevcut!" -#: instances/jobs.py:199 +#: instances/jobs.py:202 #, python-format msgid "Instance name '%(clone_name)s' contains invalid characters!" msgstr "Sanal makine adı '%(clone_name)s' geçersiz karakterler içermektedir!" -#: instances/jobs.py:202 +#: instances/jobs.py:205 #, python-format msgid "Instance MAC '%(clone_mac)s' invalid format!" msgstr "Sanal makine MAC adresi '%(clone_mac)s' geçersiz biçemde belirtilmiş!" -#: instances/jobs.py:204 +#: instances/jobs.py:207 #, python-format msgid "Disk name '%(disk_name)s' contains invalid characters!" msgstr "Disk adı '%(disk_name)s' geçersiz karakterler içeriyor!" -#: instances/jobs.py:224 +#: instances/jobs.py:227 #, python-format msgid "The clone is made, but not as asked: %(error)s" msgstr "Klon oluşturuldu, ama istendiği gibi değil: %(error)s" -#: instances/jobs.py:280 +#: instances/jobs.py:283 msgid "The VM was not defined and no volume of it was left." msgstr "Sanal makine tanımlanmadı ve ondan geriye birim kalmadı." -#: instances/jobs.py:282 +#: instances/jobs.py:285 #, python-format msgid "" "The VM was not defined; check these volumes, then resolve this job: " @@ -2763,28 +2763,28 @@ msgstr "" "Sanal makine tanımlanmadı; şu birimleri kontrol edin, sonra bu işi çözün: " "%(volumes)s" -#: instances/jobs.py:303 +#: instances/jobs.py:306 msgid "Delete snapshot" msgstr "Anlık görüntüyü sil" -#: instances/jobs.py:313 vrtManager/instance.py:2299 +#: instances/jobs.py:316 vrtManager/instance.py:2287 #, python-format msgid "The VM has no external snapshot named %(name)s" msgstr "Sanal makinede %(name)s adında harici anlık görüntü yok" -#: instances/jobs.py:326 +#: instances/jobs.py:329 msgid "Merging the snapshot" msgstr "Anlık görüntü birleştiriliyor" -#: instances/jobs.py:345 +#: instances/jobs.py:348 msgid "The VM is no longer on its compute" msgstr "Sanal makine artık kendi sunucusunda değil" -#: instances/jobs.py:348 +#: instances/jobs.py:351 msgid "libvirt is still merging the snapshot" msgstr "libvirt anlık görüntüyü hâlâ birleştiriyor" -#: instances/jobs.py:356 +#: instances/jobs.py:359 msgid "" "The snapshot is still listed and no merge runs. It cannot be told whether the" " disks changed; check the VM before deleting the snapshot again or reverting " @@ -2794,44 +2794,44 @@ msgstr "" "değişmediği bilinemiyor; anlık görüntüyü yeniden silmeden ya da ona dönmeden " "önce sanal makineyi kontrol edin." -#: instances/jobs.py:363 +#: instances/jobs.py:366 msgid "The VM is no longer on the compute the job ran on" msgstr "Sanal makine artık işin çalıştığı sunucuda değil" -#: instances/jobs.py:369 +#: instances/jobs.py:372 msgid "Take snapshot" msgstr "Anlık görüntü al" -#: instances/jobs.py:381 instances/jobs.py:390 vrtManager/instance.py:1895 +#: instances/jobs.py:384 instances/jobs.py:393 vrtManager/instance.py:1883 #, python-format msgid "A snapshot named %(name)s already exists" msgstr "%(name)s adında bir anlık görüntü zaten var" -#: instances/jobs.py:396 +#: instances/jobs.py:399 msgid "Taking the snapshot" msgstr "Anlık görüntü alınıyor" -#: instances/jobs.py:409 +#: instances/jobs.py:412 msgid "libvirt is still taking the snapshot" msgstr "libvirt anlık görüntüyü hâlâ alıyor" -#: instances/jobs.py:412 +#: instances/jobs.py:415 msgid "The snapshot was not taken" msgstr "Anlık görüntü alınmadı" -#: instances/jobs.py:435 +#: instances/jobs.py:438 msgid "Revert snapshot" msgstr "Snapshota dön" -#: instances/jobs.py:466 +#: instances/jobs.py:469 msgid "Reverting the VM" msgstr "Sanal makine geri döndürülüyor" -#: instances/jobs.py:477 +#: instances/jobs.py:480 msgid "libvirt is still reverting the VM" msgstr "libvirt sanal makineyi hâlâ geri döndürüyor" -#: instances/jobs.py:481 +#: instances/jobs.py:484 msgid "" "It cannot be told whether the VM was reverted; check it, then revert again or" " resolve this job." @@ -2839,12 +2839,12 @@ msgstr "" "Sanal makinenin geri döndürülüp döndürülmediği bilinemiyor; kontrol edin, " "sonra yeniden geri döndürün ya da bu işi çözün." -#: instances/jobs.py:498 +#: instances/jobs.py:501 msgid "The VM must be running, paused or shut off to be cloned" msgstr "" "Klonlanmak için sanal makine çalışıyor, duraklatılmış ya da kapalı olmalı" -#: instances/jobs.py:499 +#: instances/jobs.py:502 #, python-format msgid "" "The guest's file systems could not be thawed (%(error)s); thaw them with: " @@ -2853,19 +2853,19 @@ msgstr "" "Konuğun dosya sistemleri çözülemedi (%(error)s); şununla çözün: virsh " "domfsthaw %(vm)s" -#: instances/jobs.py:518 +#: instances/jobs.py:521 msgid "Clone VM" msgstr "Sanal makineyi klonla" -#: instances/jobs.py:559 instances/jobs.py:566 instances/jobs.py:841 +#: instances/jobs.py:562 instances/jobs.py:569 instances/jobs.py:844 msgid "Copying disks" msgstr "Diskler kopyalanıyor" -#: instances/jobs.py:618 +#: instances/jobs.py:621 msgid "libvirt has no result of the copy" msgstr "libvirt'te kopyanın sonucu yok" -#: instances/jobs.py:629 +#: instances/jobs.py:632 #, python-format msgid "" "The copy failed: %(error)s. The guest's file systems could not be thawed " @@ -2874,11 +2874,11 @@ 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:632 instances/jobs.py:716 +#: instances/jobs.py:635 instances/jobs.py:719 msgid "The copy failed" msgstr "Kopyalama başarısız oldu" -#: instances/jobs.py:657 +#: instances/jobs.py:660 #, python-format msgid "" "The VM is no longer on the compute the job ran on; check these volumes, then " @@ -2887,7 +2887,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:692 +#: instances/jobs.py:695 #, python-format msgid "" "A volume of the clone was being created; check these volumes, then resolve " @@ -2896,15 +2896,15 @@ msgstr "" "Klonun bir birimi oluşturuluyordu; şu birimleri kontrol edin, sonra bu işi " "çözün: %(volumes)s" -#: instances/jobs.py:696 +#: instances/jobs.py:699 msgid "The job stopped before the copy started" msgstr "İş, kopyalama başlamadan durdu" -#: instances/jobs.py:703 +#: instances/jobs.py:706 msgid "libvirt is still copying the disks" msgstr "libvirt diskleri hâlâ kopyalıyor" -#: instances/jobs.py:706 +#: instances/jobs.py:709 #, python-format msgid "" "Another backup runs on the VM; check these volumes, then resolve this job: " @@ -2913,7 +2913,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:711 +#: instances/jobs.py:714 #, python-format msgid "" "libvirt has no result of the copy; check these volumes, then resolve this " @@ -2922,7 +2922,7 @@ msgstr "" "libvirt'te kopyanın sonucu yok; şu birimleri kontrol edin, sonra bu işi " "çözün: %(volumes)s" -#: instances/jobs.py:723 +#: instances/jobs.py:726 #, python-format msgid "" "The disks were copied, but the clone could not be defined: %(error)s; check " @@ -2931,156 +2931,184 @@ msgstr "" "Diskler kopyalandı, ancak klon tanımlanamadı: %(error)s; şu birimleri kontrol" " edin, sonra bu işi çözün: %(volumes)s" -#: instances/jobs.py:746 instances/templates/create_instance_w1.html:60 +#: instances/jobs.py:749 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:770 instances/jobs.py:815 instances/views.py:2504 +#: instances/jobs.py:773 instances/jobs.py:818 instances/views.py:2459 msgid "A virtual machine with this name already exists" msgstr "Bu isimde bir sanal makine mevcut" -#: instances/jobs.py:772 instances/jobs.py:812 +#: instances/jobs.py:775 instances/jobs.py:815 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:775 +#: instances/jobs.py:778 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:777 +#: instances/jobs.py:780 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:779 +#: instances/jobs.py:782 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:781 +#: instances/jobs.py:784 msgid "Invalid cache mode" msgstr "Geçersiz önbellek modu" -#: instances/jobs.py:783 +#: instances/jobs.py:786 #, 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:785 +#: instances/jobs.py:788 #, python-format msgid "A CD-ROM cannot use the %(bus)s bus" msgstr "CD-ROM %(bus)s veri yolunu kullanamaz" -#: instances/jobs.py:788 +#: instances/jobs.py:791 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:791 +#: instances/jobs.py:794 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:797 +#: instances/jobs.py:800 #, python-format msgid "This host offers no firmware %(firmware)s" msgstr "Bu sunucu %(firmware)s firmware'ini sunmuyor" -#: instances/jobs.py:799 vrtManager/instance.py:3023 +#: instances/jobs.py:802 vrtManager/instance.py:3011 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:860 +#: instances/jobs.py:863 msgid "Writing the cloud-init seed" msgstr "cloud-init tohumu yazılıyor" -#: instances/jobs.py:867 +#: instances/jobs.py:870 msgid "Defining the VM" msgstr "Sanal makine tanımlanıyor" -#: instances/jobs.py:900 +#: instances/jobs.py:903 #, python-format msgid "%(error)s. Remove these volumes by hand: %(volumes)s" msgstr "%(error)s. Şu birimleri elle silin: %(volumes)s" -#: instances/jobs.py:925 +#: instances/jobs.py:928 #, python-format msgid "The instance is already on %(compute)s" msgstr "Sanal makine zaten %(compute)s üzerinde" -#: instances/jobs.py:927 +#: instances/jobs.py:930 #, python-format msgid "%(compute)s is not reachable" msgstr "%(compute)s sunucusuna ulaşılamıyor" -#: instances/jobs.py:929 +#: instances/jobs.py:932 #, 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:963 +#: instances/jobs.py:966 #, 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:969 +#: instances/jobs.py:972 #, 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:976 +#: instances/jobs.py:979 msgid "Migrate VM" msgstr "Sanal makineyi taşı" -#: instances/jobs.py:1023 +#: instances/jobs.py:1026 msgid "Migrating the VM" msgstr "Sanal makine taşınıyor" -#: instances/jobs.py:1070 +#: instances/jobs.py:1073 msgid "libvirt is still migrating the VM" msgstr "libvirt sanal makineyi hâlâ taşıyor" -#: instances/jobs.py:1079 +#: instances/jobs.py:1084 msgid "The VM stayed on the source host" msgstr "Sanal makine kaynak sunucuda kaldı" -#: instances/jobs.py:1081 +#: instances/jobs.py:1086 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:1129 +#: instances/jobs.py:1134 msgid "Move disk" msgstr "Diski taşı" -#: instances/jobs.py:1136 +#: instances/jobs.py:1141 msgid "Choose a disk of the VM" msgstr "Sanal makinenin bir diskini seçin" -#: instances/jobs.py:1160 +#: instances/jobs.py:1165 msgid "Copying the disk" msgstr "Disk kopyalanıyor" -#: instances/jobs.py:1203 +#: instances/jobs.py:1208 #, 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:1209 +#: instances/jobs.py:1214 #, 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:1211 +#: instances/jobs.py:1216 #, 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 +#, 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 +#, 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 +#, 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 +msgid "Delete VM" +msgstr "Sanal makineyi sil" + +#: instances/jobs.py:1309 +msgid "Deleting the VM" +msgstr "Sanal makine siliniyor" + +#: instances/jobs.py:1321 +msgid "The VM was not deleted; it may have been shut off" +msgstr "Sanal makine silinmedi; kapatılmış olabilir" + #: instances/models.py:18 msgid "label" msgstr "etiket" @@ -3308,7 +3336,7 @@ msgid "Disk source" msgstr "Disk kaynağı" #: instances/templates/add_instance_volume.html:21 -#: instances/templates/create_instance_w2.html:134 instances/views.py:2523 +#: instances/templates/create_instance_w2.html:134 instances/views.py:2478 msgid "New disk" msgstr "Yeni disk" @@ -3680,7 +3708,7 @@ msgstr "Özel CPU modelleri" msgid "Size (GiB)" msgstr "Boyut (GiB)" -#: instances/templates/create_instance_w2.html:161 instances/views.py:2524 +#: instances/templates/create_instance_w2.html:161 instances/views.py:2479 msgid "Existing volumes" msgstr "Mevcut birimler" @@ -3716,7 +3744,7 @@ msgstr "Aygıt" msgid "Remove" msgstr "Kaldır" -#: instances/templates/create_instance_w2.html:194 instances/views.py:2525 +#: instances/templates/create_instance_w2.html:194 instances/views.py:2480 msgid "Clone from template" msgstr "Şablondan klonla" @@ -4060,18 +4088,18 @@ msgstr "%(kind)s %(name)s yukarı taşı" msgid "Move %(kind)s %(name)s down" msgstr "%(kind)s %(name)s aşağı taşı" -#: instances/templates/instances/destroy_instance_form.html:3 -#: instances/templates/instances/destroy_instance_form.html:6 +#: instances/templates/instances/destroy_instance_form.html:4 +#: instances/templates/instances/destroy_instance_form.html:7 #, python-format msgid "Destroy %(name)s" msgstr "%(name)s sanal makinesini sil" -#: instances/templates/instances/destroy_instance_form.html:6 +#: instances/templates/instances/destroy_instance_form.html:7 #, python-format msgid "on %(host)s" msgstr "%(host)s üzerinde" -#: instances/templates/instances/destroy_instance_form.html:10 +#: instances/templates/instances/destroy_instance_form.html:11 msgid "" "The VM's definition, saved state and snapshot records are removed. A running " "VM is forced off first; what the guest has not written to disk is lost." @@ -4080,15 +4108,15 @@ msgstr "" " Çalışan bir sanal makine önce zorla kapatılır; konuk sistemin diske " "yazmadıkları kaybolur." -#: instances/templates/instances/destroy_instance_form.html:13 +#: instances/templates/instances/destroy_instance_form.html:14 msgid "What should happen to the files?" msgstr "Dosyalara ne olsun?" -#: instances/templates/instances/destroy_instance_form.html:18 +#: instances/templates/instances/destroy_instance_form.html:19 msgid "Delete disk files" msgstr "Disk dosyalarını sil" -#: instances/templates/instances/destroy_instance_form.html:19 +#: instances/templates/instances/destroy_instance_form.html:20 msgid "" "With them go this VM's external snapshot files, snapshot memory files and " "cloud-init seed." @@ -4096,11 +4124,11 @@ msgstr "" "Onlarla birlikte bu sanal makinenin harici anlık görüntü dosyaları, anlık " "görüntü bellek dosyaları ve cloud-init tohumu da silinir." -#: instances/templates/instances/destroy_instance_form.html:25 +#: instances/templates/instances/destroy_instance_form.html:26 msgid "Keep the disk files" msgstr "Disk dosyalarını koru" -#: instances/templates/instances/destroy_instance_form.html:26 +#: instances/templates/instances/destroy_instance_form.html:27 msgid "" "They stay with their internal snapshot data; the snapshot records still go " "with the VM." @@ -4108,11 +4136,11 @@ msgstr "" "Dosyalar iç anlık görüntü verileriyle birlikte kalır; anlık görüntü kayıtları" " yine de sanal makineyle birlikte silinir." -#: instances/templates/instances/destroy_instance_form.html:35 +#: instances/templates/instances/destroy_instance_form.html:36 msgid "no file" msgstr "dosya yok" -#: instances/templates/instances/destroy_instance_form.html:39 +#: instances/templates/instances/destroy_instance_form.html:40 msgid "" "A file another VM uses on any of the panel's hosts, directly or under its own" " disk, is kept, and so is the template a disk was made from. If a host cannot" @@ -4122,23 +4150,23 @@ msgstr "" "kendi diskinin altında kullandığı dosyalar korunur; bir diskin oluşturulduğu " "şablon da korunur. Bir sunucu denetlenemezse sanal makine silinmez." -#: instances/templates/instances/destroy_instance_form.html:43 +#: instances/templates/instances/destroy_instance_form.html:44 msgid "Delete the NVRAM file (firmware settings). Untick to keep it." msgstr "" "NVRAM dosyasını (ürün yazılımı ayarları) sil. Korumak için işareti kaldırın." -#: instances/templates/instances/destroy_instance_form.html:47 +#: instances/templates/instances/destroy_instance_form.html:48 msgid "" "Its TPM state is deleted with it, and the keys in it, such as BitLocker's." msgstr "" "TPM durumu da onunla birlikte silinir, içindeki anahtarlar da, örneğin " "BitLocker'ınkiler." -#: instances/templates/instances/destroy_instance_form.html:50 +#: instances/templates/instances/destroy_instance_form.html:51 msgid "This cannot be undone." msgstr "Bu işlem geri alınamaz." -#: instances/templates/instances/destroy_instance_form.html:52 +#: instances/templates/instances/destroy_instance_form.html:53 msgid "Destroy VM" msgstr "Sanal makineyi sil" @@ -5879,43 +5907,43 @@ msgstr "Geçersiz MAC adresi" msgid "More MAC addresses than networks" msgstr "Ağlardan daha fazla MAC adresi" -#: instances/views.py:173 +#: instances/views.py:169 msgid "Enter an IP address, a network such as 192.0.2.0/24, or a MAC address." msgstr "Bir IP adresi, 192.0.2.0/24 gibi bir ağ ya da bir MAC adresi girin." -#: instances/views.py:179 instances/views.py:213 +#: instances/views.py:175 instances/views.py:209 msgid "Too many searches are still running; try again shortly." msgstr "Çok fazla arama hâlâ çalışıyor; birazdan yeniden deneyin." -#: instances/views.py:261 +#: instances/views.py:257 #, python-format msgid "The host %(host)s of '%(name)s' cannot be reached: %(error)s" msgstr "'%(name)s' sanal makinesinin sunucusu %(host)s erişilemiyor: %(error)s" -#: instances/views.py:267 +#: instances/views.py:263 #, python-format msgid "The host of '%(name)s' cannot be reached right now." msgstr "'%(name)s' sanal makinesinin sunucusuna şu anda erişilemiyor." -#: instances/views.py:268 +#: instances/views.py:264 msgid " Jobs on it can be followed under Jobs in the menu." msgstr " Üzerindeki işler menüdeki İşler bölümünden izlenebilir." -#: instances/views.py:276 +#: instances/views.py:272 #, python-format msgid "'%(name)s' is no longer on its host." msgstr "'%(name)s' artık sunucusunda yok." -#: instances/views.py:374 +#: instances/views.py:370 msgid "There is no other host to migrate to." msgstr "Taşınacak başka bir sunucu yok." -#: instances/views.py:376 +#: instances/views.py:372 msgid "A VM migrates when it is running, paused or shut off." msgstr "" "Sanal makine çalışırken, duraklatılmışken ya da kapalıyken taşınabilir." -#: instances/views.py:378 +#: instances/views.py:374 msgid "" "A VM with snapshots cannot be migrated: its snapshots stay on this host. " "Delete them first." @@ -5923,7 +5951,7 @@ msgstr "" "Anlık görüntüsü olan bir sanal makine taşınamaz: anlık görüntüleri bu " "sunucuda kalır. Önce onları silin." -#: instances/views.py:380 +#: instances/views.py:376 msgid "" "A VM with host devices cannot be migrated: the destination may not have them." " Remove them first." @@ -5931,11 +5959,11 @@ msgstr "" "Sunucu aygıtları olan bir sanal makine taşınamaz: hedefte bu aygıtlar " "olmayabilir. Önce onları kaldırın." -#: instances/views.py:644 +#: instances/views.py:640 msgid "The VM was moved meanwhile; try again." msgstr "Sanal makine bu arada taşındı; yeniden deneyin." -#: instances/views.py:760 +#: instances/views.py:756 msgid "" "The running VM has no free PCI slot for another disk on this bus: choose the " "scsi bus if the VM has a SCSI controller, or shut the VM down and add the " @@ -5948,7 +5976,7 @@ msgstr "" "yuvaları ekle, sonraki başlatmadan itibaren ona boş yuvalar verir. Yeni bir " "birim havuzunda kalır, mevcut birim olarak eklenebilir." -#: instances/views.py:764 +#: instances/views.py:760 msgid "" "The running VM has no free PCI slot for the SCSI controller the disk needs: " "shut the VM down and add the disk then; Add PCIe slots on the Disks tab gives" @@ -5960,191 +5988,175 @@ msgstr "" "PCIe yuvaları ekle, sonraki başlatmadan itibaren ona boş yuvalar verir. Yeni " "bir birim havuzunda kalır, mevcut birim olarak eklenebilir." -#: instances/views.py:782 +#: instances/views.py:778 #, python-format msgid "Invalid disk options: %(options)s" msgstr "Geçersiz disk seçenekleri: %(options)s" -#: instances/views.py:792 instances/views.py:807 +#: instances/views.py:788 instances/views.py:803 msgid "Templates cannot be started." msgstr "Şablon makineler başlatılamaz." -#: instances/views.py:903 -#, 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/views.py:909 -#, 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/views.py:918 -#, 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/views.py:1040 +#: instances/views.py:995 #, python-format msgid "Set the gstfsd key of %(compute)s first (Computes, edit the host)" msgstr "" "Önce %(compute)s sunucusunun gstfsd anahtarını ayarlayın (Sunucular, sunucuyu" " düzenle)" -#: instances/views.py:1047 instances/views.py:1065 instances/views.py:1074 +#: instances/views.py:1002 instances/views.py:1020 instances/views.py:1029 #, python-format msgid "gstfsd error: %(err)s" msgstr "gstfsd hatası: %(err)s" -#: instances/views.py:1075 +#: instances/views.py:1030 msgid "the reply is not signed with the key" msgstr "yanıt anahtarla imzalanmamış" -#: instances/views.py:1083 +#: instances/views.py:1038 msgid "Shut the VM down, or start its QEMU guest agent, and try again" msgstr "" "Sanal makineyi kapatın ya da QEMU konuk ajanını başlatın ve yeniden deneyin" -#: instances/views.py:1096 +#: instances/views.py:1051 msgid "The change may still be made when the agent answers again." msgstr "Ajan yeniden yanıt verdiğinde değişiklik yine de yapılabilir." -#: instances/views.py:1124 +#: instances/views.py:1079 msgid "Reset root password" msgstr "Root parolasını sıfırla" -#: instances/views.py:1128 +#: instances/views.py:1083 msgid "Enter a password" msgstr "Bir parola girin" -#: instances/views.py:1142 +#: instances/views.py:1097 msgid "Select an SSH public key" msgstr "Bir SSH açık anahtarı seçin" -#: instances/views.py:1164 +#: instances/views.py:1119 #, python-format msgid "Installed new SSH public key %(keyname)s" msgstr "Yeni %(keyname)s SSH açık anahtarı yüklendi" -#: instances/views.py:1184 +#: instances/views.py:1139 msgid "Enter a whole number of vCPUs" msgstr "vCPU sayısı için bir tam sayı girin" -#: instances/views.py:1188 +#: instances/views.py:1143 msgid "Shut off the VM to change its vCPUs" msgstr "vCPU'larını değiştirmek için sanal makineyi kapatın" -#: instances/views.py:1191 +#: instances/views.py:1146 msgid "The current vCPUs cannot be more than the maximum" msgstr "Geçerli vCPU sayısı en fazla değerden büyük olamaz" -#: instances/views.py:1198 +#: instances/views.py:1153 #, python-format msgid "%(quota)s: cannot resize the CPU of '%(instance_name)s'." msgstr "%(quota)s: '%(instance_name)s' CPU'su yeniden boyutlandırılamıyor." -#: instances/views.py:1206 +#: instances/views.py:1161 #, python-format msgid "vCPUs set to %(cur)s (maximum %(max)s)" msgstr "vCPU sayısı %(cur)s olarak ayarlandı (en fazla %(max)s)" -#: instances/views.py:1225 +#: instances/views.py:1180 msgid "Enter a whole number for memory" msgstr "Bellek için bir tam sayı girin" -#: instances/views.py:1228 +#: instances/views.py:1183 msgid "The current memory cannot be more than the maximum" msgstr "Geçerli bellek en fazla değerden büyük olamaz" -#: instances/views.py:1232 +#: instances/views.py:1187 #, python-format msgid "%(quota)s: cannot resize the memory of '%(instance_name)s'." msgstr "%(quota)s: '%(instance_name)s' belleği yeniden boyutlandırılamıyor." -#: instances/views.py:1238 +#: instances/views.py:1193 #, python-format msgid "Memory set to %(cur)s MiB (maximum %(max)s MiB)" msgstr "Bellek %(cur)s MiB olarak ayarlandı (en fazla %(max)s MiB)" -#: instances/views.py:1258 +#: instances/views.py:1213 msgid "Enter disk sizes as whole GiB" msgstr "Disk boyutlarını tam GiB olarak girin" -#: instances/views.py:1262 +#: instances/views.py:1217 #, python-format msgid "%(dev)s is %(size)s: a disk cannot shrink" msgstr "%(dev)s boyutu %(size)s: disk küçültülemez" -#: instances/views.py:1270 +#: instances/views.py:1225 msgid "No disks were selected or valid for resizing." msgstr "Boyutlandırma için seçilmiş ya da geçerli disk yok." -#: instances/views.py:1279 +#: instances/views.py:1234 #, python-format msgid "%(quota)s: cannot resize the disks of '%(instance_name)s'." msgstr "%(quota)s: '%(instance_name)s' diskleri yeniden boyutlandırılamıyor." -#: instances/views.py:1291 +#: instances/views.py:1246 #, python-format msgid "The storage pool of %(dev)s cannot resize its volumes" msgstr "%(dev)s diskinin depolama havuzu birimlerini boyutlandıramaz" -#: instances/views.py:1293 +#: instances/views.py:1248 #, python-format msgid "Disk is resized: %(dev)s" msgstr "Disk boyutu değiştirildi: %(dev)s" -#: instances/views.py:1387 +#: instances/views.py:1342 msgid "The VM's machine has no PCIe slots to add" msgstr "Sanal makinenin makine tipinde eklenecek PCIe yuvası yok" -#: instances/views.py:1392 +#: instances/views.py:1347 #, python-format msgid "%(count)s PCIe slots added" msgstr "%(count)s PCIe yuvası eklendi" -#: instances/views.py:1394 +#: instances/views.py:1349 #, python-format msgid "%(count)s PCIe slots added: the VM gets them at its next start" msgstr "" "%(count)s PCIe yuvası eklendi: sanal makine bunları sonraki başlatmasında " "alır" -#: instances/views.py:1440 +#: instances/views.py:1395 #, python-format msgid "%(volume)s is already a disk of this VM" msgstr "%(volume)s zaten bu sanal makinenin bir diski" -#: instances/views.py:1530 +#: instances/views.py:1485 msgid "Volume changes are applied. But it will be activated after shutdown" msgstr "" "Birim değişiklikleri uygulandı. Ama yeniden başlatıldıktan sonra uygulanacak" -#: instances/views.py:1535 +#: instances/views.py:1490 msgid "Volume is changed successfully." msgstr "Birim başarıyla değiştirildi." -#: instances/views.py:1553 +#: instances/views.py:1508 #, python-format msgid "Disk %(dev)s is not a storage volume of this instance" msgstr "%(dev)s diski bu sanal makinenin bir depolama birimi değil" -#: instances/views.py:1560 +#: instances/views.py:1515 #, python-format msgid "Disk %(dev)s has a pending change; delete it once the VM is shut down" msgstr "" "%(dev)s diskinin bekleyen bir değişikliği var; sanal makine kapatıldığında " "silin" -#: instances/views.py:1575 +#: instances/views.py:1530 #, python-format msgid "Volume %(vol)s is used by another VM; detach it instead" msgstr "" "%(vol)s birimi başka bir sanal makine tarafından kullanılıyor; onun yerine " "ayırın" -#: instances/views.py:1587 +#: instances/views.py:1542 #, python-format msgid "" "The guest has not released disk %(dev)s yet; volume %(vol)s was kept. Delete " @@ -6153,62 +6165,62 @@ msgstr "" "Konuk sistem %(dev)s diskini henüz bırakmadı; %(vol)s birimi korundu. Sanal " "makine kapatıldığında depolama havuzundan silin." -#: instances/views.py:1598 +#: instances/views.py:1553 #, python-format msgid "Disk %(dev)s was detached, but its volume was kept: %(err)s" msgstr "%(dev)s diski ayrıldı, ancak birimi korundu: %(err)s" -#: instances/views.py:1624 +#: instances/views.py:1579 #, python-format msgid "This VM cannot take a CD-ROM on the %(bus)s bus now" msgstr "Bu sanal makineye şu anda %(bus)s veri yolunda CD-ROM eklenemez" -#: instances/views.py:1627 +#: instances/views.py:1582 msgid "A USB CD-ROM needs an ISO image: libvirt has no empty USB drive" msgstr "USB CD-ROM bir ISO imajı ister: libvirt boş USB sürücü desteklemiyor" -#: instances/views.py:1632 +#: instances/views.py:1587 #, python-format msgid "%(image)s is already in a CD-ROM of this VM" msgstr "%(image)s bu sanal makinenin bir CD-ROM'unda zaten takılı" -#: instances/views.py:1713 +#: instances/views.py:1668 #, python-format msgid "Pool %(pool)s was not read again: %(err)s" msgstr "%(pool)s havuzu yeniden okunamadı: %(err)s" -#: instances/views.py:1734 +#: instances/views.py:1689 #, python-format msgid "Snapshot was not deleted: %(err)s" msgstr "Anlık görüntü silinmedi: %(err)s" -#: instances/views.py:1849 +#: instances/views.py:1804 msgid "Add at least one device to the boot order." msgstr "Ön yükleme sırasına en az bir aygıt ekleyin." -#: instances/views.py:1863 +#: instances/views.py:1818 msgid "Boot order changed. It applies at the next start." msgstr "Ön yükleme sırası değiştirildi. Sonraki başlatmada uygulanır." -#: instances/views.py:1865 +#: instances/views.py:1820 msgid "Boot order changed successfully." msgstr "Ön yükleme sırası başarıyla değiştirildi." -#: instances/views.py:1885 +#: instances/views.py:1840 msgid "The XML is empty" msgstr "XML boş" -#: instances/views.py:1889 instances/views.py:2514 +#: instances/views.py:1844 instances/views.py:2469 #, python-format msgid "The XML is not well-formed: %(error)s" msgstr "XML düzgün biçimlendirilmemiş: %(error)s" -#: instances/views.py:1891 +#: instances/views.py:1846 #, python-format msgid "The XML must keep the VM's UUID %(uuid)s." msgstr "XML, sanal makinenin %(uuid)s UUID'sini korumalıdır." -#: instances/views.py:1895 +#: instances/views.py:1850 msgid "" "The definition has changed since the editor was opened. Reload the page to " "edit the current one." @@ -6216,40 +6228,40 @@ msgstr "" "Düzenleyici açıldığından beri tanım değişti. Geçerli tanımı düzenlemek için " "sayfayı yeniden yükleyin." -#: instances/views.py:1907 +#: instances/views.py:1862 msgid "The XML definition was saved." msgstr "XML tanımı kaydedildi." -#: instances/views.py:1909 +#: instances/views.py:1864 msgid "The XML definition was saved; the VM uses it from its next start." msgstr "" "XML tanımı kaydedildi; sanal makine onu sonraki başlatmasından itibaren " "kullanır." -#: instances/views.py:1990 +#: instances/views.py:1945 msgid "Select one network interface to change" msgstr "Değiştirilecek bir ağ arabirimi seçin" -#: instances/views.py:2028 +#: instances/views.py:1983 msgid "Network Device Config is changed. Please shutdown instance to activate." msgstr "" "Ağ aygıtı yapılandırması değiştirildi. Aktifleştirmek için lütfen sanal " "makineyi kapatın." -#: instances/views.py:2030 +#: instances/views.py:1985 msgid "Network device changed" msgstr "Ağ aygıtı değiştirildi" -#: instances/views.py:2042 +#: instances/views.py:1997 msgid "No network selected" msgstr "Ağ seçilmedi" -#: instances/views.py:2047 +#: instances/views.py:2002 #, python-format msgid "The VM already has a network device with MAC %(mac)s" msgstr "Sanal makinede %(mac)s MAC adresli bir ağ aygıtı zaten var" -#: instances/views.py:2066 +#: instances/views.py:2021 msgid "" "The running VM has no free PCI slot for another network device: shut it down " "and add the device then; Add PCIe slots on the Disks tab gives it free ones " @@ -6259,21 +6271,21 @@ msgstr "" "aygıtı sonra ekleyin; Diskler sekmesindeki PCIe yuvaları ekle, sonraki " "başlatmadan itibaren ona boş yuvalar verir." -#: instances/views.py:2107 instances/views.py:2113 +#: instances/views.py:2062 instances/views.py:2068 msgid "The VM has it" msgstr "Sanal makinede var" -#: instances/views.py:2144 +#: instances/views.py:2099 #, python-format msgid "The host has no USB device %(device)s" msgstr "Sunucuda %(device)s USB aygıtı yok" -#: instances/views.py:2165 +#: instances/views.py:2120 #, python-format msgid "The host has no PCI device %(device)s" msgstr "Sunucuda %(device)s PCI aygıtı yok" -#: instances/views.py:2183 +#: instances/views.py:2138 #, python-format msgid "" "Removal of PCI device %(address)s requested: the guest has not let it go yet;" @@ -6283,20 +6295,20 @@ msgstr "" "bırakmadı; bırakana ya da sanal makine durana kadar çalışan sanal makinede " "kalır." -#: instances/views.py:2228 instances/views.py:2258 +#: instances/views.py:2183 instances/views.py:2213 msgid "Select a network interface and a QoS direction" msgstr "Bir ağ arabirimi ve bir QoS yönü seçin" -#: instances/views.py:2231 vrtManager/network.py:459 +#: instances/views.py:2186 vrtManager/network.py:459 msgid "QoS rates must be whole numbers" msgstr "QoS hızları tam sayı olmalıdır" -#: instances/views.py:2238 networks/views.py:229 +#: instances/views.py:2193 networks/views.py:229 #, python-format msgid "%(qos_dir)s QoS is set" msgstr "%(qos_dir)s QoS ayarlandı" -#: instances/views.py:2243 +#: instances/views.py:2198 #, python-format msgid "" "%(qos_dir)s QoS is set. A running VM gets it after it is powered off and on." @@ -6304,12 +6316,12 @@ msgstr "" "%(qos_dir)s QoS ayarlandı. Çalışan bir sanal makine, kapatılıp açıldıktan " "sonra bunu alır." -#: instances/views.py:2265 networks/views.py:255 +#: instances/views.py:2220 networks/views.py:255 #, python-format msgid "%(qos_dir)s QoS is deleted" msgstr "%(qos_dir)s QoS silindi" -#: instances/views.py:2270 +#: instances/views.py:2225 #, python-format msgid "" "%(qos_dir)s QoS is deleted. A running VM keeps the old limit until it is " @@ -6318,21 +6330,21 @@ msgstr "" "%(qos_dir)s QoS silindi. Çalışan bir sanal makine, kapatılıp açılana kadar " "eski sınırı korur." -#: instances/views.py:2298 +#: instances/views.py:2253 msgid "Only one owner is allowed and the one already added" msgstr "Sadece bir sahibe izin verilmiştir ve bir sahip zaten eklenmiş" -#: instances/views.py:2300 +#: instances/views.py:2255 #, python-format msgid "%(user)s is already an owner" msgstr "%(user)s zaten bir sahip" -#: instances/views.py:2345 +#: instances/views.py:2300 #, python-format msgid "Console settings were not saved: %(errors)s" msgstr "Konsol ayarları kaydedilmedi: %(errors)s" -#: instances/views.py:2367 +#: instances/views.py:2322 msgid "" "Error setting console password. You should check that your instance have an " "graphic device." @@ -6340,65 +6352,65 @@ msgstr "" "Konsol parolası ayarlanırken hata oluştu. Sanal makinenin bir grafik aygıtına" " sahip olduğundan emin olunuz." -#: instances/views.py:2414 +#: instances/views.py:2369 msgid "Shut the VM down to change whether it is a template." msgstr "Şablon olup olmadığını değiştirmek için sanal makineyi kapatın." -#: instances/views.py:2420 +#: instances/views.py:2375 #, python-format msgid "%(quota)s: '%(instance_name)s' stays a template." msgstr "%(quota)s: '%(instance_name)s' şablon olarak kalıyor." -#: instances/views.py:2502 +#: instances/views.py:2457 msgid "The XML has no name" msgstr "XML'de ad yok" -#: instances/views.py:2516 webvirtcloud/middleware.py:126 +#: instances/views.py:2471 webvirtcloud/middleware.py:126 #, python-format msgid "libvirt Error - %(exception)s" msgstr "libvirt Hatası - %(exception)s" -#: instances/views.py:2523 +#: instances/views.py:2478 msgid "An empty disk of the size you set" msgstr "Belirlediğiniz boyutta boş bir disk" -#: instances/views.py:2524 +#: instances/views.py:2479 msgid "Volumes already in a pool" msgstr "Bir havuzda zaten bulunan birimler" -#: instances/views.py:2525 +#: instances/views.py:2480 msgid "A copy of a template volume" msgstr "Bir şablon biriminin kopyası" -#: instances/views.py:2614 +#: instances/views.py:2569 msgid "You haven't defined any storage pools" msgstr "Hiç bir depolama havuzu tanımlamadınız" -#: instances/views.py:2616 +#: instances/views.py:2571 msgid "You haven't defined any network pools" msgstr "Hiç bir ağ havuzu tanımlamadınız" -#: instances/views.py:2679 +#: instances/views.py:2634 msgid "Flavor Created" msgstr "Flavor Oluşturuldu" -#: instances/views.py:2687 +#: instances/views.py:2642 msgid "Create Flavor" msgstr "Kullanıcı Oluştur" -#: instances/views.py:2702 +#: instances/views.py:2657 msgid "Flavor Updated" msgstr "Flavor Güncellendi" -#: instances/views.py:2708 +#: instances/views.py:2663 msgid "Update Flavor" msgstr "Flavor Güncelle" -#: instances/views.py:2720 +#: instances/views.py:2675 msgid "Flavor Deleted" msgstr "Flavor Silindi" -#: instances/views.py:2726 +#: instances/views.py:2681 msgid "Only the size template goes; VMs made from it keep their size." msgstr "" "Yalnızca boyut şablonu silinir; ondan oluşturulan sanal makineler boyutlarını" @@ -7954,7 +7966,7 @@ msgstr "" "Kurtarma bir saat boyunca işin durumunu okuyamadı; sanal makineyi kontrol " "edin, sonra bu işi çözün" -#: operations/worker.py:464 +#: operations/worker.py:473 msgid "The worker stopped before the job changed anything" msgstr "Worker, iş herhangi bir şeyi değiştirmeden önce durdu" @@ -9139,56 +9151,56 @@ msgid "Please shutdown the instance then try to enable vCPU hotplug" msgstr "" "vCPU hotplug özelliğini etkinleştirmek için önce sanal makineyi kapatın" -#: vrtManager/instance.py:1854 +#: vrtManager/instance.py:1842 msgid "" "The VM has external snapshots; internal snapshots cannot be mixed with them" msgstr "" "Sanal makinenin harici anlık görüntüleri var; dahili anlık görüntüler " "bunlarla karıştırılamaz" -#: vrtManager/instance.py:1886 +#: vrtManager/instance.py:1874 msgid "A snapshot with memory is not quiesced; it keeps the whole guest state" msgstr "" "Bellekli bir anlık görüntüde dosya sistemleri dondurulmaz; tüm konuk durumunu" " saklar" -#: vrtManager/instance.py:1888 +#: vrtManager/instance.py:1876 msgid "Only a running VM's file systems can be frozen" msgstr "Yalnızca çalışan bir sanal makinenin dosya sistemleri dondurulabilir" -#: vrtManager/instance.py:1890 +#: vrtManager/instance.py:1878 msgid "The QEMU guest agent is not connected; it freezes the file systems" msgstr "QEMU konuk aracısı bağlı değil; dosya sistemlerini o dondurur" -#: vrtManager/instance.py:1893 +#: vrtManager/instance.py:1881 msgid "" "The VM has internal snapshots; external snapshots cannot be mixed with them" msgstr "" "Sanal makinenin dahili anlık görüntüleri var; harici anlık görüntüler " "bunlarla karıştırılamaz" -#: vrtManager/instance.py:1898 +#: vrtManager/instance.py:1886 msgid "Newer snapshots exist after the last revert; delete them first" msgstr "" "Son geri dönüşten sonra daha yeni anlık görüntüler var; önce onları silin" -#: vrtManager/instance.py:1901 +#: vrtManager/instance.py:1889 msgid "No snapshot is current; revert to a snapshot first" msgstr "Geçerli anlık görüntü yok; önce bir anlık görüntüye geri dönün" -#: vrtManager/instance.py:1907 +#: vrtManager/instance.py:1895 #, python-format msgid "Eject the media from %(dev)s first" msgstr "Önce %(dev)s içindeki ortamı çıkarın" -#: vrtManager/instance.py:1909 +#: vrtManager/instance.py:1897 #, python-format msgid "Disk %(dev)s is not a file; external snapshots need file disks" msgstr "" "Disk %(dev)s bir dosya değil; harici anlık görüntüler dosya diskleri " "gerektirir" -#: vrtManager/instance.py:1917 +#: vrtManager/instance.py:1905 #, python-format msgid "" "The storage pools could not be refreshed, so their free space is unknown: " @@ -9196,21 +9208,21 @@ msgid "" msgstr "" "Depolama havuzları yenilenemedi, bu yüzden boş alanları bilinmiyor: %(err)s" -#: vrtManager/instance.py:1938 +#: vrtManager/instance.py:1926 msgid "Memory is saved only from a running VM" msgstr "Bellek yalnızca çalışan bir sanal makineden kaydedilir" -#: vrtManager/instance.py:1940 +#: vrtManager/instance.py:1928 msgid "The VM has no disk to keep its memory next to" msgstr "Sanal makinenin, belleğinin yanına kaydedileceği bir diski yok" -#: vrtManager/instance.py:1944 +#: vrtManager/instance.py:1932 #, python-format msgid "%(disk)s is not in a storage pool; memory is saved only into one" msgstr "" "%(disk)s bir depolama havuzunda değil; bellek yalnızca bir havuza kaydedilir" -#: vrtManager/instance.py:1975 +#: vrtManager/instance.py:1963 #, python-format msgid "" "Storage pool %(pool)s has %(free).1f GiB free; the snapshot needs %(size).1f " @@ -9221,7 +9233,7 @@ msgstr "" "%(size).1f GiB gerektiriyor (sanal makinenin oradaki disklerinin " "%%%(percent)g kadarı, en az %(minimum)g GiB, ve kaydediliyorsa bellek)" -#: vrtManager/instance.py:1993 +#: vrtManager/instance.py:1981 msgid "" "This snapshot was taken by an older version on a UEFI VM and cannot be " "reverted; delete it instead" @@ -9229,7 +9241,7 @@ msgstr "" "Bu anlık görüntü UEFI bir sanal makinede eski bir sürümle alındı ve geri " "dönülemez; bunun yerine silin" -#: vrtManager/instance.py:2023 +#: vrtManager/instance.py:2011 #, python-format msgid "" "The revert failed twice; try again in a moment (%(error)s). The VM is " @@ -9238,7 +9250,7 @@ msgstr "" "Geri dönüş iki kez başarısız oldu; biraz sonra tekrar deneyin (%(error)s). " "Sanal makine çalışıyor." -#: vrtManager/instance.py:2025 +#: vrtManager/instance.py:2013 #, python-format msgid "" "The revert failed twice; try again in a moment (%(error)s). The VM is shut " @@ -9247,13 +9259,13 @@ msgstr "" "Geri dönüş iki kez başarısız oldu; biraz sonra tekrar deneyin (%(error)s). " "Sanal makine kapalı." -#: vrtManager/instance.py:2188 +#: vrtManager/instance.py:2176 msgid "A disk moves when its VM is defined and running, paused or shut off" msgstr "" "Bir disk, sanal makinesi tanımlıyken ve çalışırken, duraklatılmışken veya " "kapalıyken taşınır" -#: vrtManager/instance.py:2190 +#: vrtManager/instance.py:2178 msgid "" "A disk of a VM with snapshots, a saved state or a running block job does not " "move" @@ -9261,7 +9273,7 @@ msgstr "" "Anlık görüntüleri, kaydedilmiş durumu veya çalışan bir blok işi olan sanal " "makinenin diski taşınmaz" -#: vrtManager/instance.py:2198 +#: vrtManager/instance.py:2186 #, python-format msgid "" "%(dev)s is not a disk file of the VM, the same in its running and next " @@ -9270,132 +9282,132 @@ msgstr "" "%(dev)s, sanal makinenin çalışan ve sonraki başlatma tanımlarında aynı olan " "bir disk dosyası değil" -#: vrtManager/instance.py:2203 +#: vrtManager/instance.py:2191 #, python-format msgid "%(dev)s does not move: only writable raw and qcow2 disks do" msgstr "%(dev)s taşınmaz: yalnızca yazılabilir raw ve qcow2 diskler taşınır" -#: vrtManager/instance.py:2210 +#: vrtManager/instance.py:2198 #, python-format msgid "%(dev)s does not move: no storage pool has %(path)s" msgstr "%(dev)s taşınmaz: hiçbir depolama havuzunda %(path)s yok" -#: vrtManager/instance.py:2212 +#: vrtManager/instance.py:2200 #, python-format msgid "%(dev)s does not move: it has a backing file" msgstr "%(dev)s taşınmaz: temel (backing) dosyası var" -#: vrtManager/instance.py:2215 +#: vrtManager/instance.py:2203 #, python-format msgid "%(pool_name)s is not an active pool of disk files of this host" msgstr "%(pool_name)s bu sunucunun etkin bir disk dosyası havuzu değil" -#: vrtManager/instance.py:2218 +#: vrtManager/instance.py:2206 #, python-format msgid "%(dev)s is in pool %(pool_name)s already" msgstr "%(dev)s zaten %(pool_name)s havuzunda" -#: vrtManager/instance.py:2222 +#: vrtManager/instance.py:2210 #, python-format msgid "Pool %(pool_name)s already has a file %(name)s" msgstr "%(pool_name)s havuzunda zaten %(name)s dosyası var" -#: vrtManager/instance.py:2246 +#: vrtManager/instance.py:2234 #, python-format msgid "The copy of %(dev)s ended before it was complete" msgstr "%(dev)s kopyası tamamlanmadan sona erdi" -#: vrtManager/instance.py:2291 +#: vrtManager/instance.py:2279 #, python-format msgid "%(error)s; remove %(dest)s if it is there: %(cleanup_error)s" msgstr "%(error)s; varsa %(dest)s dosyasını kaldırın: %(cleanup_error)s" -#: vrtManager/instance.py:2293 +#: vrtManager/instance.py:2281 #, python-format msgid "%(error)s; the VM may use %(dest)s now: check its disk %(dev)s" msgstr "" "%(error)s; sanal makine şu anda %(dest)s dosyasını kullanıyor olabilir: " "%(dev)s diskini kontrol edin" -#: vrtManager/instance.py:2300 +#: vrtManager/instance.py:2288 #, python-format msgid "The VM has no internal snapshot named %(name)s" msgstr "Sanal makinenin %(name)s adlı dahili anlık görüntüsü yok" -#: vrtManager/instance.py:2309 +#: vrtManager/instance.py:2297 msgid "The VM has a saved state; start it or remove the saved state first" msgstr "" "Sanal makinenin kaydedilmiş durumu var; önce başlatın veya kaydedilmiş durumu" " kaldırın" -#: vrtManager/instance.py:2311 +#: vrtManager/instance.py:2299 msgid "A snapshot job is still running on this VM; try again when it ends" msgstr "" "Bu sanal makinede hâlâ bir anlık görüntü işi çalışıyor; bittiğinde tekrar " "deneyin" -#: vrtManager/instance.py:2321 +#: vrtManager/instance.py:2309 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:2415 +#: vrtManager/instance.py:2403 msgid "Cannot clone a VM whose NVRAM is not a file" msgstr "NVRAM'i dosya olmayan bir sanal makine klonlanamaz" -#: vrtManager/instance.py:2483 +#: vrtManager/instance.py:2471 #, 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:2493 +#: vrtManager/instance.py:2481 msgid "Shut the VM down before cloning it" msgstr "Klonlamadan önce sanal makineyi kapatın" -#: vrtManager/instance.py:2547 +#: vrtManager/instance.py:2535 #, 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:2558 +#: vrtManager/instance.py:2546 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:2561 +#: vrtManager/instance.py:2549 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:2564 +#: vrtManager/instance.py:2552 #, 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:2566 +#: vrtManager/instance.py:2554 #, 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:2571 +#: vrtManager/instance.py:2559 #, 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:2573 +#: vrtManager/instance.py:2561 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:2586 +#: vrtManager/instance.py:2574 #, 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:2605 +#: vrtManager/instance.py:2593 #, python-format msgid "" "Storage pool %(pool)s has %(free).1f GiB free; the clone needs %(size).1f GiB" @@ -9405,20 +9417,20 @@ msgstr "" "gerektiriyor (kopyalanan diskler, artı bunların %%%(percent)g kadarı, en az " "%(minimum)g GiB)" -#: vrtManager/instance.py:2744 +#: vrtManager/instance.py:2732 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:2760 +#: vrtManager/instance.py:2748 #, python-format msgid "No network interface with MAC %(old_mac)s" msgstr "MAC adresi %(old_mac)s olan ağ arabirimi yok" -#: vrtManager/instance.py:2763 +#: vrtManager/instance.py:2751 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:2854 +#: vrtManager/instance.py:2842 msgid "" "A VM changes its PCI devices while it runs, or is shut off without a saved " "state" @@ -9426,14 +9438,14 @@ msgstr "" "Sanal makine PCI aygıtlarını çalışırken veya kaydedilmiş durumu olmadan " "kapalıyken değiştirir" -#: vrtManager/instance.py:2866 +#: vrtManager/instance.py:2854 #, 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:2868 +#: vrtManager/instance.py:2856 #, python-format msgid "" "%(err)s; PCI device %(address)s: the VM is not running, its next start has it" @@ -9441,7 +9453,7 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: sanal makine çalışmıyor, sonraki başlatmada " "var" -#: vrtManager/instance.py:2870 +#: vrtManager/instance.py:2858 #, python-format msgid "" "%(err)s; PCI device %(address)s: the VM is not running, its next start does " @@ -9450,7 +9462,7 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: sanal makine çalışmıyor, sonraki başlatmada " "yok" -#: vrtManager/instance.py:2871 +#: vrtManager/instance.py:2859 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM has it, its next start has it" @@ -9458,7 +9470,7 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: çalışan sanal makinede var, sonraki " "başlatmada var" -#: vrtManager/instance.py:2873 +#: vrtManager/instance.py:2861 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM has it, its next start does " @@ -9467,7 +9479,7 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: çalışan sanal makinede var, sonraki " "başlatmada yok" -#: vrtManager/instance.py:2875 +#: vrtManager/instance.py:2863 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM does not have it, its next " @@ -9476,7 +9488,7 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: çalışan sanal makinede yok, sonraki " "başlatmada var" -#: vrtManager/instance.py:2877 +#: vrtManager/instance.py:2865 #, python-format msgid "" "%(err)s; PCI device %(address)s: the running VM does not have it, its next " @@ -9485,29 +9497,29 @@ msgstr "" "%(err)s; PCI aygıtı %(address)s: çalışan sanal makinede yok, sonraki " "başlatmada yok" -#: vrtManager/instance.py:2911 +#: vrtManager/instance.py:2899 #, python-format msgid "The VM has no PCI device %(address)s" msgstr "Sanal makinede %(address)s PCI aygıtı yok" -#: vrtManager/instance.py:2929 +#: vrtManager/instance.py:2917 msgid "The VM has no USB controller" msgstr "Sanal makinede USB denetleyicisi yok" -#: vrtManager/instance.py:2948 +#: vrtManager/instance.py:2936 msgid "The VM has no such USB device" msgstr "Sanal makinede böyle bir USB aygıtı yok" -#: vrtManager/instance.py:2989 +#: vrtManager/instance.py:2977 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:3016 +#: vrtManager/instance.py:3004 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:3035 +#: vrtManager/instance.py:3023 #, 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 e12ef6f0747083556c8781be31733b7cd61f8d7e..f761599c8c767b0dc28ffeeb623617e14af84128 100644 GIT binary patch delta 43205 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 delta 43058 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