Seems straightforward. There are actually some intersections here between my currently-existing config changes and some of the trimming you provide here which simplifies my upcoming series when I rebase it to use this series.
Reviewed-by: Nicholas Pratte <npra...@iol.unh.edu> On Thu, Aug 22, 2024 at 12:40 PM Luca Vizzarro <luca.vizza...@arm.com> wrote: > > Adds a new script which automatically re-generates the JSON schema file > based on the Pydantic configuration models. > > Moreover, update the JSON schema with this script for the first time. > > Signed-off-by: Luca Vizzarro <luca.vizza...@arm.com> > Reviewed-by: Paul Szczepanek <paul.szczepa...@arm.com> > --- > doc/guides/tools/dts.rst | 10 + > dts/framework/config/conf_yaml_schema.json | 776 ++++++++++++--------- > dts/generate-schema.py | 38 + > 3 files changed, 486 insertions(+), 338 deletions(-) > create mode 100755 dts/generate-schema.py > > diff --git a/doc/guides/tools/dts.rst b/doc/guides/tools/dts.rst > index 515b15e4d8..317bd0ff99 100644 > --- a/doc/guides/tools/dts.rst > +++ b/doc/guides/tools/dts.rst > @@ -430,6 +430,16 @@ Refer to the script for usage: > ``devtools/dts-check-format.sh -h``. > Configuration Schema > -------------------- > > +The configuration schema is automatically generated from Pydantic models and > can be found > +at ``dts/framework/config/conf_yaml_schema.json``. Whenever the models are > changed, the schema > +should be regenerated using the dedicated script at > ``dts/generate-schema.py``, e.g.: > + > +.. code-block:: console > + > + $ poetry shell > + (dts-py3.10) $ ./generate-schema.py > + > + > Definitions > ~~~~~~~~~~~ > > diff --git a/dts/framework/config/conf_yaml_schema.json > b/dts/framework/config/conf_yaml_schema.json > index f02a310bb5..1cf1bb098a 100644 > --- a/dts/framework/config/conf_yaml_schema.json > +++ b/dts/framework/config/conf_yaml_schema.json > @@ -1,402 +1,502 @@ > { > - "$schema": "https://json-schema.org/draft-07/schema", > - "title": "DTS Config Schema", > - "definitions": { > - "node_name": { > - "type": "string", > - "description": "A unique identifier for a node" > - }, > - "NIC": { > - "type": "string", > - "enum": [ > - "ALL", > - "ConnectX3_MT4103", > - "ConnectX4_LX_MT4117", > - "ConnectX4_MT4115", > - "ConnectX5_MT4119", > - "ConnectX5_MT4121", > - "I40E_10G-10G_BASE_T_BC", > - "I40E_10G-10G_BASE_T_X722", > - "I40E_10G-SFP_X722", > - "I40E_10G-SFP_XL710", > - "I40E_10G-X722_A0", > - "I40E_1G-1G_BASE_T_X722", > - "I40E_25G-25G_SFP28", > - "I40E_40G-QSFP_A", > - "I40E_40G-QSFP_B", > - "IAVF-ADAPTIVE_VF", > - "IAVF-VF", > - "IAVF_10G-X722_VF", > - "ICE_100G-E810C_QSFP", > - "ICE_25G-E810C_SFP", > - "ICE_25G-E810_XXV_SFP", > - "IGB-I350_VF", > - "IGB_1G-82540EM", > - "IGB_1G-82545EM_COPPER", > - "IGB_1G-82571EB_COPPER", > - "IGB_1G-82574L", > - "IGB_1G-82576", > - "IGB_1G-82576_QUAD_COPPER", > - "IGB_1G-82576_QUAD_COPPER_ET2", > - "IGB_1G-82580_COPPER", > - "IGB_1G-I210_COPPER", > - "IGB_1G-I350_COPPER", > - "IGB_1G-I354_SGMII", > - "IGB_1G-PCH_LPTLP_I218_LM", > - "IGB_1G-PCH_LPTLP_I218_V", > - "IGB_1G-PCH_LPT_I217_LM", > - "IGB_1G-PCH_LPT_I217_V", > - "IGB_2.5G-I354_BACKPLANE_2_5GBPS", > - "IGC-I225_LM", > - "IGC-I226_LM", > - "IXGBE_10G-82599_SFP", > - "IXGBE_10G-82599_SFP_SF_QP", > - "IXGBE_10G-82599_T3_LOM", > - "IXGBE_10G-82599_VF", > - "IXGBE_10G-X540T", > - "IXGBE_10G-X540_VF", > - "IXGBE_10G-X550EM_A_SFP", > - "IXGBE_10G-X550EM_X_10G_T", > - "IXGBE_10G-X550EM_X_SFP", > - "IXGBE_10G-X550EM_X_VF", > - "IXGBE_10G-X550T", > - "IXGBE_10G-X550_VF", > - "brcm_57414", > - "brcm_P2100G", > - "cavium_0011", > - "cavium_a034", > - "cavium_a063", > - "cavium_a064", > - "fastlinq_ql41000", > - "fastlinq_ql41000_vf", > - "fastlinq_ql45000", > - "fastlinq_ql45000_vf", > - "hi1822", > - "virtio" > - ] > - }, > - > - "ARCH": { > - "type": "string", > + "$defs": { > + "Architecture": { > + "description": "The supported architectures of > :class:`~framework.testbed_model.node.Node`\\s.", > "enum": [ > + "i686", > "x86_64", > + "x86_32", > "arm64", > "ppc64le" > - ] > - }, > - "OS": { > - "type": "string", > - "enum": [ > - "linux" > - ] > - }, > - "cpu": { > - "type": "string", > - "description": "Native should be the default on x86", > - "enum": [ > - "native", > - "armv8a", > - "dpaa2", > - "thunderx", > - "xgene1" > - ] > - }, > - "compiler": { > - "type": "string", > - "enum": [ > - "gcc", > - "clang", > - "icc", > - "mscv" > - ] > + ], > + "title": "Architecture", > + "type": "string" > }, > - "build_target": { > - "type": "object", > - "description": "Targets supported by DTS", > + "BuildTargetConfiguration": { > + "additionalProperties": false, > + "description": "DPDK build configuration.\n\nThe configuration used > for building DPDK.\n\nAttributes:\n arch: The target architecture to build > for.\n os: The target os to build for.\n cpu: The target CPU to build > for.\n compiler: The compiler executable to use.\n compiler_wrapper: > This string will be put in front of the compiler when\n executing the > build. Useful for adding wrapper commands, such as ``ccache``.", > "properties": { > "arch": { > - "type": "string", > - "enum": [ > - "ALL", > - "x86_64", > - "arm64", > - "ppc64le", > - "other" > - ] > + "$ref": "#/$defs/Architecture" > }, > "os": { > - "$ref": "#/definitions/OS" > + "$ref": "#/$defs/OS" > }, > "cpu": { > - "$ref": "#/definitions/cpu" > + "$ref": "#/$defs/CPUType" > }, > "compiler": { > - "$ref": "#/definitions/compiler" > + "$ref": "#/$defs/Compiler" > }, > - "compiler_wrapper": { > - "type": "string", > - "description": "This will be added before compiler to the CC > variable when building DPDK. Optional." > + "compiler_wrapper": { > + "default": "", > + "title": "Compiler Wrapper", > + "type": "string" > } > }, > - "additionalProperties": false, > "required": [ > "arch", > "os", > "cpu", > "compiler" > - ] > + ], > + "title": "BuildTargetConfiguration", > + "type": "object" > }, > - "hugepages_2mb": { > - "type": "object", > - "description": "Optional hugepage configuration. If not specified, > hugepages won't be configured and DTS will use system configuration.", > + "CPUType": { > + "description": "The supported CPUs of > :class:`~framework.testbed_model.node.Node`\\s.", > + "enum": [ > + "native", > + "armv8a", > + "dpaa2", > + "thunderx", > + "xgene1" > + ], > + "title": "CPUType", > + "type": "string" > + }, > + "Compiler": { > + "description": "The supported compilers of > :class:`~framework.testbed_model.node.Node`\\s.", > + "enum": [ > + "gcc", > + "clang", > + "icc", > + "msvc" > + ], > + "title": "Compiler", > + "type": "string" > + }, > + "HugepageConfiguration": { > + "additionalProperties": false, > + "description": "The hugepage configuration of > :class:`~framework.testbed_model.node.Node`\\s.\n\nAttributes:\n > number_of: The number of hugepages to allocate.\n force_first_numa: If > :data:`True`, the hugepages will be configured on the first NUMA node.", > "properties": { > "number_of": { > - "type": "integer", > - "description": "The number of hugepages to configure. Hugepage > size will be the system default." > + "title": "Number Of", > + "type": "integer" > }, > "force_first_numa": { > - "type": "boolean", > - "description": "Set to True to force configuring hugepages on the > first NUMA node. Defaults to False." > + "title": "Force First Numa", > + "type": "boolean" > } > }, > - "additionalProperties": false, > "required": [ > - "number_of" > - ] > - }, > - "mac_address": { > - "type": "string", > - "description": "A MAC address", > - "pattern": "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$" > + "number_of", > + "force_first_numa" > + ], > + "title": "HugepageConfiguration", > + "type": "object" > }, > - "pci_address": { > - "type": "string", > - "pattern": "^[\\da-fA-F]{4}:[\\da-fA-F]{2}:[\\da-fA-F]{2}.\\d:?\\w*$" > + "OS": { > + "description": "The supported operating systems of > :class:`~framework.testbed_model.node.Node`\\s.", > + "enum": [ > + "linux", > + "freebsd", > + "windows" > + ], > + "title": "OS", > + "type": "string" > }, > - "port_peer_address": { > - "description": "Peer is a TRex port, and IXIA port or a PCI address", > - "oneOf": [ > - { > - "description": "PCI peer port", > - "$ref": "#/definitions/pci_address" > + "PortConfig": { > + "additionalProperties": false, > + "description": "The port configuration of > :class:`~framework.testbed_model.node.Node`\\s.\n\nAttributes:\n pci: The > PCI address of the port.\n os_driver_for_dpdk: The operating system driver > name for use with DPDK.\n os_driver: The operating system driver name when > the operating system controls the port.\n peer_node: The > :class:`~framework.testbed_model.node.Node` of the port\n connected to > this port.\n peer_pci: The PCI address of the port connected to this > port.", > + "properties": { > + "pci": { > + "description": "The local PCI address of the port.", > + "pattern": > "^[\\da-fA-F]{4}:[\\da-fA-F]{2}:[\\da-fA-F]{2}.\\d:?\\w*$", > + "title": "Pci", > + "type": "string" > + }, > + "os_driver_for_dpdk": { > + "description": "The driver that the kernel should bind this device > to for DPDK to use it.", > + "examples": [ > + "vfio-pci", > + "mlx5_core" > + ], > + "title": "Os Driver For Dpdk", > + "type": "string" > + }, > + "os_driver": { > + "description": "The driver normally used by this port", > + "examples": [ > + "i40e", > + "ice", > + "mlx5_core" > + ], > + "title": "Os Driver", > + "type": "string" > + }, > + "peer_node": { > + "description": "The name of the peer node this port is connected > to.", > + "title": "Peer Node", > + "type": "string" > + }, > + "peer_pci": { > + "description": "The PCI address of the peer port this port is > connected to.", > + "pattern": > "^[\\da-fA-F]{4}:[\\da-fA-F]{2}:[\\da-fA-F]{2}.\\d:?\\w*$", > + "title": "Peer Pci", > + "type": "string" > } > - ] > + }, > + "required": [ > + "pci", > + "os_driver_for_dpdk", > + "os_driver", > + "peer_node", > + "peer_pci" > + ], > + "title": "PortConfig", > + "type": "object" > }, > - "test_suite": { > - "type": "string", > - "enum": [ > - "hello_world", > - "os_udp", > - "pmd_buffer_scatter" > - ] > + "ScapyTrafficGeneratorConfig": { > + "additionalProperties": false, > + "description": "Scapy traffic generator specific configuration.", > + "properties": { > + "type": { > + "const": "SCAPY", > + "enum": [ > + "SCAPY" > + ], > + "title": "Type", > + "type": "string" > + } > + }, > + "required": [ > + "type" > + ], > + "title": "ScapyTrafficGeneratorConfig", > + "type": "object" > }, > - "test_target": { > - "type": "object", > + "SutNodeConfiguration": { > + "additionalProperties": false, > + "description": ":class:`~framework.testbed_model.sut_node.SutNode` > specific configuration.\n\nAttributes:\n memory_channels: The number of > memory channels to use when running DPDK.", > "properties": { > - "suite": { > - "$ref": "#/definitions/test_suite" > + "name": { > + "description": "A unique identifier for this node.", > + "title": "Name", > + "type": "string" > + }, > + "hostname": { > + "description": "The hostname or IP address of the node.", > + "title": "Hostname", > + "type": "string" > + }, > + "user": { > + "description": "The login user to use to connect to this node.", > + "title": "User", > + "type": "string" > }, > - "cases": { > - "type": "array", > - "description": "If specified, only this subset of test suite's > test cases will be run.", > + "password": { > + "anyOf": [ > + { > + "type": "string" > + }, > + { > + "type": "null" > + } > + ], > + "default": null, > + "description": "The login password to use to connect to this node. > SSH keys are STRONGLY preferred, use only as last resort.", > + "title": "Password" > + }, > + "use_first_core": { > + "default": false, > + "description": "DPDK won't use the first physical core if set to > False.", > + "title": "Use First Core", > + "type": "boolean" > + }, > + "hugepages_2mb": { > + "anyOf": [ > + { > + "$ref": "#/$defs/HugepageConfiguration" > + }, > + { > + "type": "null" > + } > + ], > + "default": null > + }, > + "ports": { > "items": { > - "type": "string" > + "$ref": "#/$defs/PortConfig" > }, > - "minimum": 1 > + "minItems": 1, > + "title": "Ports", > + "type": "array" > + }, > + "memory_channels": { > + "default": 1, > + "description": "Number of memory channels to use when running > DPDK.", > + "title": "Memory Channels", > + "type": "integer" > + }, > + "arch": { > + "$ref": "#/$defs/Architecture" > + }, > + "os": { > + "$ref": "#/$defs/OS" > + }, > + "lcores": { > + "default": "1", > + "description": "Comma-separated list of logical cores to use. An > empty string means use all lcores.", > + "examples": [ > + "1,2,3,4,5,18-22", > + "10-15" > + ], > + "pattern": > "^(([0-9]+|([0-9]+-[0-9]+))(,([0-9]+|([0-9]+-[0-9]+)))*)?$", > + "title": "Lcores", > + "type": "string" > } > }, > "required": [ > - "suite" > + "name", > + "hostname", > + "user", > + "ports", > + "arch", > + "os" > ], > - "additionalProperties": false > - } > - }, > - "type": "object", > - "properties": { > - "nodes": { > - "type": "array", > - "items": { > - "type": "object", > - "properties": { > - "name": { > - "type": "string", > - "description": "A unique identifier for this node" > - }, > - "hostname": { > - "type": "string", > - "description": "A hostname from which the node running DTS can > access this node. This can also be an IP address." > - }, > - "user": { > - "type": "string", > - "description": "The user to access this node with." > - }, > - "password": { > - "type": "string", > - "description": "The password to use on this node. Use only as a > last resort. SSH keys are STRONGLY preferred." > - }, > - "arch": { > - "$ref": "#/definitions/ARCH" > - }, > - "os": { > - "$ref": "#/definitions/OS" > - }, > - "lcores": { > - "type": "string", > - "pattern": > "^(([0-9]+|([0-9]+-[0-9]+))(,([0-9]+|([0-9]+-[0-9]+)))*)?$", > - "description": "Optional comma-separated list of logical cores > to use, e.g.: 1,2,3,4,5,18-22. Defaults to 1. An empty string means use all > lcores." > + "title": "SutNodeConfiguration", > + "type": "object" > + }, > + "TGNodeConfiguration": { > + "additionalProperties": false, > + "description": ":class:`~framework.testbed_model.tg_node.TGNode` > specific configuration.\n\nAttributes:\n traffic_generator: The > configuration of the traffic generator present on the TG node.", > + "properties": { > + "name": { > + "description": "A unique identifier for this node.", > + "title": "Name", > + "type": "string" > + }, > + "hostname": { > + "description": "The hostname or IP address of the node.", > + "title": "Hostname", > + "type": "string" > + }, > + "user": { > + "description": "The login user to use to connect to this node.", > + "title": "User", > + "type": "string" > + }, > + "password": { > + "anyOf": [ > + { > + "type": "string" > + }, > + { > + "type": "null" > + } > + ], > + "default": null, > + "description": "The login password to use to connect to this node. > SSH keys are STRONGLY preferred, use only as last resort.", > + "title": "Password" > + }, > + "use_first_core": { > + "default": false, > + "description": "DPDK won't use the first physical core if set to > False.", > + "title": "Use First Core", > + "type": "boolean" > + }, > + "hugepages_2mb": { > + "anyOf": [ > + { > + "$ref": "#/$defs/HugepageConfiguration" > + }, > + { > + "type": "null" > + } > + ], > + "default": null > + }, > + "ports": { > + "items": { > + "$ref": "#/$defs/PortConfig" > }, > - "use_first_core": { > - "type": "boolean", > - "description": "Indicate whether DPDK should use the first > physical core. It won't be used by default." > + "minItems": 1, > + "title": "Ports", > + "type": "array" > + }, > + "arch": { > + "$ref": "#/$defs/Architecture" > + }, > + "os": { > + "$ref": "#/$defs/OS" > + }, > + "lcores": { > + "default": "1", > + "description": "Comma-separated list of logical cores to use. An > empty string means use all lcores.", > + "examples": [ > + "1,2,3,4,5,18-22", > + "10-15" > + ], > + "pattern": > "^(([0-9]+|([0-9]+-[0-9]+))(,([0-9]+|([0-9]+-[0-9]+)))*)?$", > + "title": "Lcores", > + "type": "string" > + }, > + "traffic_generator": { > + "discriminator": { > + "mapping": { > + "SCAPY": "#/$defs/ScapyTrafficGeneratorConfig" > + }, > + "propertyName": "type" > }, > - "memory_channels": { > - "type": "integer", > - "description": "How many memory channels to use. Optional, > defaults to 1." > + "oneOf": [ > + { > + "$ref": "#/$defs/ScapyTrafficGeneratorConfig" > + } > + ], > + "title": "Traffic Generator" > + } > + }, > + "required": [ > + "name", > + "hostname", > + "user", > + "ports", > + "arch", > + "os", > + "traffic_generator" > + ], > + "title": "TGNodeConfiguration", > + "type": "object" > + }, > + "TestRunConfiguration": { > + "additionalProperties": false, > + "description": "The configuration of a test run.\n\nThe configuration > contains testbed information, what tests to execute\nand with what DPDK > build.\n\nAttributes:\n build_targets: A list of DPDK builds to test.\n > perf: Whether to run performance tests.\n func: Whether to run functional > tests.\n skip_smoke_tests: Whether to skip smoke tests.\n test_suites: > The names of test suites and/or test cases to execute.\n > system_under_test_node: The SUT node configuration to use in this test run.\n > traffic_generator_node: The TG node name to use in this test run.", > + "properties": { > + "perf": { > + "description": "Enable performance testing.", > + "title": "Perf", > + "type": "boolean" > + }, > + "func": { > + "description": "Enable functional testing.", > + "title": "Func", > + "type": "boolean" > + }, > + "test_suites": { > + "items": { > + "$ref": "#/$defs/TestSuiteConfig" > }, > - "hugepages_2mb": { > - "$ref": "#/definitions/hugepages_2mb" > + "minItems": 1, > + "title": "Test Suites", > + "type": "array" > + }, > + "build_targets": { > + "items": { > + "$ref": "#/$defs/BuildTargetConfiguration" > }, > - "ports": { > - "type": "array", > - "items": { > - "type": "object", > - "description": "Each port should be described on both sides of > the connection. This makes configuration slightly more verbose but greatly > simplifies implementation. If there are inconsistencies, then DTS will not > run until that issue is fixed. An example inconsistency would be port 1, node > 1 says it is connected to port 1, node 2, but port 1, node 2 says it is > connected to port 2, node 1.", > - "properties": { > - "pci": { > - "$ref": "#/definitions/pci_address", > - "description": "The local PCI address of the port" > - }, > - "os_driver_for_dpdk": { > - "type": "string", > - "description": "The driver that the kernel should bind > this device to for DPDK to use it. (ex: vfio-pci)" > - }, > - "os_driver": { > - "type": "string", > - "description": "The driver normally used by this port (ex: > i40e)" > - }, > - "peer_node": { > - "type": "string", > - "description": "The name of the node the peer port is on" > - }, > - "peer_pci": { > - "$ref": "#/definitions/pci_address", > - "description": "The PCI address of the peer port" > - } > - }, > - "additionalProperties": false, > - "required": [ > - "pci", > - "os_driver_for_dpdk", > - "os_driver", > - "peer_node", > - "peer_pci" > - ] > - }, > - "minimum": 1 > + "title": "Build Targets", > + "type": "array" > + }, > + "skip_smoke_tests": { > + "default": false, > + "title": "Skip Smoke Tests", > + "type": "boolean" > + }, > + "system_under_test_node": { > + "$ref": "#/$defs/TestRunSUTNodeConfiguration" > + }, > + "traffic_generator_node": { > + "title": "Traffic Generator Node", > + "type": "string" > + } > + }, > + "required": [ > + "perf", > + "func", > + "test_suites", > + "build_targets", > + "system_under_test_node", > + "traffic_generator_node" > + ], > + "title": "TestRunConfiguration", > + "type": "object" > + }, > + "TestRunSUTNodeConfiguration": { > + "additionalProperties": false, > + "description": "The SUT node configuration of a test > run.\n\nAttributes:\n node_name: The SUT node to use in this test run.\n > vdevs: The names of virtual devices to test.", > + "properties": { > + "vdevs": { > + "items": { > + "type": "string" > }, > - "traffic_generator": { > - "oneOf": [ > - { > - "type": "object", > - "description": "Scapy traffic generator. Used for functional > testing.", > - "properties": { > - "type": { > - "type": "string", > - "enum": [ > - "SCAPY" > - ] > - } > - } > - } > - ] > - } > + "title": "Vdevs", > + "type": "array" > }, > - "additionalProperties": false, > - "required": [ > - "name", > - "hostname", > - "user", > - "arch", > - "os" > - ] > + "node_name": { > + "title": "Node Name", > + "type": "string" > + } > }, > - "minimum": 1 > + "required": [ > + "node_name" > + ], > + "title": "TestRunSUTNodeConfiguration", > + "type": "object" > }, > - "test_runs": { > - "type": "array", > - "items": { > - "type": "object", > - "properties": { > - "build_targets": { > - "type": "array", > - "items": { > - "$ref": "#/definitions/build_target" > + "TestSuiteConfig": { > + "anyOf": [ > + { > + "additionalProperties": false, > + "properties": { > + "test_suite": { > + "description": "The identifying name of the test suite.", > + "title": "Test suite name", > + "type": "string" > }, > - "minimum": 1 > - }, > - "perf": { > - "type": "boolean", > - "description": "Enable performance testing." > - }, > - "func": { > - "type": "boolean", > - "description": "Enable functional testing." > - }, > - "test_suites": { > - "type": "array", > - "items": { > - "oneOf": [ > - { > - "$ref": "#/definitions/test_suite" > - }, > - { > - "$ref": "#/definitions/test_target" > - } > - ] > + "test_cases": { > + "description": "The identifying name of the test cases of the > test suite.", > + "items": { > + "type": "string" > + }, > + "title": "Test cases by name", > + "type": "array" > } > }, > - "skip_smoke_tests": { > - "description": "Optional field that allows you to skip smoke > testing", > - "type": "boolean" > - }, > - "system_under_test_node": { > - "type":"object", > - "properties": { > - "node_name": { > - "$ref": "#/definitions/node_name" > - }, > - "vdevs": { > - "description": "Optional list of names of vdevs to be used > in the test run", > - "type": "array", > - "items": { > - "type": "string" > - } > - } > - }, > - "required": [ > - "node_name" > - ] > + "required": [ > + "test_suite" > + ], > + "type": "object" > + }, > + { > + "type": "string" > + } > + ], > + "description": "Test suite configuration.\n\nInformation about a > single test suite to be executed. It can be represented and validated as > a\nstring type in the form of: ``TEST_SUITE [TEST_CASE, ...]``, in the > configuration file.\n\nAttributes:\n test_suite: The name of the test > suite module without the starting ``TestSuite_``.\n test_cases: The names > of test cases from this test suite to execute.\n If empty, all test > cases will be executed.", > + "title": "TestSuiteConfig" > + } > + }, > + "description": "DTS testbed and test configuration.\n\nAttributes:\n > test_runs: Test run configurations.\n nodes: Node configurations.", > + "properties": { > + "test_runs": { > + "items": { > + "$ref": "#/$defs/TestRunConfiguration" > + }, > + "minItems": 1, > + "title": "Test Runs", > + "type": "array" > + }, > + "nodes": { > + "items": { > + "anyOf": [ > + { > + "$ref": "#/$defs/TGNodeConfiguration" > }, > - "traffic_generator_node": { > - "$ref": "#/definitions/node_name" > + { > + "$ref": "#/$defs/SutNodeConfiguration" > } > - }, > - "additionalProperties": false, > - "required": [ > - "build_targets", > - "perf", > - "func", > - "test_suites", > - "system_under_test_node", > - "traffic_generator_node" > ] > }, > - "minimum": 1 > + "minItems": 1, > + "title": "Nodes", > + "type": "array" > } > }, > "required": [ > "test_runs", > "nodes" > ], > - "additionalProperties": false > -} > + "title": "Configuration", > + "type": "object", > + "$schema": "https://json-schema.org/draft/2020-12/schema" > +} > \ No newline at end of file > diff --git a/dts/generate-schema.py b/dts/generate-schema.py > new file mode 100755 > index 0000000000..b41d28492f > --- /dev/null > +++ b/dts/generate-schema.py > @@ -0,0 +1,38 @@ > +#!/usr/bin/env python3 > +# SPDX-License-Identifier: BSD-3-Clause > +# Copyright(c) 2024 Arm Limited > + > +"""JSON schema generation script.""" > + > +import json > +import os > + > +from pydantic.json_schema import GenerateJsonSchema > + > +from framework.config import ConfigurationType > + > +DTS_DIR = os.path.dirname(os.path.realpath(__file__)) > +RELATIVE_PATH_TO_SCHEMA = "framework/config/conf_yaml_schema.json" > + > + > +class GenerateSchemaWithDialect(GenerateJsonSchema): > + """Custom schema generator which adds the schema dialect.""" > + > + def generate(self, schema, mode="validation"): > + """Generate JSON schema.""" > + json_schema = super().generate(schema, mode=mode) > + json_schema["$schema"] = self.schema_dialect > + return json_schema > + > + > +try: > + path = os.path.join(DTS_DIR, RELATIVE_PATH_TO_SCHEMA) > + > + with open(path, "w") as schema_file: > + schema_dict = > ConfigurationType.json_schema(schema_generator=GenerateSchemaWithDialect) > + schema_json = json.dumps(schema_dict, indent=2) > + schema_file.write(schema_json) > + > + print("Schema generated successfully!") > +except Exception as e: > + raise Exception("failed to generate schema") from e > -- > 2.34.1 >