需要避免的七個(gè)YAML陷阱
譯文?譯者 | 李睿
審校 | 孫淑娟
YAML (“YAML Ain't Markup Language”)配置語言是許多現(xiàn)代應(yīng)用程序的核心,包括Kubernetes、Ansible、CircleCI和Salt。YAML提供了許多優(yōu)勢(shì),例如可讀性、靈活性以及處理JSON文件的能力。但是對(duì)于沒有經(jīng)驗(yàn)或粗心的人來說,YAML也是一種陷阱或是陷阱的來源。
YAML行為的許多方面都考慮到了暫時(shí)的便利,但其代價(jià)是以后會(huì)出現(xiàn)意想不到的曲折或麻煩。即使是具有豐富組裝或部署YAML經(jīng)驗(yàn)的人也可能會(huì)被這些問題所困擾,這些問題通常以看似無害的行為的幌子而浮出水面。
可以采取以下七個(gè)步驟來防范YAML中最棘手的問題。
1.如有疑問,請(qǐng)引用字符串?
編寫YAML時(shí)可以采用的最強(qiáng)大的防御實(shí)踐:引用所有應(yīng)為字符串的內(nèi)容。
YAML最著名的怪癖之一是,可以編寫字符串而無需引用:
- movie:
title: Blade Runner
year: 1982
在這一示例中,鍵movie、title和year將被解釋為字符串,值Blade Runner也將被解釋為字符串。值1982將被解析為數(shù)字。
但是這里會(huì)發(fā)生什么?
- movie:
title: 1979
year: 2016
沒錯(cuò),電影片名將被解釋為一個(gè)數(shù)字。這甚至還不是可能發(fā)生的最糟糕的事情:
- movie:
title: No
year: 2012
這個(gè)標(biāo)題被解釋為布爾值的幾率是多少?
如果想絕對(duì)確保鍵和值將被解釋為字符串,并防止任何潛在的歧義(很多歧義可能會(huì)潛入YAML),請(qǐng)引用字符串:
- "movie":
"title": "Blade Runner"
"year": 1982
如果由于某種原因無法引用字符串,則可以使用速記前綴來指示類型。這些使YAML比引用的字符串讀起來更嘈雜,但它們與引用一樣明確:
movie: !!str Blade Runner
2.當(dāng)心多行字符串
YAML有多種方式來表示多行字符串,具體取決于這些字符串的格式。例如,當(dāng)前綴為“>”時(shí),未加引號(hào)的字符串可以簡(jiǎn)單地跨多行斷開:
long string: >
This is a long string
that spans multiple lines.
需要注意的是,使用>會(huì)自動(dòng)在字符串末尾附加一個(gè)\n。如果不想要尾隨的新行,使用>-而不是>。
如果使用帶引號(hào)的字符串,則需要在每個(gè)換行符前加上反斜杠:
long string: "This is a long string \
that spans multiple lines."
需要注意的是,換行符后的任何空格都被解釋為YAML格式,而不是字符串的一部分。這就是上例中在反斜杠之前插入空格的原因。
3.小心布爾值
正如上面所暗示的,YAML的另一個(gè)大問題之一是布爾值。在YAML中有很多方法可以指定布爾值,因此很容易將預(yù)期的字符串解釋為布爾值。
一個(gè)臭名昭著的例子是兩位數(shù)的國(guó)家代碼問題。如果你所在的國(guó)家/地區(qū)是美國(guó)或英國(guó),則是YES。如果所在的國(guó)家是挪威,其國(guó)家代碼是NO,則它不再是一個(gè)字符串,而是一個(gè)計(jì)算結(jié)果為false的布爾值!
只要有可能,特意使用布爾值和可能被誤解為布爾值的較短字符串。YAML的布爾值速記前綴是!!bool。
4.注意多種形式的八進(jìn)制
多種形式的八進(jìn)制是一個(gè)不為人知的問題,但它可能很麻煩。YAML 1.1對(duì)八進(jìn)制數(shù)使用了與YAML 1.2不同的符號(hào)。在YAML 1.1中,八進(jìn)制數(shù)看起來像0777。在YAML1.2中,相同的八進(jìn)制數(shù)變成0o777。這樣就不那么模棱兩可了。
Kubernetes是YAML的最大用戶之一,它使用YAML1.1。如果將YAML與使用規(guī)范1.2版的其他應(yīng)用程序一起使用,特別注意不要使用錯(cuò)誤的八進(jìn)制表示法。由于如今八進(jìn)制通常僅用于文件權(quán)限,因此與其他YAML陷阱相比,這是一個(gè)極端情況。盡管如此,如果不小心,YAML八進(jìn)制可能會(huì)帶來麻煩。
5.小心可執(zhí)行的YAML
可執(zhí)行YAML?是的,有許多YAML庫(kù),例如Python的PyYAML,在反序列化YAML時(shí)允許執(zhí)行任意命令。令人驚訝的是,這不是一個(gè)bug,而是YAML設(shè)計(jì)允許的功能。
在PyYAML的情況下,反序列化的默認(rèn)行為最終被更改為只支持不允許這種事情的安全YAML子集。原始行為可以進(jìn)行人工恢復(fù),但如果可以,應(yīng)該避免使用這一功能,如果尚未禁用,則應(yīng)默認(rèn)禁用這一功能。
6.序列化和反序列化時(shí)要注意不一致
YAML的另一個(gè)潛在問題是, 跨不同編程語言的不同YAML處理庫(kù)有時(shí)會(huì)產(chǎn)生不同的結(jié)果。
需要考慮的是:如果有一個(gè)包含表示為true和false的布爾值的YAML文件,并且使用一個(gè)不同的庫(kù)將其重新序列化為YAML,該庫(kù)表示布爾值為y和n或on和off,可能會(huì)得到意想不到的結(jié)果。即使代碼在功能上保持不變,它也可能看起來完全不同。
7.不要使用YAML
避免YAML問題的通用方法是什么?不要使用它。或者至少不要直接使用它。
如果必須作為配置過程的一部分編寫YAML,則更安全的做法是使用JSON或原生代碼(例如Python字典)編寫代碼,然后將其序列化為YAML。可以更好地控制對(duì)象的類型,并且可以更自如地使用已經(jīng)使用過的語言。
如果做不到這一點(diǎn),可以使用yamllint之類的linter來檢查常見的YAML問題。例如,可以禁止像YES或off這樣的真值,以支持簡(jiǎn)單的true和false,或者強(qiáng)制字符串引用。
原文鏈接:https://www.infoworld.com/article/3669238/7-ugly-yaml-gotchas-to-avoid-and-how-to-avoid-them.html































