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..47ef7dac34 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,35 @@ def test_zcrypt_mode(root_logger: Logger) -> None: } +def test_iommu_is_supported(root_logger: Logger) -> None: + + result = _CONSTRAINT_TRANSFORMERS['iommu.is_supported']( + _parse_iommu({"is-supported": True}), root_logger) + + assert result.to_mrack() == { + 'system': { + 'key_value': { + '_key': 'VIRT_IOMMU', + '_op': '==', + '_value': '1' + } + } + } + + result = _CONSTRAINT_TRANSFORMERS['iommu.is_supported']( + _parse_iommu({"is-supported": False}), root_logger) + + assert result.to_mrack() == { + 'system': { + 'key_value': { + '_key': 'VIRT_IOMMU', + '_op': '==', + '_value': '0' + } + } + } + + def test_location_lab_controller(root_logger: Logger) -> None: result = _CONSTRAINT_TRANSFORMERS['location.lab_controller']( 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 305154b24a..b1626edca2 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] }