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
>

Reply via email to