Merge ~ltrager/maas:2.3_fix_scriptresult_updates_on_trigger into maas:2.3

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: 05937bab771228759f35174ebebba6d49d2c906c
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~ltrager/maas:2.3_fix_scriptresult_updates_on_trigger
Merge into: maas:2.3
Prerequisite: ~ltrager/maas:2.3_ws_cache_current_scriptresults_only
Diff against target: 117 lines (+69/-3)
2 files modified
src/maasserver/websockets/handlers/node.py (+17/-3)
src/maasserver/websockets/handlers/tests/test_machine.py (+52/-0)
Reviewer Review Type Date Requested Status
Alberto Donato (community) Approve
Review via email: mp+368113@code.launchpad.net

Commit message

Update ScriptResult cache on node listen from trigger

Backport of f0e252b for LP: #1830365

To post a comment you must log in.
Revision history for this message
Alberto Donato (ack) wrote :

+1

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :

LANDING
-b 2.3_fix_scriptresult_updates_on_trigger lp:~ltrager/maas/+git/maas into -b 2.3 lp:~maas-committers/maas

STATUS: FAILED BUILD
LOG: http://maas-ci-jenkins.internal:8080/job/maas/job/branch-tester/5802/consoleText

05937ba... by Lee Trager

Merge branch '2.3' into 2.3_fix_scriptresult_updates_on_trigger

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/src/maasserver/websockets/handlers/node.py b/src/maasserver/websockets/handlers/node.py
2index d53e445..fda47a7 100644
3--- a/src/maasserver/websockets/handlers/node.py
4+++ b/src/maasserver/websockets/handlers/node.py
5@@ -313,9 +313,8 @@ class NodeHandler(TimestampedModelHandler):
6
7 return data
8
9- def _cache_pks(self, nodes):
10+ def _cache_script_results(self, nodes):
11 """Refresh the ScriptResult cache from the given node."""
12- super()._cache_pks(nodes)
13 script_results = ScriptResult.objects.filter(
14 script_set__node__in=nodes)
15 script_results = script_results.select_related('script_set', 'script')
16@@ -324,6 +323,7 @@ class NodeHandler(TimestampedModelHandler):
17 '-id')
18 script_results = script_results.distinct(
19 'script_name', 'physical_blockdevice_id', 'script_set__node_id')
20+ nodes_reset = set()
21 for script_result in script_results:
22 node_id = script_result.script_set.node_id
23 if script_result.script is not None:
24@@ -331,8 +331,14 @@ class NodeHandler(TimestampedModelHandler):
25 else:
26 hardware_type = HARDWARE_TYPE.NODE
27
28- if node_id not in self._script_results:
29+ # _cache_script_results is only called once per list(), get()
30+ # Postgres trigger update. Make sure the cache is cleared for the
31+ # node so if list(), get(), or a trigger is called multiple times
32+ # with the same instance of NodesHandler() only one set of results
33+ # is stored.
34+ if node_id not in nodes_reset:
35 self._script_results[node_id] = {}
36+ nodes_reset.add(node_id)
37
38 if hardware_type not in self._script_results[node_id]:
39 self._script_results[node_id][hardware_type] = []
40@@ -352,6 +358,14 @@ class NodeHandler(TimestampedModelHandler):
41 self._script_results[node_id][hardware_type].append(
42 script_result)
43
44+ def _cache_pks(self, nodes):
45+ super()._cache_pks(nodes)
46+ self._cache_script_results(nodes)
47+
48+ def on_listen_for_active_pk(self, action, pk, obj):
49+ self._cache_script_results([obj])
50+ return super().on_listen_for_active_pk(action, pk, obj)
51+
52 def dehydrate_blockdevice(self, blockdevice, obj):
53 """Return `BlockDevice` formatted for JSON encoding."""
54 # model and serial are currently only avalible on physical block
55diff --git a/src/maasserver/websockets/handlers/tests/test_machine.py b/src/maasserver/websockets/handlers/tests/test_machine.py
56index c6bbbbf..007bf55 100644
57--- a/src/maasserver/websockets/handlers/tests/test_machine.py
58+++ b/src/maasserver/websockets/handlers/tests/test_machine.py
59@@ -498,6 +498,58 @@ class TestMachineHandler(MAASServerTestCase):
60 queries_total, 12,
61 "Number of queries has changed; make sure this is expected.")
62
63+ def test_trigger_update_updates_script_result_cache(self):
64+ owner = factory.make_User()
65+ node = factory.make_Node(owner=owner)
66+ commissioning_script_set = factory.make_ScriptSet(
67+ node=node, result_type=RESULT_TYPE.COMMISSIONING)
68+ testing_script_set = factory.make_ScriptSet(
69+ node=node, result_type=RESULT_TYPE.TESTING)
70+ node.current_commissioning_script_set = commissioning_script_set
71+ node.current_testing_script_set = testing_script_set
72+ node.save()
73+ for _ in range(10):
74+ factory.make_ScriptResult(
75+ status=SCRIPT_STATUS.PASSED,
76+ script_set=commissioning_script_set)
77+ factory.make_ScriptResult(
78+ status=SCRIPT_STATUS.PASSED,
79+ script_set=testing_script_set)
80+
81+ handler = MachineHandler(owner, {})
82+ # Simulate a trigger pushing an update to the UI
83+ _, _, ret = handler.on_listen_for_active_pk(
84+ 'update', node.system_id, node)
85+ self.assertEquals(ret['commissioning_script_count'], 10)
86+ self.assertEquals(ret['testing_script_count'], 10)
87+
88+ def test_cache_clears_on_reload(self):
89+ owner = factory.make_User()
90+ node = factory.make_Node(owner=owner)
91+ commissioning_script_set = factory.make_ScriptSet(
92+ node=node, result_type=RESULT_TYPE.COMMISSIONING)
93+ testing_script_set = factory.make_ScriptSet(
94+ node=node, result_type=RESULT_TYPE.TESTING)
95+ node.current_commissioning_script_set = commissioning_script_set
96+ node.current_testing_script_set = testing_script_set
97+ node.save()
98+ for _ in range(10):
99+ factory.make_ScriptResult(
100+ status=SCRIPT_STATUS.PASSED,
101+ script_set=commissioning_script_set)
102+ factory.make_ScriptResult(
103+ status=SCRIPT_STATUS.PASSED,
104+ script_set=testing_script_set)
105+
106+ handler = MachineHandler(owner, {})
107+ handler.list({})
108+ handler.list({})
109+ count = 0
110+ for result_type in handler._script_results[node.id].values():
111+ for _ in result_type:
112+ count += 1
113+ self.assertEqual(20, count)
114+
115 def test_dehydrate_owner_empty_when_None(self):
116 owner = factory.make_User()
117 handler = MachineHandler(owner, {})

Subscribers

People subscribed via source and target branches