Skip to content

Commit

Permalink
feat: add helper function: get_dependency_specs and test (#3534)
Browse files Browse the repository at this point in the history
* feat: add helper function: "get_dependency_specs" and test

Signed-off-by: Xiangce Liu <[email protected]>

* coverage 100%

Signed-off-by: Xiangce Liu <[email protected]>

* fix typo in test

Signed-off-by: Xiangce Liu <[email protected]>

* fix doc error

Signed-off-by: Xiangce Liu <[email protected]>

* doc: move the note back to the example

Signed-off-by: Xiangce Liu <[email protected]>

* fix test for python 2

Signed-off-by: Xiangce Liu <[email protected]>

* add more docs

Signed-off-by: Xiangce Liu <[email protected]>

* remove blank line

Signed-off-by: Xiangce Liu <[email protected]>

* make the get_requires() looks more reasonable and add test

Signed-off-by: Xiangce Liu <[email protected]>

* Refine the code a bit

Signed-off-by: Xiangce Liu <[email protected]>

Signed-off-by: Xiangce Liu <[email protected]>
(cherry picked from commit 430c852)
  • Loading branch information
xiangce authored and Sachin Patil committed Oct 6, 2022
1 parent ba604d1 commit fa731e6
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 0 deletions.
61 changes: 61 additions & 0 deletions insights/core/dr.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,67 @@ def visitor(c, parent):
return graph


def get_dependency_specs(component):
"""
Get the dependency specs of the specified `component`. Only `requires` and
`at_least_one` specs will be returned. The `optional` specs is not
considered in this function.
Arguments:
component (callable): The component to check. The component must
already be loaded.
Returns:
list: The `requires` and `at_least_one` spec sets of the `component`.
The return list is in the following format::
[
requires_1,
requires_2,
(at_least_one_11, at_least_one_12),
(at_least_one_21, [req_alo22, (alo_23, alo_24)]),
]
Note:
- The 'requires_1' and 'requires_2' are `requires` specs.
Each of them are required.
- The 'at_least_one_11' and 'at_least_one_12' are `at_least_one`
specs in the same at least one set.
At least one of them is required
- The 'alo_23' and 'alo_24' are `at_least_one` specs and
together with the 'req_alo22' are `requires` for the
sub-set. This sub-set specs and the 'at_least_one_21' are
`at_least_one` specs in the same at least one set.
"""
def get_requires(comp):
req = list()
for cmp in get_delegate(comp).requires:
if get_name(cmp).startswith("insights.specs."):
req.append(get_simple_name(cmp))
else:
req.extend(get_requires(cmp) + get_at_least_one(cmp))
return req

def get_at_least_one(comp):
alo = list()
for cmps in get_delegate(comp).at_least_one:
salo = list()
for cmp in cmps:
ssreq = get_requires(cmp)
ssalo = get_at_least_one(cmp)
if ssreq and ssalo:
# they are mixed and in the same `requires` level
salo.append([ss for ss in ssreq + ssalo])
else:
# no mixed, just add them one by one
salo.extend(ssreq or ssalo)
alo.append(tuple(salo))
return alo

return get_requires(component) + get_at_least_one(component)


def get_subgraphs(graph=None):
"""
Given a graph of possibly disconnected components, generate all graphs of
Expand Down
131 changes: 131 additions & 0 deletions insights/tests/test_get_dependency_specs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
from insights import condition, rule, make_fail
from insights.parsers.installed_rpms import InstalledRpms
from insights.parsers.up2date import Up2Date
from insights.parsers.messages import Messages
from insights.parsers.ps import PsAuxcww
from insights.parsers.virt_what import VirtWhat
from insights.parsers.date import Date
from insights.parsers.tags import Tags
from insights.parsers.lspci import LsPci, LsPciVmmkn
from insights.parsers.lsof import Lsof
from insights.parsers.lscpu import LsCPU
from insights.parsers.lsblk import LSBlock
from insights.parsers.ls_etc import LsEtc
from insights.parsers.ls_boot import LsBoot
from insights.parsers.ls_dev import LsDev
from insights.parsers.ls_disk import LsDisk
from insights.parsers.ls_tmp import LsTmp
from insights.parsers.ls_usr_bin import LsUsrBin
from insights.parsers.ls_var_log import LsVarLog
from insights.parsers.ls_var_tmp import LsVarTmp
from insights.parsers.ls_var_www_perms import LsVarWwwPerms
from insights.parsers.ls_var_run import LsVarRun
from insights.parsers.mount import Mount
from insights.parsers.lvm import LvmConfig, LvmConf
from insights.parsers.lsscsi import LsSCSI
from insights.parsers.uptime import Uptime
from insights.combiners.redhat_release import RedHatRelease
from insights.core.dr import get_dependency_specs


@condition(InstalledRpms, [Up2Date, PsAuxcww], optional=[Messages])
def condition_1(*args):
return True


@condition(VirtWhat, Tags, RedHatRelease, optional=[Date, Uptime])
def condition_2(*args):
return True


@condition(LsVarLog, [LsBoot, LsEtc])
def condition_3(*args):
return True


@condition(LsVarWwwPerms, [LsDev, LsDisk], optional=[LsVarRun])
def condition_4(*args):
return True


@condition([LsPci, LsPciVmmkn])
def condition_5(*args):
return True


@condition([LvmConf, LvmConfig])
def condition_6(*args):
return True


@condition(Mount, [LsTmp, LsVarTmp], optional=[LsUsrBin])
def condition_7(*args):
return True


@rule(Lsof, condition_1, condition_2,
[LsCPU, condition_3], [condition_4, LsSCSI], [condition_5, condition_6],
optional=[LSBlock, condition_7])
def report(*args):
return make_fail("HIT")


@condition(LsVarLog, [LsBoot, LsEtc])
def ABC(*args):
return True


@condition([LsPci, ABC])
def DEF(*args):
return True


@condition(LsPci, LsBoot, LsDisk)
def XYZ(*args):
return True


def test_get_dependency_specs_1_level_requires_only():
specs = get_dependency_specs(XYZ)
assert sorted(specs) == ['ls_boot', 'ls_disk', 'lspci']


def test_get_dependency_specs_2_level():
specs = get_dependency_specs(DEF)
# [
# ('lspci', [('ls_etc', 'ls_boot'), 'ls_var_log'])
# ]
assert len([alo for alo in specs if isinstance(alo, tuple)]) == 1
assert 'lspci' in specs[0]
x, y = specs[0]
if x == 'lspci':
assert 'ls_var_log' in y
else:
assert 'ls_var_log' in x
m, n = x
if isinstance(m, tuple):
t = m
else:
t = n
assert all(i in t for i in ('ls_etc', 'ls_boot'))


def test_get_dependency_specs_complex():
specs = get_dependency_specs(report)
# [
# 'installed_rpms',
# 'tags',
# 'lsof',
# 'virt_what',
# ('redhat_release', 'uname'),
# ('ps_auxcww', 'up2date'),
# ('ls_cpu', ['ls_var_log', ('ls_boot', 'ls_etc')]),
# ('lsscsi', ['ls_var_tmp', ('ls_disk', 'ls_dev')]),
# (('lspci', 'lspci_vmmkn'), ('lvm_conf', 'lvmconfig'))
# ]
requires = ['installed_rpms', 'tags', 'lsof', 'virt_what']
assert all(req in specs for req in requires) is True
# It's difficult to check the details since the result would in different
# order due to python versions. Here we just check the number of the
# `at_least_one` specs
assert len([alo for alo in specs if isinstance(alo, tuple)]) == 5

0 comments on commit fa731e6

Please sign in to comment.