mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-10 12:16:49 +00:00
feat(instances): snapshot revert runs as a job
This commit is contained in:
parent
6f81043438
commit
8d2e88f4bb
7 changed files with 102 additions and 82 deletions
|
|
@ -3,13 +3,14 @@
|
|||
from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
from vrtManager.util import OperationError
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TransactionTestCase
|
||||
from django.urls import reverse
|
||||
|
||||
from appsettings.settings import get_settings
|
||||
from computes.models import Compute
|
||||
from instances.jobs import CreateSnapshot
|
||||
from instances.jobs import CreateSnapshot, RevertSnapshot
|
||||
from instances.models import Instance
|
||||
from operations.jobs import Context, get_kind
|
||||
from operations.models import Claim, Operation, acquire
|
||||
|
|
@ -36,7 +37,8 @@ class SnapshotJobsTestCase(TransactionTestCase):
|
|||
op = Operation.objects.get()
|
||||
self.assertIn((f"instance:{self.instance.uuid}", "exclusive"),
|
||||
set(Claim.objects.values_list("resource", "mode")))
|
||||
self.assertFalse(self.proxy.create_snapshot.called or self.proxy.create_external_snapshot.called)
|
||||
self.assertFalse(self.proxy.create_snapshot.called or self.proxy.create_external_snapshot.called
|
||||
or self.proxy.snapshot_revert.called or self.proxy.revert_external_snapshot.called)
|
||||
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()
|
||||
|
|
@ -69,3 +71,28 @@ class SnapshotJobsTestCase(TransactionTestCase):
|
|||
self.proxy.instance.isActive.return_value = True
|
||||
self.proxy.instance.jobInfo.return_value = [2] + [0] * 11 # VIR_DOMAIN_JOB_UNBOUNDED
|
||||
self.assertEqual(CreateSnapshot().reconcile(op).state, Operation.RUNNING)
|
||||
|
||||
def test_an_external_revert_is_made_by_the_worker(self):
|
||||
self.proxy.revert_external_snapshot.return_value = ["/pool/a.one"]
|
||||
op, result = self.queue_and_run("revert_external_snapshot", {"name": "a"})
|
||||
self.assertEqual((op.kind, result), ("snapshot.revert", {"left_behind": ["/pool/a.one"]}))
|
||||
self.proxy.revert_external_snapshot.assert_called_once_with("a")
|
||||
|
||||
def test_a_revert_libvirt_cannot_do_is_refused_before_effects(self):
|
||||
self.proxy.check_external_revert.side_effect = OperationError("taken by an older version")
|
||||
with self.assertRaises(OperationError):
|
||||
self.queue_and_run("revert_external_snapshot", {"name": "a"})
|
||||
self.assertFalse(Operation.objects.get().effects_started)
|
||||
|
||||
def test_an_internal_revert_is_made_by_the_worker(self):
|
||||
self.queue_and_run("revert_snapshot", {"name": "b"})
|
||||
self.proxy.snapshot_revert.assert_called_once_with("b")
|
||||
|
||||
def test_revert_recovery(self):
|
||||
op = Operation(params={"instance": self.instance.pk, "name": "a", "external": False},
|
||||
intent={"compute": self.instance.compute_id, "was_current": "z"})
|
||||
self.proxy.instance.hasCurrentSnapshot.return_value = 1
|
||||
self.proxy.instance.snapshotCurrent.return_value.getName.return_value = "a"
|
||||
self.assertEqual(RevertSnapshot().reconcile(op).state, Operation.SUCCEEDED)
|
||||
op.intent["was_current"] = "a" # it was current before: nothing tells
|
||||
self.assertEqual(RevertSnapshot().reconcile(op).state, Operation.UNCERTAIN)
|
||||
|
|
|
|||
|
|
@ -30,15 +30,12 @@ class SnapshotViewsTestCase(TestCase):
|
|||
admin = get_user_model().objects.create_superuser("snap_admin", "s@example.com", "pw")
|
||||
self.client.force_login(admin)
|
||||
|
||||
def post(self, view, data, error=None, left=()):
|
||||
def post(self, view, data, error=None):
|
||||
with patch("instances.models.wvmInstance") as mock_wvm:
|
||||
proxy = mock_wvm.return_value
|
||||
method = {
|
||||
"revert_external_snapshot": proxy.revert_external_snapshot,
|
||||
"revert_snapshot": proxy.snapshot_revert,
|
||||
"delete_snapshot": proxy.snapshot_delete,
|
||||
}[view]
|
||||
method.return_value = list(left) # files revert and delete left behind
|
||||
if error:
|
||||
method.side_effect = util.OperationError(error)
|
||||
self.client.cookies.pop("messages", None) # only this request's messages
|
||||
|
|
@ -60,20 +57,6 @@ class SnapshotViewsTestCase(TestCase):
|
|||
get_settings()
|
||||
self.assertEqual(_snapshot_free_space(), expected)
|
||||
|
||||
def test_revert_calls_the_backend_once_and_leaves_power_alone(self):
|
||||
proxy, method, _ = self.post("revert_external_snapshot", {"name": "a"})
|
||||
method.assert_called_once_with("a")
|
||||
for power in ("start", "force_shutdown", "shutdown"):
|
||||
getattr(proxy, power).assert_not_called()
|
||||
|
||||
def test_files_left_behind_are_named_in_a_warning(self):
|
||||
_, _, messages = self.post("revert_external_snapshot", {"name": "a"}, left=["/pool/a.one", "/pool/vm.one.mem"])
|
||||
warning = [m for m in messages if "/pool/a.one, /pool/vm.one.mem" in m]
|
||||
self.assertEqual(len(warning), 1, messages)
|
||||
self.assertIn("qemu user", warning[0])
|
||||
_, _, messages = self.post("revert_external_snapshot", {"name": "a"})
|
||||
self.assertFalse([m for m in messages if "not removed" in m], messages)
|
||||
|
||||
def delete(self, listed):
|
||||
with patch("instances.jobs.wvmInstance") as mock_wvm:
|
||||
proxy = mock_wvm.return_value
|
||||
|
|
@ -101,7 +84,7 @@ class SnapshotViewsTestCase(TestCase):
|
|||
self.assertFalse(Operation.objects.exists())
|
||||
|
||||
def test_refusals_become_messages(self):
|
||||
for view in ("revert_external_snapshot", "revert_snapshot", "delete_snapshot"):
|
||||
for view in ("delete_snapshot",):
|
||||
with self.subTest(view):
|
||||
_, _, messages = self.post(view, {"name": "a"}, error="refused for a reason")
|
||||
self.assertTrue(any("refused for a reason" in m for m in messages), messages)
|
||||
|
|
|
|||
|
|
@ -521,15 +521,6 @@ class InstancesTestCase(TestCase):
|
|||
self.instance.__dict__.pop(cached, None)
|
||||
self.assertEqual(len(self.instance.snapshots), 1)
|
||||
|
||||
response = self.client.post(
|
||||
reverse("instances:revert_snapshot", args=[self.instance.id]),
|
||||
{
|
||||
"name": "test-snapshot",
|
||||
},
|
||||
HTTP_REFERER=reverse("index"),
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
response = self.client.post(
|
||||
reverse("instances:delete_snapshot", args=[self.instance.id]),
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue