1
0

starting_states.rst 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. .. _starting-states:
  2. =========================
  3. How Do I Use Salt States?
  4. =========================
  5. Simplicity, Simplicity, Simplicity
  6. Many of the most powerful and useful engineering solutions are founded on
  7. simple principles. Salt States strive to do just that: K.I.S.S. (Keep It
  8. Stupidly Simple)
  9. The core of the Salt State system is the SLS, or **S**\ a\ **L**\ t
  10. **S**\ tate file. The SLS is a representation of the state in which
  11. a system should be in, and is set up to contain this data in a simple format.
  12. This is often called configuration management.
  13. .. note::
  14. This is just the beginning of using states, make sure to read up on pillar
  15. :ref:`Pillar <pillar-walk-through>` next.
  16. It is All Just Data
  17. ===================
  18. Before delving into the particulars, it will help to understand that the SLS
  19. file is just a data structure under the hood. While understanding that the SLS
  20. is just a data structure isn't critical for understanding and making use of
  21. Salt States, it should help bolster knowledge of where the real power is.
  22. SLS files are therefore, in reality, just dictionaries, lists, strings, and
  23. numbers. By using this approach Salt can be much more flexible. As one writes
  24. more state files, it becomes clearer exactly what is being written. The result
  25. is a system that is easy to understand, yet grows with the needs of the admin
  26. or developer.
  27. The Top File
  28. ============
  29. The example SLS files in the below sections can be assigned to hosts using a
  30. file called :strong:`top.sls`. This file is described in-depth :ref:`here
  31. <states-top>`.
  32. Default Data - YAML
  33. ===================
  34. By default Salt represents the SLS data in what is one of the simplest
  35. serialization formats available - `YAML`_.
  36. A typical SLS file will often look like this in YAML:
  37. .. note::
  38. These demos use some generic service and package names, different
  39. distributions often use different names for packages and services. For
  40. instance `apache` should be replaced with `httpd` on a Red Hat system.
  41. Salt uses the name of the init script, systemd name, upstart name etc.
  42. based on what the underlying service management for the platform. To
  43. get a list of the available service names on a platform execute the
  44. service.get_all salt function.
  45. Information on how to make states work with multiple distributions
  46. is later in the tutorial.
  47. .. code-block:: yaml
  48. apache:
  49. pkg.installed: []
  50. service.running:
  51. - require:
  52. - pkg: apache
  53. This SLS data will ensure that the package named apache is installed, and
  54. that the apache service is running. The components can be explained in a
  55. simple way.
  56. The first line is the ID for a set of data, and it is called the ID
  57. Declaration. This ID sets the name of the thing that needs to be manipulated.
  58. The second and third lines contain the state module function to be run, in the
  59. format ``<state_module>.<function>``. The ``pkg.installed`` state module
  60. function ensures that a software package is installed via the system's native
  61. package manager. The ``service.running`` state module function ensures that a
  62. given system daemon is running.
  63. Finally, on line five, is the word ``require``. This is called a Requisite
  64. Statement, and it makes sure that the Apache service is only started after
  65. a successful installation of the apache package.
  66. .. _`YAML`: https://yaml.org/spec/1.1/
  67. Adding Configs and Users
  68. ========================
  69. When setting up a service like an Apache web server, many more components may
  70. need to be added. The Apache configuration file will most likely be managed,
  71. and a user and group may need to be set up.
  72. .. code-block:: yaml
  73. apache:
  74. pkg.installed: []
  75. service.running:
  76. - watch:
  77. - pkg: apache
  78. - file: /etc/httpd/conf/httpd.conf
  79. - user: apache
  80. user.present:
  81. - uid: 87
  82. - gid: 87
  83. - home: /var/www/html
  84. - shell: /bin/nologin
  85. - require:
  86. - group: apache
  87. group.present:
  88. - gid: 87
  89. - require:
  90. - pkg: apache
  91. /etc/httpd/conf/httpd.conf:
  92. file.managed:
  93. - source: salt://apache/httpd.conf
  94. - user: root
  95. - group: root
  96. - mode: 644
  97. This SLS data greatly extends the first example, and includes a config file,
  98. a user, a group and new requisite statement: ``watch``.
  99. Adding more states is easy, since the new user and group states are under
  100. the Apache ID, the user and group will be the Apache user and group. The
  101. ``require`` statements will make sure that the user will only be made after
  102. the group, and that the group will be made only after the Apache package is
  103. installed.
  104. Next, the ``require`` statement under service was changed to watch, and is
  105. now watching 3 states instead of just one. The watch statement does the same
  106. thing as require, making sure that the other states run before running the
  107. state with a watch, but it adds an extra component. The ``watch`` statement
  108. will run the state's watcher function for any changes to the watched states.
  109. So if the package was updated, the config file changed, or the user
  110. uid modified, then the service state's watcher will be run. The service
  111. state's watcher just restarts the service, so in this case, a change in the
  112. config file will also trigger a restart of the respective service.
  113. Moving Beyond a Single SLS
  114. ==========================
  115. When setting up Salt States in a scalable manner, more than one SLS will need
  116. to be used. The above examples were in a single SLS file, but two or more
  117. SLS files can be combined to build out a State Tree. The above example also
  118. references a file with a strange source - ``salt://apache/httpd.conf``. That
  119. file will need to be available as well.
  120. The SLS files are laid out in a directory structure on the Salt master; an
  121. SLS is just a file and files to download are just files.
  122. The Apache example would be laid out in the root of the Salt file server like
  123. this:
  124. .. code-block:: text
  125. apache/init.sls
  126. apache/httpd.conf
  127. So the httpd.conf is just a file in the apache directory, and is referenced
  128. directly.
  129. .. include:: ../../_incl/_incl/sls_filename_cant_contain_period.rst
  130. But when using more than one single SLS file, more components can be added to
  131. the toolkit. Consider this SSH example:
  132. ``ssh/init.sls:``
  133. .. code-block:: yaml
  134. openssh-client:
  135. pkg.installed
  136. /etc/ssh/ssh_config:
  137. file.managed:
  138. - user: root
  139. - group: root
  140. - mode: 644
  141. - source: salt://ssh/ssh_config
  142. - require:
  143. - pkg: openssh-client
  144. ``ssh/server.sls:``
  145. .. code-block:: yaml
  146. include:
  147. - ssh
  148. openssh-server:
  149. pkg.installed
  150. sshd:
  151. service.running:
  152. - require:
  153. - pkg: openssh-client
  154. - pkg: openssh-server
  155. - file: /etc/ssh/banner
  156. - file: /etc/ssh/sshd_config
  157. /etc/ssh/sshd_config:
  158. file.managed:
  159. - user: root
  160. - group: root
  161. - mode: 644
  162. - source: salt://ssh/sshd_config
  163. - require:
  164. - pkg: openssh-server
  165. /etc/ssh/banner:
  166. file:
  167. - managed
  168. - user: root
  169. - group: root
  170. - mode: 644
  171. - source: salt://ssh/banner
  172. - require:
  173. - pkg: openssh-server
  174. .. note::
  175. Notice that we use two similar ways of denoting that a file
  176. is managed by Salt. In the `/etc/ssh/sshd_config` state section above,
  177. we use the `file.managed` state declaration whereas with the
  178. `/etc/ssh/banner` state section, we use the `file` state declaration
  179. and add a `managed` attribute to that state declaration. Both ways
  180. produce an identical result; the first way -- using `file.managed` --
  181. is merely a shortcut.
  182. Now our State Tree looks like this:
  183. .. code-block:: text
  184. apache/init.sls
  185. apache/httpd.conf
  186. ssh/init.sls
  187. ssh/server.sls
  188. ssh/banner
  189. ssh/ssh_config
  190. ssh/sshd_config
  191. This example now introduces the ``include`` statement. The include statement
  192. includes another SLS file so that components found in it can be required,
  193. watched or as will soon be demonstrated - extended.
  194. The include statement allows for states to be cross linked. When an SLS
  195. has an include statement it is literally extended to include the contents of
  196. the included SLS files.
  197. Note that some of the SLS files are called init.sls, while others are not. More
  198. info on what this means can be found in the :ref:`States Tutorial
  199. <sls-file-namespace>`.
  200. Extending Included SLS Data
  201. ===========================
  202. Sometimes SLS data needs to be extended. Perhaps the apache service needs to
  203. watch additional resources, or under certain circumstances a different file
  204. needs to be placed.
  205. In these examples, the first will add a custom banner to ssh and the second will
  206. add more watchers to apache to include mod_python.
  207. ``ssh/custom-server.sls:``
  208. .. code-block:: yaml
  209. include:
  210. - ssh.server
  211. extend:
  212. /etc/ssh/banner:
  213. file:
  214. - source: salt://ssh/custom-banner
  215. ``python/mod_python.sls:``
  216. .. code-block:: yaml
  217. include:
  218. - apache
  219. extend:
  220. apache:
  221. service:
  222. - watch:
  223. - pkg: mod_python
  224. mod_python:
  225. pkg.installed
  226. The ``custom-server.sls`` file uses the extend statement to overwrite where the
  227. banner is being downloaded from, and therefore changing what file is being used
  228. to configure the banner.
  229. In the new mod_python SLS the mod_python package is added, but more importantly
  230. the apache service was extended to also watch the mod_python package.
  231. .. include:: ../../_incl/extend_with_require_watch.rst
  232. Understanding the Render System
  233. ===============================
  234. Since SLS data is simply that (data), it does not need to be represented
  235. with YAML. Salt defaults to YAML because it is very straightforward and easy
  236. to learn and use. But the SLS files can be rendered from almost any imaginable
  237. medium, so long as a renderer module is provided.
  238. The default rendering system is the ``jinja|yaml`` renderer. The
  239. ``jinja|yaml`` renderer will first pass the template through the `Jinja2`_
  240. templating system, and then through the YAML parser. The benefit here is that
  241. full programming constructs are available when creating SLS files.
  242. Other renderers available are ``yaml_mako`` and ``yaml_wempy`` which each use
  243. the `Mako`_ or `Wempy`_ templating system respectively rather than the jinja
  244. templating system, and more notably, the pure Python or ``py``, ``pydsl`` &
  245. ``pyobjects`` renderers.
  246. The ``py`` renderer allows for SLS files to be written in pure Python,
  247. allowing for the utmost level of flexibility and power when preparing SLS
  248. data; while the :mod:`pydsl<salt.renderers.pydsl>` renderer
  249. provides a flexible, domain-specific language for authoring SLS data in Python;
  250. and the :mod:`pyobjects<salt.renderers.pyobjects>` renderer
  251. gives you a `"Pythonic"`_ interface to building state data.
  252. .. _`Jinja2`: https://jinja.palletsprojects.com/en/2.11.x/
  253. .. _`Mako`: https://www.makotemplates.org/
  254. .. _`Wempy`: https://fossil.secution.com/u/gcw/wempy/doc/tip/README.wiki
  255. .. _`"Pythonic"`: https://legacy.python.org/dev/peps/pep-0008/
  256. .. note::
  257. The templating engines described above aren't just available in SLS files.
  258. They can also be used in :mod:`file.managed <salt.states.file.managed>`
  259. states, making file management much more dynamic and flexible. Some
  260. examples for using templates in managed files can be found in the
  261. documentation for the :mod:`file state <salt.states.file>`, as well as the
  262. :ref:`MooseFS example<jinja-example-moosefs>` below.
  263. Getting to Know the Default - jinja|yaml
  264. ----------------------------------------
  265. The default renderer - ``jinja|yaml``, allows for use of the jinja
  266. templating system. A guide to the Jinja templating system can be found here:
  267. https://jinja.palletsprojects.com/en/2.11.x/
  268. When working with renderers a few very useful bits of data are passed in. In
  269. the case of templating engine based renderers, three critical components are
  270. available, ``salt``, ``grains``, and ``pillar``. The ``salt`` object allows for
  271. any Salt function to be called from within the template, and ``grains`` allows
  272. for the Grains to be accessed from within the template. A few examples:
  273. ``apache/init.sls:``
  274. .. code-block:: jinja
  275. apache:
  276. pkg.installed:
  277. {% if grains['os'] == 'RedHat'%}
  278. - name: httpd
  279. {% endif %}
  280. service.running:
  281. {% if grains['os'] == 'RedHat'%}
  282. - name: httpd
  283. {% endif %}
  284. - watch:
  285. - pkg: apache
  286. - file: /etc/httpd/conf/httpd.conf
  287. - user: apache
  288. user.present:
  289. - uid: 87
  290. - gid: 87
  291. - home: /var/www/html
  292. - shell: /bin/nologin
  293. - require:
  294. - group: apache
  295. group.present:
  296. - gid: 87
  297. - require:
  298. - pkg: apache
  299. /etc/httpd/conf/httpd.conf:
  300. file.managed:
  301. - source: salt://apache/httpd.conf
  302. - user: root
  303. - group: root
  304. - mode: 644
  305. This example is simple. If the ``os`` grain states that the operating system is
  306. Red Hat, then the name of the Apache package and service needs to be httpd.
  307. .. _jinja-example-moosefs:
  308. A more aggressive way to use Jinja can be found here, in a module to set up
  309. a MooseFS distributed filesystem chunkserver:
  310. ``moosefs/chunk.sls:``
  311. .. code-block:: jinja
  312. include:
  313. - moosefs
  314. {% for mnt in salt['cmd.run']('ls /dev/data/moose*').split() %}
  315. /mnt/moose{{ mnt[-1] }}:
  316. mount.mounted:
  317. - device: {{ mnt }}
  318. - fstype: xfs
  319. - mkmnt: True
  320. file.directory:
  321. - user: mfs
  322. - group: mfs
  323. - require:
  324. - user: mfs
  325. - group: mfs
  326. {% endfor %}
  327. /etc/mfshdd.cfg:
  328. file.managed:
  329. - source: salt://moosefs/mfshdd.cfg
  330. - user: root
  331. - group: root
  332. - mode: 644
  333. - template: jinja
  334. - require:
  335. - pkg: mfs-chunkserver
  336. /etc/mfschunkserver.cfg:
  337. file.managed:
  338. - source: salt://moosefs/mfschunkserver.cfg
  339. - user: root
  340. - group: root
  341. - mode: 644
  342. - template: jinja
  343. - require:
  344. - pkg: mfs-chunkserver
  345. mfs-chunkserver:
  346. pkg.installed: []
  347. mfschunkserver:
  348. service.running:
  349. - require:
  350. {% for mnt in salt['cmd.run']('ls /dev/data/moose*') %}
  351. - mount: /mnt/moose{{ mnt[-1] }}
  352. - file: /mnt/moose{{ mnt[-1] }}
  353. {% endfor %}
  354. - file: /etc/mfschunkserver.cfg
  355. - file: /etc/mfshdd.cfg
  356. - file: /var/lib/mfs
  357. This example shows much more of the available power of Jinja.
  358. Multiple for loops are used to dynamically detect available hard drives
  359. and set them up to be mounted, and the ``salt`` object is used multiple
  360. times to call shell commands to gather data.
  361. Introducing the Python, PyDSL, and the Pyobjects Renderers
  362. ----------------------------------------------------------
  363. Sometimes the chosen default renderer might not have enough logical power to
  364. accomplish the needed task. When this happens, the Python renderer can be
  365. used. Normally a YAML renderer should be used for the majority of SLS files,
  366. but an SLS file set to use another renderer can be easily added to the tree.
  367. This example shows a very basic Python SLS file:
  368. ``python/django.sls:``
  369. .. code-block:: python
  370. #!py
  371. def run():
  372. '''
  373. Install the django package
  374. '''
  375. return {'include': ['python'],
  376. 'django': {'pkg': ['installed']}}
  377. This is a very simple example; the first line has an SLS shebang that
  378. tells Salt to not use the default renderer, but to use the ``py`` renderer.
  379. Then the run function is defined, the return value from the run function
  380. must be a Salt friendly data structure, or better known as a Salt
  381. :ref:`HighState data structure<states-highstate>`.
  382. Alternatively, using the :mod:`pydsl<salt.renderers.pydsl>`
  383. renderer, the above example can be written more succinctly as:
  384. .. code-block:: python
  385. #!pydsl
  386. include('python', delayed=True)
  387. state('django').pkg.installed()
  388. The :mod:`pyobjects<salt.renderers.pyobjects>` renderer
  389. provides an `"Pythonic"`_ object based approach for building the state data.
  390. The above example could be written as:
  391. .. code-block:: python
  392. #!pyobjects
  393. include('python')
  394. Pkg.installed("django")
  395. These Python examples would look like this if they were written in YAML:
  396. .. code-block:: yaml
  397. include:
  398. - python
  399. django:
  400. pkg.installed
  401. This example clearly illustrates that; one, using the YAML renderer by default
  402. is a wise decision and two, unbridled power can be obtained where needed by
  403. using a pure Python SLS.
  404. Running and Debugging Salt States
  405. ---------------------------------
  406. Once the rules in an SLS are ready, they should be tested to ensure they
  407. work properly. To invoke these rules, simply execute
  408. ``salt '*' state.apply`` on the command line. If you get back only
  409. hostnames with a ``:`` after, but no return, chances are there is a problem with
  410. one or more of the sls files. On the minion, use the ``salt-call`` command to
  411. examine the output for errors:
  412. .. code-block:: bash
  413. salt-call state.apply -l debug
  414. This should help troubleshoot the issue. The minion can also be started in the
  415. foreground in debug mode by running ``salt-minion -l debug``.
  416. Next Reading
  417. ============
  418. With an understanding of states, the next recommendation is to become familiar
  419. with Salt's pillar interface:
  420. :ref:`Pillar Walkthrough <pillar-walk-through>`