From d7686b4ae8f7f25c2570242cfe01566ce46c77fe Mon Sep 17 00:00:00 2001 From: qiankehan Date: Wed, 2 Oct 2024 03:37:51 +0800 Subject: [PATCH] Add the `iommu` specification for hardware (#3100) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #2392 Signed-off-by: Han Han Co-authored-by: Petr Šplíchal --- docs/releases.rst | 5 +++++ spec/hardware/iommu.fmf | 32 +++++++++++++++++++++++++++ tests/unit/provision/mrack/test_hw.py | 17 ++++++++++++++ tests/unit/test_utils.py | 8 +++---- tmt/hardware.py | 22 ++++++++++++++++++ tmt/schemas/provision/hardware.yaml | 17 ++++++++++++++ tmt/steps/provision/mrack.py | 16 ++++++++++++++ 7 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 spec/hardware/iommu.fmf diff --git a/docs/releases.rst b/docs/releases.rst index eb873c1a2d..b994400ab1 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -57,6 +57,11 @@ The ``tmt try`` command now supports the new new :ref:`/stories/cli/try/option/install` option backed by the :ref:`prepare/feature` plugin. +The new key :ref:`/spec/hardware/iommu` allowing to provision a +guest with the `Input–output memory management unit` has been +added into the :ref:`/spec/hardware` specification and implemented +in the :ref:`/plugins/provision/beaker` provision plugin. + tmt-1.36.1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/spec/hardware/iommu.fmf b/spec/hardware/iommu.fmf new file mode 100644 index 0000000000..49903026fb --- /dev/null +++ b/spec/hardware/iommu.fmf @@ -0,0 +1,32 @@ +summary: | + Select or provision a guest with the `Input–output memory management unit`. + +description: | + .. code-block:: + + iommu: + # Boolean, whether the guest supports IOMMU + is-supported: true|false + # String, the model name for IOMMU + model-name: "virtio"|"intel"|"smmuv3"|... + + .. versionadded:: 1.37 + + .. versionchanged:: 1.37 + ``beaker`` plugin supports ``iommu`` + +example: + - | + # Require a guest that supports IOMMU + iommu: + is-supported: true + + - | + # Require a guest with the IOMMU of virtio model + iommu: + is-supported: true + model-name: virtio + +link: + - implemented-by: /tmt/steps/provision/mrack.py + note: "``iommu.is-supported`` only" diff --git a/tests/unit/provision/mrack/test_hw.py b/tests/unit/provision/mrack/test_hw.py index 958614744f..e0d0827511 100644 --- a/tests/unit/provision/mrack/test_hw.py +++ b/tests/unit/provision/mrack/test_hw.py @@ -10,6 +10,7 @@ _parse_cpu, _parse_disk, _parse_hostname, + _parse_iommu, _parse_location, _parse_memory, _parse_system, @@ -788,6 +789,22 @@ def test_zcrypt_mode(root_logger: Logger) -> None: } +def test_iommu_is_supported(root_logger: Logger) -> None: + + for value in True, False: + + result = _CONSTRAINT_TRANSFORMERS['iommu.is_supported']( + _parse_iommu({"is-supported": value}), root_logger) + + assert result.to_mrack() == { + 'key_value': { + '_key': 'VIRT_IOMMU', + '_op': '==', + '_value': str(int(value)) + } + } + + def test_location_lab_controller(root_logger: Logger) -> None: result = _CONSTRAINT_TRANSFORMERS['location.lab_controller']( diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index ac057542dc..13330c18ce 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -1742,7 +1742,7 @@ def test_jira_link_test_only(self, mock_config_tree, mock_add_simple_link) -> No logger=self.logger) result = mock_add_simple_link.call_args.args[1] assert 'https://tmt.testing-farm.io/?' in result['url'] - assert 'test-url=https%3A%2F%2Fgithub.com%2Fteemtee%2Ftmt' in result['url'] + assert 'test-url=https%3A%2F%2Fgithub.com%2F' in result['url'] assert '&test-name=%2Ftmp%2Ftest' in result['url'] assert '&test-path=%2Ftests%2Funit%2Ftmp' in result['url'] @@ -1760,15 +1760,15 @@ def test_jira_link_test_plan_story(self, mock_config_tree, mock_add_simple_link) result = mock_add_simple_link.call_args.args[1] assert 'https://tmt.testing-farm.io/?' in result['url'] - assert 'test-url=https%3A%2F%2Fgithub.com%2Fteemtee%2Ftmt' in result['url'] + assert 'test-url=https%3A%2F%2Fgithub.com%2F' in result['url'] assert '&test-name=%2Ftmp%2Ftest' in result['url'] assert '&test-path=%2Ftests%2Funit%2Ftmp' in result['url'] - assert '&plan-url=https%3A%2F%2Fgithub.com%2Fteemtee%2Ftmt' in result['url'] + assert '&plan-url=https%3A%2F%2Fgithub.com%2F' in result['url'] assert '&plan-name=%2Ftmp%2Fplan' in result['url'] assert '&plan-path=%2Ftests%2Funit%2Ftmp' in result['url'] - assert '&story-url=https%3A%2F%2Fgithub.com%2Fteemtee%2Ftmt' in result['url'] + assert '&story-url=https%3A%2F%2Fgithub.com%2F' in result['url'] assert '&story-name=%2Ftmp%2Fstory' in result['url'] assert '&story-path=%2Ftests%2Funit%2Ftmp' in result['url'] diff --git a/tmt/hardware.py b/tmt/hardware.py index f79d1b63d3..bf0010015f 100644 --- a/tmt/hardware.py +++ b/tmt/hardware.py @@ -1333,6 +1333,25 @@ def _parse_zcrypt(spec: Spec) -> BaseConstraint: return group +@ungroupify +def _parse_iommu(spec: Spec) -> BaseConstraint: + """ + Parse constraints related to the ``iommu`` HW requirement. + + :param spec: raw constraint block specification. + :returns: block representation as :py:class:`BaseConstraint` or one of its subclasses. + """ + + group = And() + + group.constraints += _parse_flag_constraints(spec, + 'iommu', + ('is-supported',)) + group.constraints += _parse_text_constraints(spec, 'iommu', ('model-name',)) + + return group + + @ungroupify def _parse_location(spec: Spec) -> BaseConstraint: """ @@ -1428,6 +1447,9 @@ def _parse_generic_spec(spec: Spec) -> BaseConstraint: if 'zcrypt' in spec: group.constraints += [_parse_zcrypt(spec['zcrypt'])] + if 'iommu' in spec: + group.constraints += [_parse_iommu(spec['iommu'])] + return group diff --git a/tmt/schemas/provision/hardware.yaml b/tmt/schemas/provision/hardware.yaml index 7d1a871380..53ce43a47e 100644 --- a/tmt/schemas/provision/hardware.yaml +++ b/tmt/schemas/provision/hardware.yaml @@ -355,6 +355,20 @@ definitions: # empty `boot`. minProperties: 1 + # Hw requirements `iommu` block + iommu: + type: object + + properties: + is-supported: + type: boolean + + model-name: + type: string + + additionalProperties: false + minProperties: 1 + # HW requirements: basic block block: type: object @@ -405,6 +419,9 @@ definitions: virtualization: "$ref": "#/definitions/virtualization" + iommu: + "$ref": "#/definitions/iommu" + additionalProperties: false # enforce at least one property - we don't care which one, but we don't want diff --git a/tmt/steps/provision/mrack.py b/tmt/steps/provision/mrack.py index 2e833f4951..be94845153 100644 --- a/tmt/steps/provision/mrack.py +++ b/tmt/steps/provision/mrack.py @@ -512,6 +512,21 @@ def _transform_zcrypt_mode( children=[MrackHWKeyValue('ZCRYPT_MODE', beaker_operator, actual_value)]) +def _transform_iommu_is_supported( + constraint: tmt.hardware.FlagConstraint, + logger: tmt.log.Logger) -> MrackBaseHWElement: + + test = (constraint.operator, constraint.value) + + if test in [(tmt.hardware.Operator.EQ, True), (tmt.hardware.Operator.NEQ, False)]: + return MrackHWKeyValue('VIRT_IOMMU', '==', '1') + + if test in [(tmt.hardware.Operator.EQ, False), (tmt.hardware.Operator.NEQ, True)]: + return MrackHWKeyValue('VIRT_IOMMU', '==', '0') + + return _transform_unsupported(constraint, logger) + + def _transform_location_lab_controller( constraint: tmt.hardware.TextConstraint, logger: tmt.log.Logger) -> MrackBaseHWElement: @@ -573,6 +588,7 @@ def _transform_system_numa_nodes( 'zcrypt.adapter': _transform_zcrypt_adapter, # type: ignore[dict-item] 'zcrypt.mode': _transform_zcrypt_mode, # type: ignore[dict-item] 'system.numa_nodes': _transform_system_numa_nodes, # type: ignore[dict-item] + 'iommu.is_supported': _transform_iommu_is_supported, # type: ignore[dict-item] }