From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id B307945A84; Tue, 1 Oct 2024 22:48:23 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 43EEC40268; Tue, 1 Oct 2024 22:48:23 +0200 (CEST) Received: from mail-lf1-f46.google.com (mail-lf1-f46.google.com [209.85.167.46]) by mails.dpdk.org (Postfix) with ESMTP id 1E91640267 for ; Tue, 1 Oct 2024 22:48:21 +0200 (CEST) Received: by mail-lf1-f46.google.com with SMTP id 2adb3069b0e04-5398cf0c328so505682e87.0 for ; Tue, 01 Oct 2024 13:48:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1727815700; x=1728420500; darn=dpdk.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=Uw6ElbpiJ/Qr1uFOq0gDxcOn3hT518lpX+rrU1kbIhc=; b=h2YYV1Oz7q86DF0PTgd7TwIDmCu4PKS5VPMoCQzVbTAo3U0OnboIBWeV0aPDFmiaWD IHxwhshy04w58dirW6yJgX2i/yIZvsTp9hId2m3t+oFJxYbFFUKJTK2mo7aYvcp7ZhT7 eqAehrjkcqY3vZfPwo+ywjVFeRcD9bUzvmavA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1727815700; x=1728420500; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Uw6ElbpiJ/Qr1uFOq0gDxcOn3hT518lpX+rrU1kbIhc=; b=bc4JbY80ESABjsL7qJarnNvcqAjBvEOLYmlQjlAc1+Yr081QXHk2hr4sEOD3t3wEak NThXwYpmwvqiWRu9XmhN8xIXQ+ciiMgIhewPABxHPxFe6nxyJcRlCFWOdnj80rnI5+bg bwafqOlW6k2IutpBQdTdGUh3rbNVSfNfg7sw8eVQk65+iOzYtL76h/l7Th1sac8/plFC I42LTmdlc+R0yJZPCl0kOgFKktraLz6szR8S/I4xsxfUYl0w9RDmZsEBCtRQT8/sosWC vAFRrwtTfT/QPEK62JTylpekt0qgoAeGi3iqbuv3ygfE/+NDWaSF7Wj80Ys6NDyhJNub lwAA== X-Gm-Message-State: AOJu0Yz8cGAXWCBO6UGRnkqcNiIPuaZ6YDGeOkOK9TQ1sEhGTcgf2rdJ 6Hyy7IPB5rAcRXweloCfBwo9Uk/KIS3izpfhzdE/erzJnGoU+XaaMTslHknqdm42GQdUl1YTfvW ZqyLtYcqVwOmCNa5LlvrM5yCZhwsl3kXywT+p9w== X-Google-Smtp-Source: AGHT+IG0oOHe1SNxp+Zc6hXmDEtmxz3yO9JB/YiJIMQV79yjBAKOxniRsnaEb7oEQmSndeOUP+YmH1jZl6mpN2gED8A= X-Received: by 2002:a2e:a543:0:b0:2ee:d55c:255f with SMTP id 38308e7fff4ca-2fae10a9041mr1833041fa.7.1727815699556; Tue, 01 Oct 2024 13:48:19 -0700 (PDT) MIME-Version: 1.0 References: <20240822163941.1390326-1-luca.vizzarro@arm.com> <20240822163941.1390326-6-luca.vizzarro@arm.com> In-Reply-To: <20240822163941.1390326-6-luca.vizzarro@arm.com> From: Nicholas Pratte Date: Tue, 1 Oct 2024 16:48:08 -0400 Message-ID: Subject: Re: [PATCH 5/5] dts: add JSON schema generation script To: Luca Vizzarro Cc: dev@dpdk.org, Honnappa Nagarahalli , =?UTF-8?Q?Juraj_Linke=C5=A1?= , Paul Szczepanek Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org 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 On Thu, Aug 22, 2024 at 12:40=E2=80=AFPM Luca Vizzarro 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 > Reviewed-by: Paul Szczepanek > --- > 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 a= re changed, the schema > +should be regenerated using the dedicated script at ``dts/generate-schem= a.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/c= onfig/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 use= d for building DPDK.\n\nAttributes:\n arch: The target architecture to b= uild 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_wra= pper: This string will be put in front of the compiler when\n execut= ing 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 v= ariable 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_m= odel.node.Node`\\s.", > + "enum": [ > + "native", > + "armv8a", > + "dpaa2", > + "thunderx", > + "xgene1" > + ], > + "title": "CPUType", > + "type": "string" > + }, > + "Compiler": { > + "description": "The supported compilers of :class:`~framework.test= bed_model.node.Node`\\s.", > + "enum": [ > + "gcc", > + "clang", > + "icc", > + "msvc" > + ], > + "title": "Compiler", > + "type": "string" > + }, > + "HugepageConfiguration": { > + "additionalProperties": false, > + "description": "The hugepage configuration of :class:`~framework.t= estbed_model.node.Node`\\s.\n\nAttributes:\n number_of: The number of hu= gepages 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:`~framew= ork.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 addres= s", > - "oneOf": [ > - { > - "description": "PCI peer port", > - "$ref": "#/definitions/pci_address" > + "PortConfig": { > + "additionalProperties": false, > + "description": "The port configuration of :class:`~framework.testb= ed_model.node.Node`\\s.\n\nAttributes:\n pci: The PCI address of the por= t.\n os_driver_for_dpdk: The operating system driver name for use with D= PDK.\n os_driver: The operating system driver name when the operating sy= stem controls the port.\n peer_node: The :class:`~framework.testbed_mode= l.node.Node` of the port\n connected to this port.\n peer_pci: Th= e 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 de= vice 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 connect= ed 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 n= ode. 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 c= an 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 a= s 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 cor= es 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` s= pecific configuration.\n\nAttributes:\n traffic_generator: The configura= tion 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 n= ode. 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 p= hysical 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, d= efaults 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 configurat= ion 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 funct= ional 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 t= raffic_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 side= s of the connection. This makes configuration slightly more verbose but gre= atly 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 i= t 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\nAttri= butes:\n node_name: The SUT node to use in this test run.\n vdevs: Th= e names of virtual devices to test.", > + "properties": { > + "vdevs": { > + "items": { > + "type": "string" > }, > - "traffic_generator": { > - "oneOf": [ > - { > - "type": "object", > - "description": "Scapy traffic generator. Used for functi= onal 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 us= ed 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 s= ingle test suite to be executed. It can be represented and validated as a\n= string type in the form of: ``TEST_SUITE [TEST_CASE, ...]``, in the configu= ration file.\n\nAttributes:\n test_suite: The name of the test suite mod= ule without the starting ``TestSuite_``.\n test_cases: The names of test= cases from this test suite to execute.\n If empty, all test cases w= ill 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 =3D os.path.dirname(os.path.realpath(__file__)) > +RELATIVE_PATH_TO_SCHEMA =3D "framework/config/conf_yaml_schema.json" > + > + > +class GenerateSchemaWithDialect(GenerateJsonSchema): > + """Custom schema generator which adds the schema dialect.""" > + > + def generate(self, schema, mode=3D"validation"): > + """Generate JSON schema.""" > + json_schema =3D super().generate(schema, mode=3Dmode) > + json_schema["$schema"] =3D self.schema_dialect > + return json_schema > + > + > +try: > + path =3D os.path.join(DTS_DIR, RELATIVE_PATH_TO_SCHEMA) > + > + with open(path, "w") as schema_file: > + schema_dict =3D ConfigurationType.json_schema(schema_generator= =3DGenerateSchemaWithDialect) > + schema_json =3D json.dumps(schema_dict, indent=3D2) > + schema_file.write(schema_json) > + > + print("Schema generated successfully!") > +except Exception as e: > + raise Exception("failed to generate schema") from e > -- > 2.34.1 >