译者 | 李睿
审校 | 孙淑娟
YAML (“YAML Ain't Markup Language”)配置语言是许多现代应用程序的核心,包括Kubernetes、Ansible、CircleCI和Salt。YAML提供了许多优势,例如可读性、灵活性以及处理JSON文件的能力。但是对于没有经验或粗心的人来说,YAML也是一种陷阱或是陷阱的来源。
YAML行为的许多方面都考虑到了暂时的便利,但其代价是以后会出现意想不到的曲折或麻烦。即使是具有丰富组装或部署YAML经验的人也可能会被这些问题所困扰,这些问题通常以看似无害的行为的幌子而浮出水面。
可以采取以下七个步骤来防范YAML中最棘手的问题。
1.如有疑问,请引用字符串
编写YAML时可以采用的最强大的防御实践:引用所有应为字符串的内容。
YAML最著名的怪癖之一是,可以编写字符串而无需引用:
- movie:
title: Blade Runner
year: 1982
在这一示例中,键movie、title和year将被解释为字符串,值Blade Runner也将被解释为字符串。值1982将被解析为数字。
但是这里会发生什么?
- movie:
title: 1979
year: 2016
没错,电影片名将被解释为一个数字。这甚至还不是可能发生的最糟糕的事情:
- movie:
title: No
year: 2012
这个标题被解释为布尔值的几率是多少?
如果想绝对确保键和值将被解释为字符串,并防止任何潜在的歧义(很多歧义可能会潜入YAML),请引用字符串:
- "movie":
"title": "Blade Runner"
"year": 1982
如果由于某种原因无法引用字符串,则可以使用速记前缀来指示类型。这些使YAML比引用的字符串读起来更嘈杂,但它们与引用一样明确:
movie: !!str Blade Runner
2.当心多行字符串
YAML有多种方式来表示多行字符串,具体取决于这些字符串的格式。例如,当前缀为“>”时,未加引号的字符串可以简单地跨多行断开:
long string: >
This is a long string
that spans multiple lines.
需要注意的是,使用>会自动在字符串末尾附加一个\n。如果不想要尾随的新行,使用>-而不是>。
如果使用带引号的字符串,则需要在每个换行符前加上反斜杠:
long string: "This is a long string \
that spans multiple lines."
需要注意的是,换行符后的任何空格都被解释为YAML格式,而不是字符串的一部分。这就是上例中在反斜杠之前插入空格的原因。
3.小心布尔值
正如上面所暗示的,YAML的另一个大问题之一是布尔值。在YAML中有很多方法可以指定布尔值,因此很容易将预期的字符串解释为布尔值。
一个臭名昭著的例子是两位数的国家代码问题。如果你所在的国家/地区是美国或英国,则是YES。如果所在的国家是挪威,其国家代码是NO,则它不再是一个字符串,而是一个计算结果为false的布尔值!
只要有可能,特意使用布尔值和可能被误解为布尔值的较短字符串。YAML的布尔值速记前缀是!!bool。
4.注意多种形式的八进制
多种形式的八进制是一个不为人知的问题,但它可能很麻烦。YAML 1.1对八进制数使用了与YAML 1.2不同的符号。在YAML 1.1中,八进制数看起来像0777。在YAML1.2中,相同的八进制数变成0o777。这样就不那么模棱两可了。
Kubernetes是YAML的最大用户之一,它使用YAML1.1。如果将YAML与使用规范1.2版的其他应用程序一起使用,特别注意不要使用错误的八进制表示法。由于如今八进制通常仅用于文件权限,因此与其他YAML陷阱相比,这是一个极端情况。尽管如此,如果不小心,YAML八进制可能会带来麻烦。
5.小心可执行的YAML
可执行YAML?是的,有许多YAML库,例如Python的PyYAML,在反序列化YAML时允许执行任意命令。令人惊讶的是,这不是一个bug,而是YAML设计允许的功能。
在PyYAML的情况下,反序列化的默认行为最终被更改为只支持不允许这种事情的安全YAML子集。原始行为可以进行人工恢复,但如果可以,应该避免使用这一功能,如果尚未禁用,则应默认禁用这一功能。
6.序列化和反序列化时要注意不一致
YAML的另一个潜在问题是, 跨不同编程语言的不同YAML处理库有时会产生不同的结果。
需要考虑的是:如果有一个包含表示为true和false的布尔值的YAML文件,并且使用一个不同的库将其重新序列化为YAML,该库表示布尔值为y和n或on和off,可能会得到意想不到的结果。即使代码在功能上保持不变,它也可能看起来完全不同。
7.不要使用YAML
避免YAML问题的通用方法是什么?不要使用它。或者至少不要直接使用它。
如果必须作为配置过程的一部分编写YAML,则更安全的做法是使用JSON或原生代码(例如Python字典)编写代码,然后将其序列化为YAML。可以更好地控制对象的类型,并且可以更自如地使用已经使用过的语言。
如果做不到这一点,可以使用yamllint之类的linter来检查常见的YAML问题。例如,可以禁止像YES或off这样的真值,以支持简单的true和false,或者强制字符串引用。
原文链接:https://www.infoworld.com/article/3669238/7-ugly-yaml-gotchas-to-avoid-and-how-to-avoid-them.html