入门
使用 JSON 模式对文件系统建模
在本循序渐进的指南中,您将学习如何设计一个 JSON 模式来反映 /etc/fstab
文件的结构。
本指南分为以下几节:
简介
并非所有 fstab 文件的约束都可以单独使用 JSON 模式进行建模;然而,它可以很好地表示其中很大一部分,并且该练习有助于演示约束的工作原理。提供的示例用于说明 JSON 模式概念,而不是 fstab 文件的实际工作模式。
此示例显示了文件系统挂载点的 JSON 模式表示,如 /etc/fstab
文件中所示。
fstab 文件中的条目可以有多种不同形式;这是一个示例
数据
{ "/": { "storage": { "type": "disk", "device": "/dev/sda1" }, "fstype": "btrfs", "readonly": true }, "/var": { "storage": { "type": "disk", "label": "8f3ba6f4-5c70-46ec-83af-0d5434953e5f" }, "fstype": "ext4", "options": [ "nosuid" ] }, "/tmp": { "storage": { "type": "tmpfs", "sizeInMB": 64 } }, "/var/www": { "storage": { "type": "nfs", "server": "my.nfs.server", "remotePath": "/exports/mypath" } }}
创建 fstab
模式
我们将从表达以下约束的基本 JSON 模式开始
- 条目列表是一个 JSON 对象;
- 此对象的成员名称(或属性名称)必须都是有效的绝对路径;
- 必须有一个根文件系统的条目(即
/
)。
从上到下构建我们的 JSON 模式
$id
关键字。$schema
关键字。type
验证关键字。required
验证关键字。properties
验证关键字。/
键现在为空;我们稍后会填写它。
patternProperties
验证关键字。- 这通过正则表达式匹配其他属性名称。注意:它不匹配
/
。 ^(/[^/]+)+$
键现在为空;我们稍后会填写它。
- 这通过正则表达式匹配其他属性名称。注意:它不匹配
additionalProperties
验证关键字。- 这里的值是
false
,以将对象属性约束为/
或匹配正则表达式。
- 这里的值是
您会注意到正则表达式是显式锚定的(使用 ^
和 $
):在 JSON 模式中,正则表达式(在 patternProperties
和 pattern
中)默认情况下不锚定。
模式
{ "$id": "https://example.com/fstab", "$schema": "https://json-schema.fullstack.org.cn/draft/2020-12/schema", "type": "object", "required": [ "/" ], "properties": { "/": {} }, "patternProperties": { "^(/[^/]+)+$": {} }, "additionalProperties": false}
启动 entry
模式
我们将从 JSON 模式的概要开始,该模式将新概念添加到我们已经演示的内容中。
我们在之前的练习中看到了这些关键字:$id
、$schema
、type
、required
和 properties
。
我们添加了
description
注解关键字。oneOf
关键字。$ref
关键字。- 在这种情况下,所有使用的引用都是使用相对片段 URI(
#/...
)在模式本地的。
- 在这种情况下,所有使用的引用都是使用相对片段 URI(
$defs
关键字。- 包括几个我们稍后将定义的键名。
模式
{ "$id": "https://example.com/entry-schema", "$schema": "https://json-schema.fullstack.org.cn/draft/2020-12/schema", "description": "JSON Schema for an fstab entry", "type": "object", "required": [ "storage" ], "properties": { "storage": { "type": "object", "oneOf": [ { "$ref": "#/$defs/diskDevice" }, { "$ref": "#/$defs/diskUUID" }, { "$ref": "#/$defs/nfs" }, { "$ref": "#/$defs/tmpfs" } ] } }, "$defs": { "diskDevice": {}, "diskUUID": {}, "nfs": {}, "tmpfs": {} }}
约束条目
现在让我们扩展这个框架,为某些属性添加约束。
- 我们的
fstype
键使用enum
验证关键字。 - 我们的
options
键使用以下内容type
验证关键字(见上文)。minItems
验证关键字。items
验证关键字。uniqueItems
验证关键字。- 这些一起表示:
options
必须是一个数组,其中的项必须是字符串,必须至少有一个项,并且所有项都应该是唯一的。
- 我们有一个
readonly
键。
添加了这些约束后,模式现在看起来像这样
模式
{ "$id": "https://example.com/entry-schema", "$schema": "https://json-schema.fullstack.org.cn/draft/2020-12/schema", "description": "JSON Schema for an fstab entry", "type": "object", "required": [ "storage" ], "properties": { "storage": { "type": "object", "oneOf": [ { "$ref": "#/$defs/diskDevice" }, { "$ref": "#/$defs/diskUUID" }, { "$ref": "#/$defs/nfs" }, { "$ref": "#/$defs/tmpfs" } ] }, "fstype": { "enum": [ "ext3", "ext4", "btrfs" ] }, "options": { "type": "array", "minItems": 1, "items": { "type": "string" }, "uniqueItems": true }, "readonly": { "type": "boolean" } }, "$defs": { "diskDevice": {}, "diskUUID": {}, "nfs": {}, "tmpfs": {} }}
diskDevice
定义
这里引入了一个新的关键字
pattern
验证关键字指出device
键必须是以 _/dev_ 开头的绝对路径。
数据
{ "diskDevice": { "properties": { "type": { "enum": [ "disk" ] }, "device": { "type": "string", "pattern": "^/dev/[^/]+(/[^/]+)*$" } }, "required": [ "type", "device" ], "additionalProperties": false }}
diskUUID
定义
这里没有引入新的关键字。
我们确实有一个新键:label
,并且 pattern
验证关键字声明它必须是有效的 UUID。
数据
{ "diskUUID": { "properties": { "type": { "enum": [ "disk" ] }, "label": { "type": "string", "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" } }, "required": [ "type", "label" ], "additionalProperties": false }}
nfs
定义
我们找到了另一个新关键字
format
注解和断言关键字。
数据
{ "nfs": { "properties": { "type": { "enum": [ "nfs" ] }, "remotePath": { "type": "string", "pattern": "^(/[^/]+)+$" }, "server": { "type": "string", "oneOf": [ { "format": "hostname" }, { "format": "ipv4" }, { "format": "ipv6" } ] } }, "required": [ "type", "server", "remotePath" ], "additionalProperties": false }}
tmpfs
定义
我们的最后一个定义引入了两个新的关键字
minimum
验证关键字。maximum
验证关键字。- 这两个关键字共同要求大小在 16 到 512 之间(含)。
数据
{ "tmpfs": { "properties": { "type": { "enum": [ "tmpfs" ] }, "sizeInMB": { "type": "integer", "minimum": 16, "maximum": 512 } }, "required": [ "type", "sizeInMB" ], "additionalProperties": false }}
完整的条目模式
最终的 schema 相当大
模式
{ "$id": "https://example.com/entry-schema", "$schema": "https://json-schema.fullstack.org.cn/draft/2020-12/schema", "description": "JSON Schema for an fstab entry", "type": "object", "required": [ "storage" ], "properties": { "storage": { "type": "object", "oneOf": [ { "$ref": "#/$defs/diskDevice" }, { "$ref": "#/$defs/diskUUID" }, { "$ref": "#/$defs/nfs" }, { "$ref": "#/$defs/tmpfs" } ] }, "fstype": { "enum": [ "ext3", "ext4", "btrfs" ] }, "options": { "type": "array", "minItems": 1, "items": { "type": "string" }, "uniqueItems": true }, "readonly": { "type": "boolean" } }, "$defs": { "diskDevice": { "properties": { "type": { "enum": [ "disk" ] }, "device": { "type": "string", "pattern": "^/dev/[^/]+(/[^/]+)*$" } }, "required": [ "type", "device" ], "additionalProperties": false }, "diskUUID": { "properties": { "type": { "enum": [ "disk" ] }, "label": { "type": "string", "pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" } }, "required": [ "type", "label" ], "additionalProperties": false }, "nfs": { "properties": { "type": { "enum": [ "nfs" ] }, "remotePath": { "type": "string", "pattern": "^(/[^/]+)+$" }, "server": { "type": "string", "oneOf": [ { "format": "hostname" }, { "format": "ipv4" }, { "format": "ipv6" } ] } }, "required": [ "type", "server", "remotePath" ], "additionalProperties": false }, "tmpfs": { "properties": { "type": { "enum": [ "tmpfs" ] }, "sizeInMB": { "type": "integer", "minimum": 16, "maximum": 512 } }, "required": [ "type", "sizeInMB" ], "additionalProperties": false } }}
在 fstab
模式中引用 entry
模式
我们兜了一圈,使用 $ref
关键字将我们的入口 schema 添加到练习开始时留空的键中
/
键。^(/[^/]+)+$
键。
模式
{ "$id": "https://example.com/fstab", "$schema": "https://json-schema.fullstack.org.cn/draft/2020-12/schema", "type": "object", "required": [ "/" ], "properties": { "/": { "$ref": "https://example.com/entry-schema" } }, "patternProperties": { "^(/[^/]+)+$": { "$ref": "https://example.com/entry-schema" } }, "additionalProperties": false}