CUE语言基础入门:CUE是一门为配置而生的语言

news/2024/12/5 13:10:25/

基础入门

从这一部分开始,我们会介绍 KubeVela 是如何基于 CUE 来实现抽象和扩展的。本节将主要介绍一些 CUE 的基础知识,如果你对 KubeVela 的核心概念还不了解也没有关系,对于那些想要快速了解 CUE 并做一些实践的读者,本节也同样适用。

概述

KubeVela 将 CUE 作为应用交付核心依赖和扩展方式的原因如下::

  • CUE 本身就是为大规模配置而设计。 CUE 能够感知非常复杂的配置文件,并且能够安全地更改可修改配置中成千上万个对象的值。这非常符合 KubeVela 的目标,即以可编程的方式,去定义和交付生产级别的应用程序。
  • CUE 支持一流的代码生成和自动化。 CUE 原生支持与现有工具以及工作流进行集成,反观其他工具则需要自定义复杂的方案才能实现。例如,需要手动使用 Go 代码生成 OpenAPI 模式。KubeVela 也是依赖 CUE 该特性进行构建开发工具和 GUI 界面的。
  • CUE 与 Go 完美集成。 KubeVela 像 Kubernetes 系统中的大多数项目一样使用 GO 进行开发。CUE 已经在 Go 中实现并提供了丰富的 API。KubeVela 以 CUE 为核心实现 Kubernetes 控制器。借助 CUE,KubeVela 可以轻松处理数据约束问题。

更多细节请查看 The Configuration Complexity Curse 以及 The Logic of CUE 两篇文章。

前提

请确保你的环境中已经安装如下命令行:

  • cue v0.2.2 目前 KubeVela 暂时只支持 CUE v0.2.2 版本,将在后续迭代中升级支持新的 CUE 版本。
  • vela >= v1.1.0。

学习 CUE 命令行

CUE 是 JSON 的超集, 我们可以像使用 JSON 一样使用 CUE,并具备以下特性:

  • C 语言风格的注释
  • 字段名称可以用双引号括起来,注意字段名称中不可以带特殊字符
  • 可选字段末尾是否有逗号
  • 允许数组中最后一个元素末尾带逗号
  • 外大括号可选

请先复制以下信息,保存为一个 first.cue 文件:

a: 1.5
a: float
b: 1
b: int
d: [1, 2, 3]
g: {h: "abc"
}
e: string

接下来,我们以上面这个文件为例子,来学习 CUE 命令行的相关指令:

  • 如何格式化 CUE 文件。(如果你使用 Goland 或者类似 JetBrains IDE, 可以参考该文章配置自动格式化插件 使用 Goland 设置 cuelang 的自动格式化。)

    该命令不仅可以格式化 CUE 文件,还能提示错误的模型,相当好用的命令。

    cue fmt first.cue
    
  • 如何校验模型。除了 cue fmt,你还可以使用 cue vet 来校验模型。

    $ cue vet first.cue
    some instances are incomplete; use the -c flag to show errors or suppress this message$ cue vet first.cue -c
    e: incomplete value string
    

    提示我们:这个文件里的 e 这个变量,有数据类型 string 但并没有赋值。

  • 如何计算/渲染结果。 cue eval 可以计算 CUE 文件并且渲染出最终结果。 我们看到最终结果中并不包含 a: floatb: int,这是因为这两个变量已经被计算填充。 其中 e: string 没有被明确的赋值, 故保持不变.

    $ cue eval first.cue
    a: 1.5
    b: 1
    d: [1, 2, 3]
    g: {
    h: "abc"
    }
    e: string
    
  • 如何指定渲染的结果。例如,我们仅想知道文件中 b 的渲染结果,则可以使用该参数 -e

    $ cue eval -e b first.cue
    1
    
  • 如何导出渲染结果。 cue export 可以导出最终渲染结果。如果一些变量没有被定义执行该命令将会报错。

    $ cue export first.cue
    e: incomplete value string  
    

    我们更新一下 first.cue 文件,给 e 赋值:

    a: 1.5
    a: float
    b: 1
    b: int
    d: [1, 2, 3]
    g: {h: "abc"
    }
    e: string
    e: "abc"
    

    然后,该命令就可以正常工作。默认情况下, 渲染结果会被格式化为 JSON 格式。

    $ cue export first.cue
    {"a": 1.5,"b": 1,"d": [1,2,3],"g": {"h": "abc"},"e": "abc"
    }
    
  • 如何导出 YAML 格式的渲染结果。

    $ cue export first.cue --out yaml
    a: 1.5
    b: 1
    d:
    - 1
    - 2
    - 3
    g:h: abc
    e: abc
    
  • 如何导出指定变量的结果。

    $ cue export -e g first.cue
    {"h": "abc"
    }
    

以上, 你已经学习完所有常用的 CUE 命令行指令。

学习 CUE 语言

在熟悉完常用 CUE 命令行指令后,我们来进一步学习 CUE 语言。

先了解 CUE 的数据类型。以下是它的基础数据类型:

// float
a: 1.5// int
b: 1// string
c: "blahblahblah"// array
d: [1, 2, 3, 1, 2, 3, 1, 2, 3]// bool
e: true// struct
f: {a: 1.5b: 1d: [1, 2, 3, 1, 2, 3, 1, 2, 3]g: {h: "abc"}
}// null
j: null

如何自定义 CUE 类型?使用 # 符号来指定一些表示 CUE 类型的变量。

#abc: string

我们将上述内容保存到 second.cue 文件。 执行 cue export 不会报 #abc 是一个类型不完整的值。

$ cue export second.cue
{}

你还可以定义更复杂的自定义结构,比如:

#abc: {x: inty: stringz: {a: floatb: bool}
}

自定义结构在 KubeVela 中被广泛用于模块定义(X-Definitions)和进行验证。

定义一个 CUE 模板

下面,我们开始尝试利用刚刚学习到的知识,来定义 CUE 模版。

  1. 定义结构体变量 parameter.
parameter: {name: stringimage: string
}

保存上述变量到文件 deployment.cue.

  1. 定义更复杂的结构变量 template 同时引用变量 parameter.
template: {apiVersion: "apps/v1"kind:       "Deployment"spec: {selector: matchLabels: {"app.oam.dev/component": parameter.name}template: {metadata: labels: {"app.oam.dev/component": parameter.name}spec: {containers: [{name:  parameter.nameimage: parameter.image}]}}}
}

熟悉 Kubernetes 的你可能已经知道,这是 Kubernetes Deployment 的模板。 parameter 为模版的参数部分。

添加上述内容到文件 deployment.cue.

  1. 随后, 我们通过更新以下内容来完成变量赋值:
parameter:{name: "mytest"image: "nginx:v1"
}
  1. 最后, 导出渲染结果为 YAML 格式:
$ cue export deployment.cue -e template --out yamlapiVersion: apps/v1
kind: Deployment
spec:selector:matchLabels:app.oam.dev/component: mytesttemplate:metadata:labels:app.oam.dev/component: mytestspec:containers:- name: mytestimage: nginx:v1

以上,你就得到了一个 Kubernetes Deployment 类型的模板。

CUE 的更多用法

  • 设计开放的结构体和数组。如果在数组或者结构体中使用 ...,则说明该对象为开放的。

    • 数组对象 [...string] ,说明该对象可以容纳多个字符串元素。 如果不添加 ..., 该对象 [string] 说明数组只能容纳一个类型为 string 的元素。

    • 如下所示的结构体说明可以包含未知字段。

      {abc: string   ...
      }
      
  • 使用运算符 | 来表示两种类型的值。如下所示,变量 a 表示类型可以是字符串或者整数类型。

a: string | int
  • 使用符号 * 定义变量的默认值。通常它与符号 | 配合使用, 代表某种类型的默认值。如下所示,变量 a 类型为 int,默认值为 1
a: *1 | int
  • 让一些变量可被选填。 某些情况下,一些变量不一定被使用,这些变量就是可选变量,我们可以使用 ?: 定义此类变量。 如下所示, a 是可选变量, 自定义 #my 对象中 xz 为可选变量, 而 y 为必填字段。
a ?: int#my: {
x ?: string
y : int
z ?:float
}

选填变量可以被跳过,这经常和条件判断逻辑一起使用。 具体来说,如果某些字段不存在,则 CUE 语法为 if _variable_!= _ | _ ,如下所示:

parameter: {name: stringimage: stringconfig?: [...#Config]
}
output: {...spec: {containers: [{name:  parameter.nameimage: parameter.imageif parameter.config != _|_ {config: parameter.config}}]}...
}
  • 使用运算符 & 来运算两个变量。
a: *1 | int
b: 3
c: a & b

保存上述内容到 third.cue 文件。

你可以使用 cue eval 来验证结果:

$ cue eval third.cue
a: 1
b: 3
c: 3
  • 需要执行条件判断。当你执行一些级联操作时,不同的值会影响不同的结果,条件判断就非常有用。 因此,你可以在模版中执行 if..else 的逻辑。
price: number
feel: *"good" | string
// Feel bad if price is too high
if price > 100 {feel: "bad"
}
price: 200

保存上述内容到 fourth.cue 文件。

你可以使用 cue eval 来验证结果:

$ cue eval fourth.cue
price: 200
feel:  "bad"

另一个示例是将布尔类型作为参数。

parameter: {name:   stringimage:  stringuseENV: bool
}
output: {...spec: {containers: [{name:  parameter.nameimage: parameter.imageif parameter.useENV == true {env: [{name: "my-env", value: "my-value"}]}}]}...
}
  • 使用 For 循环。 我们为了避免减少重复代码,常常使用 For 循环。

    • 映射遍历。

      parameter: {name:  stringimage: stringenv: [string]: string
      }
      output: {spec: {containers: [{name:  parameter.nameimage: parameter.imageenv: [for k, v in parameter.env {name:  kvalue: v},]}]}
      }
      
    • 类型遍历。

      #a: {"hello": "Barcelona""nihao": "Shanghai"
      }for k, v in #a {"\(k)": {nameLen: len(v)value:   v}
      }
      
    • 切片遍历。

      parameter: {name:  stringimage: stringenv: [...{name:string,value:string}]
      }
      output: {...spec: {containers: [{name:  parameter.nameimage: parameter.imageenv: [for _, v in parameter.env {name:  v.namevalue: v.value},]}]}
      }
      
      • 循环内使用条件判断
      parameter: [
      {name: "empty"
      }, {name: "xx1"
      },
      ]dataFrom: [ for _, v in parameter {
      if v.name != "empty" {name: v.name
      }
      }]
      

      结果是:

      cue eval ../blog/a.cue -e dataFrom
      [{}, {name: "xx1"
      }]
      
      • 将条件判断作为循环的条件
      parameter: [
      {name: "empty"
      }, {name: "xx1"
      },
      ]
      

    dataFrom: [ for _, v in parameter if v.name != “empty” { name: v.name }]

    结果是:
    

    cue eval …/blog/a.cue -e dataFrom [{ name: “xx1” }]

    
    

另外,可以使用 "\( _my-statement_ )" 进行字符串内部计算,比如上面类型循环示例中,获取值的长度等等操作。

导入 CUE 内部包

CUE 有很多 internal packages 可以被 KubeVela 使用,这样可以满足更多的开发需求。

比如,使用 strings.Join 方法将字符串数组拼接成字符串。

import ("strings")parameter: {outputs: [{ip: "1.1.1.1", hostname: "xxx.com"}, {ip: "2.2.2.2", hostname: "yyy.com"}]
}
output: {spec: {if len(parameter.outputs) > 0 {_x: [ for _, v in parameter.outputs {"\(v.ip) \(v.hostname)"}]message: "Visiting URL: " + strings.Join(_x, "")}}
}

至此,你已经学会了基础的 CUE 知识,如果你还想了解更多的 CUE 实践细节,可以参考其官方文档。

在本部分接下来的章节里,我们会开始介绍 KubeVela 如何使用 CUE 像胶水一样衔接不同的资源,请确保你对 KubeVela 的核心概念有所了解。

参考链接:

http://static.kubevela.net/zh/docs/platform-engineers/cue/basic


http://www.ppmy.cn/news/728662.html

相关文章

CUE是何方神圣?

导读 本片文章主要介绍 CUE 的基本概念,CUE 是什么以及可以做些什么,通过一些 demo 演示了基本的用法,适合小白入门阅读。 本文首发于 https://russellgao.cn/cue-intro/ ,转载请保留出处。 什么是CUE C(Configure:配…

android auto凯迪拉克,凯迪拉克支持Apple CarPlay及Android Auto

苹果及安卓两大智能手机系统品牌,在数年前宣布将推出车载智能资讯系统后,由于开发时遭遇许多困难,推出时程屡屡后延,近期终于到了最后问世阶段,许多车厂也在近期公布导入计划。日前凯迪拉克宣布,2016年式车…

iso转cue mac_如何在Mac上将.bin和.cue转换为ISO

您有时偶尔会遇到磁盘映像的.bin和.cue文件或cue / bin提示表通常是在为旧机器下载旧Mac软件(甚至DOSWindowsLinux)时音频或视频光盘或者只是某些东西的磁盘映像因此Mac用户可能需要将该bin和cue文件转换为ISO文件以供在其他地方使用无论是用于虚拟机还是将ISO刻录到光盘 我们将…

bin和cue怎么合并_用foobar进行APE分割及合并,cue的制作

1.0.9.6以后的版本都不直接支持ape转换了 2.可以,基本上没有影响,不过我还是鼓励你用foobar2000外挂Monkeys audio的转换程序mac.exe。 去弄个Monkeys audio就可以了,然后抠出里面的mac.exe摔到foobar2000安装文件夹下面。 设置参数 编码器&a…

Cuesport理解

Cuesport理解 cuesport是一个简单的进程池,多用于数据库连接 调用方式 cuesport:start_link(?POOL_NAME, PoolSize, ChildMods, ChildMFA). 1.?POOL_NAME为进程池名称 2.PoolSize为进程池阈值 3.ChildMods为回调模块名称 4.ChildMFA为需添加到进程池的M:F:…

html5 显示多个cue,WordPress添加超酷html5音乐播放器Cue

文件引用、加载 下载之后解压可得cue-html5musicplayer文件夹, 打开它 你会看到functions.cue.php 和 cue文件夹 两个个东东。 1、将functions.cue.php里面的代码复制到你主题的functions.php里面,或者在functions.php中使用include ("functions.cu…

【cue语言系列学习】base64编解码

【cue语言系列学习】base64编解码 release author: ningan123 release time: 2022-08-14 在线运行 工具 三种不同的输出方式,输出的结果是不一样的 本地模拟 base64.cue [rootmaster base64]# cat base64.cue import "encoding/base64"t1: base64.E…

xmcd2cue 工具下载

转换 xmcd 歌曲列表到 cue 歌曲列表工具 特点!这个xmcd2cue是由大佬用Go语言于2019年重写的,天生支持 UTF8 编码,老的那个不支持。 别人的源代码仓库:https://github.com/jopadan/xmcd2cue 基于别人的源代码,我编译…