使用 jsonschema 验证值组合

Validating value combinations with jsonschema

我正在使用 jsonschema 来验证配置文件。 目前我 运行 无法验证嵌套属性的值组合。

我最初实现了 if/then/else,但在几次通过后没有看到预期的行为。 对开关、依赖项和最后使用蕴涵也进行了同样的操作。

这是我的架构:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "account_group": {
      "type": "string"
    },
    "region": {
      "type": "string",
      "pattern": "^(us(-gov)?|ap|ca|cn|eu|sa)-(central|(north|south)?(east|west)?)-\d$"
    },
    "appid": {
      "type": "string"
    },
    "services": {
      "type": "object",
      "minProperties": 1,
      "patternProperties": {
        "^[A-Za-z_]*$": {
          "type": "object",
          "properties": {
            "source": {
              "type": "string"
            },
            "port": {
              "type": "number"
            },
            "cpu": {
              "type": "number",
              "enum": [256, 512, 1024, 2048, 4096]
            },
            "memory": {
              "type": "number",
              "enum": [0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
                22, 23, 24, 25, 26, 27, 28, 29, 30]
            }
          },
          "required": [
            "source",
            "port",
            "cpu",
            "memory"
          ],
        }
      },
      "additionalProperties": false
    },
    "stages": {
      "type": "object",
      "minProperties": 1
    },
    "workingDirectory": {
      "type": "string"
    }
  },
  "required": [
    "name",
    "account_group",
    "appid",
    "services"
  ]
}

注意:我删除了最新的 allOf 块以避免出现我已经测试过的损坏代码

我要完成的是验证正在解析的配置文件中 cpu/memory 值的正确组合并与模式进行比较。

组合是:

256/[0.5, 1, 2]
512/[1-4]
1024/[2-8]
2048/[2-16]
4096/[2-30]

有人可以建议适当的架构设计来验证这些组合吗?

本质上,如果 cpu 为 256,并且内存值不是 0.5、1、2,我需要验证失败 - 如果 cpu 为 512,并且内存值是任何值,则验证失败但是 1 - 4 等等

我已经得到了最接近的 using implication,但是我已经看到许多使用依赖关系的组合,这对我来说进一步混淆了水域。我个人认为 if/then/else 是最合乎逻辑的方法,但它没有产生预期的行为。

if/then 是最好的选择。蕴涵模式也有效,但 if/then 更好用。一般策略是为每个条件创建一个定义,然后使用 allOf 将它们组合起来。您当然可以将条件内联而不是使用 definitions,但这种方式读起来更好,使维护更容易。我做了前两个来说明。您可以从那里推断。

{
  "type": "object",
  "properties": {
    "source": { "type": "string" },
    "port": { "type": "number" },
    "cpu": { "enum": [256, 512, 1024, 2048, 4096] },
    "memory": { "enum": [0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
                         12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
                         22, 23, 24, 25, 26, 27, 28, 29, 30] }
  },
  "required": ["source", "port", "cpu", "memory"],
  "allOf": [
    { "$ref": "#/definitions/if-cpu-256-then-memory-0.5-1-2" },
    { "$ref": "#/definitions/if-cpu-512-then-memory-1-4" }
  ],
  "definitions": {
    "if-cpu-256-then-memory-0.5-1-2": {
      "if": {
        "properties": {
          "cpu": { "const": 256 }
        },
        "required": ["cpu"]
      },
      "then": {
        "properties": {
          "memory": { "enum": [0.5, 1, 2] }
        }
      }
    },
    "if-cpu-512-then-memory-1-4": {
      "if": {
        "properties": {
          "cpu": { "const": 512 }
        },
        "required": ["cpu"]
      },
      "then": {
        "properties": {
          "memory": { "minimum": 1, "maximum": 4 }
        }
      }
    }
  }
}