1
0

yaml_idiosyncrasies.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. .. _yaml-idiosyncrasies:
  2. ===================
  3. YAML Idiosyncrasies
  4. ===================
  5. One of Salt's strengths, the use of existing serialization systems for
  6. representing SLS data, can also backfire. `YAML`_ is a general purpose system
  7. and there are a number of things that would seem to make sense in an sls
  8. file that cause YAML issues. It is wise to be aware of these issues. While
  9. reports or running into them are generally rare they can still crop up at
  10. unexpected times.
  11. .. _`YAML`: https://yaml.org/spec/1.1/
  12. Spaces vs Tabs
  13. ==============
  14. `YAML uses spaces`_, period. Do not use tabs in your SLS files! If strange
  15. errors are coming up in rendering SLS files, make sure to check that
  16. no tabs have crept in! In Vim, after enabling search highlighting
  17. with: ``:set hlsearch``, you can check with the following key sequence in
  18. normal mode(you can hit `ESC` twice to be sure): ``/``, `Ctrl-v`, `Tab`, then
  19. hit `Enter`. Also, you can convert tabs to 2 spaces by these commands in Vim:
  20. ``:set tabstop=2 expandtab`` and then ``:retab``.
  21. .. _`YAML uses spaces`: https://yaml.org/spec/1.1/#id871998
  22. Indentation
  23. ===========
  24. The suggested syntax for YAML files is to use 2 spaces for indentation,
  25. but YAML will follow whatever indentation system that the individual file
  26. uses. Indentation of two spaces works very well for SLS files given the
  27. fact that the data is uniform and not deeply nested.
  28. .. _nested-dict-indentation:
  29. Nested Dictionaries
  30. -------------------
  31. When dictionaries are nested within other data structures (particularly lists),
  32. the indentation logic sometimes changes. Examples of where this might happen
  33. include ``context`` and ``default`` options from the :mod:`file.managed
  34. <salt.states.file>` state:
  35. .. code-block:: yaml
  36. /etc/http/conf/http.conf:
  37. file:
  38. - managed
  39. - source: salt://apache/http.conf
  40. - user: root
  41. - group: root
  42. - mode: 644
  43. - template: jinja
  44. - context:
  45. custom_var: "override"
  46. - defaults:
  47. custom_var: "default value"
  48. other_var: 123
  49. Notice that while the indentation is two spaces per level, for the values under
  50. the ``context`` and ``defaults`` options there is a four-space indent. If only
  51. two spaces are used to indent, then those keys will be considered part of the
  52. same dictionary that contains the ``context`` key, and so the data will not be
  53. loaded correctly. If using a double indent is not desirable, then a
  54. deeply-nested dict can be declared with curly braces:
  55. .. code-block:: yaml
  56. /etc/http/conf/http.conf:
  57. file:
  58. - managed
  59. - source: salt://apache/http.conf
  60. - user: root
  61. - group: root
  62. - mode: 644
  63. - template: jinja
  64. - context: {
  65. custom_var: "override" }
  66. - defaults: {
  67. custom_var: "default value",
  68. other_var: 123 }
  69. Here is a more concrete example of how YAML actually handles these
  70. indentations, using the Python interpreter on the command line:
  71. .. code-block:: python
  72. >>> import yaml
  73. >>> yaml.safe_load('''mystate:
  74. ... file.managed:
  75. ... - context:
  76. ... some: var''')
  77. {'mystate': {'file.managed': [{'context': {'some': 'var'}}]}}
  78. >>> yaml.safe_load('''mystate:
  79. ... file.managed:
  80. ... - context:
  81. ... some: var''')
  82. {'mystate': {'file.managed': [{'some': 'var', 'context': None}]}}
  83. Note that in the second example, ``some`` is added as another key in the same
  84. dictionary, whereas in the first example, it's the start of a new dictionary.
  85. That's the distinction. ``context`` is a common example because it is a keyword
  86. arg for many functions, and should contain a dictionary.
  87. Multi-line Strings
  88. ------------------
  89. Similarly, when a multi-line string is nested within a list item (such as when
  90. using the ``contents`` argument for a :py:func:`file.managed
  91. <salt.states.file.managed>` state), the indentation must be doubled. Take for
  92. example the following state:
  93. .. code-block:: yaml
  94. /tmp/foo.txt:
  95. file.managed:
  96. - contents: |
  97. foo
  98. bar
  99. baz
  100. This is invalid YAML, and will result in a rather cryptic error when you try to
  101. run the state:
  102. .. code-block:: text
  103. myminion:
  104. Data failed to compile:
  105. ----------
  106. Rendering SLS 'base:test' failed: could not find expected ':'; line 5
  107. ---
  108. /tmp/foo.txt:
  109. file.managed:
  110. - contents: |
  111. foo
  112. bar <======================
  113. baz
  114. ---
  115. The correct indentation would be as follows:
  116. .. code-block:: yaml
  117. /tmp/foo.txt:
  118. file.managed:
  119. - contents: |
  120. foo
  121. bar
  122. baz
  123. True/False, Yes/No, On/Off
  124. ==========================
  125. PyYAML will load these values as boolean ``True`` or ``False``. Un-capitalized
  126. versions will also be loaded as booleans (``true``, ``false``, ``yes``, ``no``,
  127. ``on``, and ``off``). This can be especially problematic when constructing
  128. Pillar data. Make sure that your Pillars which need to use the string versions
  129. of these values are enclosed in quotes. Pillars will be parsed twice by salt,
  130. so you'll need to wrap your values in multiple quotes, including double quotation
  131. marks (``" "``) and single quotation marks (``' '``). Note that spaces are included
  132. in the quotation type examples for clarity.
  133. Multiple quoting examples looks like this:
  134. .. code-block:: yaml
  135. - '"false"'
  136. - "'True'"
  137. - "'YES'"
  138. - '"No"'
  139. .. note::
  140. When using multiple quotes in this manner, they must be different. Using ``"" ""``
  141. or ``'' ''`` won't work in this case (spaces are included in examples for clarity).
  142. The '%' Sign
  143. ============
  144. The `%` symbol has a special meaning in YAML, it needs to be passed as a
  145. string literal:
  146. .. code-block:: yaml
  147. cheese:
  148. ssh_auth.present:
  149. - user: tbortels
  150. - source: salt://ssh_keys/chease.pub
  151. - config: '%h/.ssh/authorized_keys'
  152. Time Expressions
  153. ================
  154. PyYAML will load a time expression as the integer value of that, assuming
  155. ``HH:MM``. So for example, ``12:00`` is loaded by PyYAML as ``720``. An
  156. excellent explanation for why can be found here__.
  157. To keep time expressions like this from being loaded as integers, always quote
  158. them.
  159. .. note::
  160. When using a jinja ``load_yaml`` map, items must be quoted twice. For
  161. example:
  162. .. code-block:: jinja
  163. {% load_yaml as wsus_schedule %}
  164. FRI_10:
  165. time: '"23:00"'
  166. day: 6 - Every Friday
  167. SAT_10:
  168. time: '"06:00"'
  169. day: 7 - Every Saturday
  170. SAT_20:
  171. time: '"14:00"'
  172. day: 7 - Every Saturday
  173. SAT_30:
  174. time: '"22:00"'
  175. day: 7 - Every Saturday
  176. SUN_10:
  177. time: '"06:00"'
  178. day: 1 - Every Sunday
  179. {% endload %}
  180. .. __: https://stackoverflow.com/questions/23812676/pyyaml-parses-900-as-int/31007425#31007425
  181. YAML does not like "Double Short Decs"
  182. ======================================
  183. If I can find a way to make YAML accept "Double Short Decs" then I will, since
  184. I think that double short decs would be awesome. So what is a "Double Short
  185. Dec"? It is when you declare a multiple short decs in one ID. Here is a
  186. standard short dec, it works great:
  187. .. code-block:: yaml
  188. vim:
  189. pkg.installed
  190. The short dec means that there are no arguments to pass, so it is not required
  191. to add any arguments, and it can save space.
  192. YAML though, gets upset when declaring multiple short decs, for the record...
  193. THIS DOES NOT WORK:
  194. .. code-block:: yaml
  195. vim:
  196. pkg.installed
  197. user.present
  198. Similarly declaring a short dec in the same ID dec as a standard dec does not
  199. work either...
  200. ALSO DOES NOT WORK:
  201. .. code-block:: yaml
  202. fred:
  203. user.present
  204. ssh_auth.present:
  205. - name: AAAAB3NzaC...
  206. - user: fred
  207. - enc: ssh-dss
  208. - require:
  209. - user: fred
  210. The correct way is to define them like this:
  211. .. code-block:: yaml
  212. vim:
  213. pkg.installed: []
  214. user.present: []
  215. fred:
  216. user.present: []
  217. ssh_auth.present:
  218. - name: AAAAB3NzaC...
  219. - user: fred
  220. - enc: ssh-dss
  221. - require:
  222. - user: fred
  223. Alternatively, they can be defined the "old way", or with multiple
  224. "full decs":
  225. .. code-block:: yaml
  226. vim:
  227. pkg:
  228. - installed
  229. user:
  230. - present
  231. fred:
  232. user:
  233. - present
  234. ssh_auth:
  235. - present
  236. - name: AAAAB3NzaC...
  237. - user: fred
  238. - enc: ssh-dss
  239. - require:
  240. - user: fred
  241. .. _yaml_plain_ascii:
  242. YAML supports only plain ASCII
  243. ==============================
  244. According to YAML specification, only ASCII characters can be used.
  245. Within double-quotes, special characters may be represented with C-style
  246. escape sequences starting with a backslash ( \\ ).
  247. Examples:
  248. .. code-block:: yaml
  249. - micro: "\u00b5"
  250. - copyright: "\u00A9"
  251. - A: "\x41"
  252. - alpha: "\u0251"
  253. - Alef: "\u05d0"
  254. List of usable `Unicode characters`_ will help you to identify correct numbers.
  255. .. _`Unicode characters`: https://en.wikipedia.org/wiki/List_of_Unicode_characters
  256. Python can also be used to discover the Unicode number for a character:
  257. .. code-block:: python
  258. repr(u"Text with wrong characters i need to figure out")
  259. This shell command can find wrong characters in your SLS files:
  260. .. code-block:: bash
  261. find . -name '*.sls' -exec grep --color='auto' -P -n '[^\x00-\x7F]' \{} \;
  262. Alternatively you can toggle the `yaml_utf8` setting in your master configuration
  263. file. This is still an experimental setting but it should manage the right
  264. encoding conversion in salt after yaml states compilations.
  265. Underscores stripped in Integer Definitions
  266. ===========================================
  267. If a definition only includes numbers and underscores, it is parsed by YAML as
  268. an integer and all underscores are stripped. To ensure the object becomes a
  269. string, it should be surrounded by quotes. `More information here`_.
  270. .. _`More information here`: https://stackoverflow.com/questions/2723321/snakeyaml-how-to-disable-underscore-stripping-when-parsing
  271. Here's an example:
  272. .. code-block:: python
  273. >>> import yaml
  274. >>> yaml.safe_load('2013_05_10')
  275. 20130510
  276. >>> yaml.safe_load('"2013_05_10"')
  277. '2013_05_10'
  278. Automatic ``datetime`` conversion
  279. =================================
  280. If there is a value in a YAML file formatted ``2014-01-20 14:23:23`` or
  281. similar, YAML will automatically convert this to a Python ``datetime`` object.
  282. These objects are not msgpack serializable, and so may break core salt
  283. functionality. If values such as these are needed in a salt YAML file
  284. (specifically a configuration file), they should be formatted with surrounding
  285. strings to force YAML to serialize them as strings:
  286. .. code-block:: python
  287. >>> import yaml
  288. >>> yaml.safe_load('2014-01-20 14:23:23')
  289. datetime.datetime(2014, 1, 20, 14, 23, 23)
  290. >>> yaml.safe_load('"2014-01-20 14:23:23"')
  291. '2014-01-20 14:23:23'
  292. Additionally, numbers formatted like ``XXXX-XX-XX`` will also be converted (or
  293. YAML will attempt to convert them, and error out if it doesn't think the date
  294. is a real one). Thus, for example, if a minion were to have an ID of
  295. ``4017-16-20`` the minion would not start because YAML would complain that the
  296. date was out of range. The workaround is the same, surround the offending
  297. string with quotes:
  298. .. code-block:: python
  299. >>> import yaml
  300. >>> yaml.safe_load('4017-16-20')
  301. Traceback (most recent call last):
  302. File "<stdin>", line 1, in <module>
  303. File "/usr/local/lib/python2.7/site-packages/yaml/__init__.py", line 93, in safe_load
  304. return load(stream, SafeLoader)
  305. File "/usr/local/lib/python2.7/site-packages/yaml/__init__.py", line 71, in load
  306. return loader.get_single_data()
  307. File "/usr/local/lib/python2.7/site-packages/yaml/constructor.py", line 39, in get_single_data
  308. return self.construct_document(node)
  309. File "/usr/local/lib/python2.7/site-packages/yaml/constructor.py", line 43, in construct_document
  310. data = self.construct_object(node)
  311. File "/usr/local/lib/python2.7/site-packages/yaml/constructor.py", line 88, in construct_object
  312. data = constructor(self, node)
  313. File "/usr/local/lib/python2.7/site-packages/yaml/constructor.py", line 312, in construct_yaml_timestamp
  314. return datetime.date(year, month, day)
  315. ValueError: month must be in 1..12
  316. >>> yaml.safe_load('"4017-16-20"')
  317. '4017-16-20'
  318. Keys Limited to 1024 Characters
  319. ===============================
  320. Simple keys are limited by the `YAML Spec`_ to a single line, and cannot be
  321. longer that 1024 characters. PyYAML enforces these limitations (see here__),
  322. and therefore anything parsed as YAML in Salt is subject to them.
  323. .. _`YAML Spec`: https://yaml.org/spec/1.2/spec.html#id2792424
  324. .. __: https://github.com/yaml/pyyaml/blob/eb459f8/lib/yaml/scanner.py#L279-L293