模型定义
KCL 的核心场景是写配置和校验,因此 KCL 被设计之初的一个核心特性就是建模,对应到 KCL 的关键字 schema
,schema
可以被用于定义结构和约束,比如字段的类型,默认值,字段的范围和各种其他约束等内容。此外,使用 KCL schema 定义的结构可以反过来用于验证实现、验证输入(JSON、YAML 等结构化数据)或生成代码(生成多语言结构体、OpenAPI 等)。
定义结构和约束
比如我们有如下定义的 KCL 文件 (main.k)。在其中,我们使用 schema
关键字定义了三个模型 App
,Service
和 Volume
。并且 App
模型具有四个属性 domainType
, containerPort
, volumes
和 services
,其中
domainType
的类型为字符串字面值联合类型,与“枚举”类似,这表明domainType
的值只能取"Standard"
,"Customized"
和"Global"
中的一个containerPort
的类型为整数int
, 此外我们使用check
关键字定义了其取值范围 1 ~ 65535services
的类型为Service
列表类型,Service
,并且我们用?
标记了它是一个可选属性,这意味着我们可以不为其赋值。volumes
的类型为Volume
列表类型,并且我们用?
标记了它是一个可选属性,这意味着我们可以不为其赋值。
schema App:
domainType: "Standard" | "Customized" | "Global"
containerPort: int
services?: [Service] # `?` specifies a optional attribute
volumes?: [Volume] # `?` specifies a optional attribute
check:
1 <= containerPort <= 65535 # `containerPort` must be in range [1, 65535]
schema Service:
clusterIP: str
$type: str
check:
clusterIP == "None" if $type == "ClusterIP" # When `type` is "ClusterIP", `clusterIP` must be `"None"`
schema Volume:
container: str = "*" # The default value of `container` is "*"
mountPath: str
check:
mountPath not in ["/", "/boot", "/home", "dev", "/etc", "/root"] # `mountPath` must not be one of the list `["/", "/boot", "/home", "dev", "/etc", "/root"]`
app: App {
domainType = "Standard"
containerPort = 80
volumes = [
{
mountPath = "/tmp"
}
]
services = [
{
clusterIP = "None"
$type = "ClusterIP"
}
]
}
我们使用如下命令行可以获得 app
实例的 YAML 输出
$ kcl main.k
app:
domainType: Standard
containerPort: 80
volumes:
- container: '*'
mountPath: /tmp
services:
- clusterIP: None
type: ClusterIP
此外,我们还可以将 App
模型放入单独的 app_module.k 中,在需要时我们可以在 main.k 中使用 import
关键字进行模块化管理,比如下面的文件结构
.
├── app_module.k
└── main.k
其中 app_module.k 的内容为
schema App:
domainType: "Standard" | "Customized" | "Global"
containerPort: int
volumes: [Volume]
services: [Service]
check:
1 <= containerPort <= 65535
schema Service:
clusterIP: str
$type: str
check:
clusterIP == "None" if $type == "ClusterIP"
schema Volume:
container: str = "*" # The default value of `container` is "*"
mountPath: str
check:
mountPath not in ["/", "/boot", "/home", "dev", "/etc", "/root"]
main.k 的内容为
import .app_module # A relative path import
app: app_module.App {
domainType = "Standard"
containerPort = 80
volumes = [
{
mountPath = "/tmp"
}
]
services = [
{
clusterIP = "None"
$type = "ClusterIP"
}
]
}
我们使用如下命令行仍然可以获得 app
实例的 YAML 输出
$ kcl main.k
app:
domainType: Standard
containerPort: 80
volumes:
- container: '*'
mountPath: /tmp
services:
- clusterIP: None
type: ClusterIP