如何使用dhall验证配置的内部一致性?

时间:2019-12-03 11:54:56

标签: dhall

我将以一个激动人心的配置示例开始,该配置几乎代表一个特使代理配置:)


virtual_hosts:
- name: webxp-api_http
  domains: ["*"]
  routes:
  - match: { prefix: "/static/v5.0" }
    route: { cluster: bodhi_static }
  - match: { prefix: "/"}
    route: { cluster: bodhi-web }

  clusters:
  - name: bodhi_web
  - name: bodhi_static

规则是,必须定义名称clusters列表,还必须定义要在配置的route部分中使用的列表。如果仔细观察,该配置将无法加载,因为bodhi_web不是bodhi-web。我将如何在Dhall中对其进行编码?

一方面,我可以将clusters作为一个let绑定的列表,这会有所帮助,但是nothig强迫我使用绑定,实际上我想将clusters视为cluster:字段的总和类型?依赖类型能否在这里为我提供帮助(即,我记得在purescript中做过类似的事情,对依赖类型编程的能力有限)

还是我应该只创建一个构造函数/验证器函数并滥用assert来验证它?

还是我不应该? :)

2 个答案:

答案 0 :(得分:0)

我将通过编写一个实用的函数来实现此目的,该函数会生成按构造正确的配置。

以您的示例为例,如果我们要确保clusters字段下面的列表始终与路由列表匹配,则可以从clusters字段派生routes字段:< / p>

let Prelude = https://prelude.dhall-lang.org/package.dhall

let Route = { match : { prefix : Text }, route : { cluster : Text } }

let toVirtualHosts =
          \(args : { name : Text, domains : List Text, routes : List Route })
      ->  { virtual_hosts =
                  args
              //  { clusters =
                      Prelude.List.map
                        Route
                        Text
                        (\(r : Route) -> r.route.cluster)
                        args.routes
                  }
          }

in  toVirtualHosts
      { name = "webxp-api_http"
      , domains = [ "*" ]
      , routes =
          [ { match = { prefix = "/static/v5.0" }
            , route = { cluster = "bodhi_static" }
            }
          , { match = { prefix = "/" }
            , route = { cluster = "bodhi_web" }
            }
          ]
      }
$ dhall-to-yaml --file ./example.dhall
virtual_hosts:
  clusters:
  - bodhi_static
  - bodhi_web
  domains:
  - *
  name: webxp-api_http
  routes:
  - match:
      prefix: /static/v5.0
    route:
      cluster: bodhi_static
  - match:
      prefix: /
    route:
      cluster: bodhi_web

答案 1 :(得分:0)

我的替代尝试在很大程度上依赖于以下事实:空替代将最终转换为yaml时成为文本,即:{cluster = <static | web>.static}被解释为cluster: static

这意味着,我可以:

let Clusters = < bodhi_static | bodhi_web >

let Route =
      { Type = { match : { prefix : Text }, cluster : Clusters }
      , default = {=}
      }

let Cluster = { Type = { name : Clusters }, default = {=} }

in  { matches =
        [ Route::{ match = { prefix = "/" }, cluster = Clusters.bodhi_web }
        , Route::{
          , match = { prefix = "/static" }
          , cluster = Clusters.bodhi_static
          }
        ]
    , clusters =
        [ Cluster::{ name = Clusters.bodhi_static }
        , Cluster::{ name = Clusters.bodhi_web }
        ]
    }

更具重复性,但我更简单吗?