Skip to content

Commit 059a5a9

Browse files
committed
Make link_from (HW/SW inventory) testable
SUP-28176 Change-Id: Ie1c9e528dbe15743c6d85a957650d17b528426a1
1 parent 0302c7c commit 059a5a9

2 files changed

Lines changed: 391 additions & 46 deletions

File tree

cmk/gui/views/visual_type.py

Lines changed: 72 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
44
# conditions defined in the file COPYING, which is part of this source code package.
55

6-
from collections.abc import Iterator
6+
from collections.abc import Callable, Iterator
77

88
from livestatus import SiteId
99

@@ -33,6 +33,8 @@
3333
from cmk.gui.views.store import get_permitted_views
3434
from cmk.gui.visuals.type import VisualType
3535

36+
_InventoryTreeCache = dict[tuple[bool, HostName, SiteId], ImmutableTree | ImmutableDeltaTree]
37+
3638

3739
class VisualTypeViews(VisualType):
3840
"""Register the views as a visual type"""
@@ -90,47 +92,20 @@ def link_from(
9092
"""This has been implemented for HW/SW Inventory views which are often useless when a host
9193
has no such information available. For example the "Oracle Tablespaces" inventory view is
9294
useless on hosts that don't host Oracle databases."""
93-
result = super().link_from(
94-
linking_view_single_infos, linking_view_rows, visual, context_vars
95-
)
96-
if result is False:
97-
return False
98-
99-
link_from = visual["link_from"]
100-
if not link_from:
101-
return True # No link from filtering: Always display this.
102-
103-
context = dict(context_vars)
104-
if (hostname := context.get("host")) is None:
105-
# No host data? Keep old behaviour
106-
return True
107-
108-
if hostname == "":
109-
return False
110-
111-
if isinstance(hostname, int):
112-
return False
113-
114-
# TODO: host is not correctly validated by visuals. Do it here for the moment.
115-
try:
116-
Hostname().validate_value(hostname, "")
117-
except MKUserError:
118-
return False
119-
120-
if not (site_id := context.get("site")):
121-
return False
122-
123-
hostname = HostName(hostname)
124-
return _has_inventory_tree(
125-
hostname,
126-
SiteId(str(site_id)),
127-
link_from.get("has_inventory_tree"),
128-
is_history=False,
129-
) or _has_inventory_tree(
130-
hostname,
131-
SiteId(str(site_id)),
132-
link_from.get("has_inventory_tree_history"),
133-
is_history=True,
95+
tree_cache: _InventoryTreeCache = g.setdefault("inventory_tree_cache", {})
96+
97+
def has_inventory_tree(
98+
hostname: HostName, site_id: SiteId, path: SDPath | None, is_history: bool
99+
) -> bool:
100+
return _has_inventory_tree(hostname, site_id, path, is_history, tree_cache)
101+
102+
return _compute_link_from_result(
103+
linking_view_single_infos,
104+
linking_view_rows,
105+
visual,
106+
context_vars,
107+
base_link_from=super().link_from,
108+
has_inventory_tree=has_inventory_tree,
134109
)
135110

136111

@@ -139,14 +114,15 @@ def _has_inventory_tree(
139114
site_id: SiteId,
140115
path: SDPath | None,
141116
is_history: bool,
117+
tree_cache: _InventoryTreeCache,
142118
) -> bool:
143119
if path is None:
144120
return False
145121

146122
# FIXME In order to decide whether this view is enabled
147123
# do we really need to load the whole tree?
148124
try:
149-
inventory_tree = _get_inventory_tree(is_history, hostname, site_id)
125+
inventory_tree = _get_inventory_tree(is_history, hostname, site_id, tree_cache)
150126
except Exception as e:
151127
if active_config.debug:
152128
html.show_warning("%s" % e)
@@ -156,10 +132,11 @@ def _has_inventory_tree(
156132

157133

158134
def _get_inventory_tree(
159-
is_history: bool, hostname: HostName, site_id: SiteId
135+
is_history: bool,
136+
hostname: HostName,
137+
site_id: SiteId,
138+
tree_cache: _InventoryTreeCache,
160139
) -> ImmutableTree | ImmutableDeltaTree:
161-
tree_cache = g.setdefault("inventory_tree_cache", {})
162-
163140
cache_id = (is_history, hostname, site_id)
164141
if cache_id in tree_cache:
165142
return tree_cache[cache_id]
@@ -171,3 +148,52 @@ def _get_inventory_tree(
171148
)
172149
tree_cache[cache_id] = tree
173150
return tree
151+
152+
153+
def _compute_link_from_result(
154+
linking_view_single_infos: SingleInfos,
155+
linking_view_rows: Rows,
156+
visual: Visual,
157+
context_vars: HTTPVariables,
158+
base_link_from: Callable[[SingleInfos, Rows, Visual, HTTPVariables], bool],
159+
has_inventory_tree: Callable[[HostName, SiteId, SDPath | None, bool], bool],
160+
) -> bool:
161+
if not base_link_from(linking_view_single_infos, linking_view_rows, visual, context_vars):
162+
return False
163+
164+
link_from = visual["link_from"]
165+
if not link_from:
166+
return True # No link from filtering: Always display this.
167+
168+
context = dict(context_vars)
169+
if (hostname := context.get("host")) is None:
170+
# No host data? Keep old behaviour
171+
return True
172+
173+
if hostname == "":
174+
return False
175+
176+
if isinstance(hostname, int):
177+
return False
178+
179+
# TODO: host is not correctly validated by visuals. Do it here for the moment.
180+
try:
181+
Hostname().validate_value(hostname, "")
182+
except MKUserError:
183+
return False
184+
185+
if not (site_id := context.get("site")):
186+
return False
187+
188+
hostname = HostName(hostname)
189+
return has_inventory_tree(
190+
hostname,
191+
SiteId(str(site_id)),
192+
link_from.get("has_inventory_tree"),
193+
False,
194+
) or has_inventory_tree(
195+
hostname,
196+
SiteId(str(site_id)),
197+
link_from.get("has_inventory_tree_history"),
198+
True,
199+
)

0 commit comments

Comments
 (0)