{"id":1230,"date":"2021-09-30T10:51:10","date_gmt":"2021-09-30T09:51:10","guid":{"rendered":"https:\/\/nine30.info\/?p=1230"},"modified":"2021-09-30T10:51:10","modified_gmt":"2021-09-30T09:51:10","slug":"vra-saltstack-config-top-files","status":"publish","type":"post","link":"https:\/\/nine30.nxt70.com\/index.php\/2021\/09\/30\/vra-saltstack-config-top-files\/","title":{"rendered":"vRA SaltStack Config \u2013 Top Files"},"content":{"rendered":"\n<p>So far we played with Salt <strong>State<\/strong> files to apply configurations to Minions and we learned that these are generic by design and describe only&nbsp;<em>what<\/em> configuration should be achieved. And we used the concept of <strong>Targeting<\/strong> to specify <em>where<\/em> one, or more, State should be applied.<\/p>\n\n\n\n<p>In this post I\u2019ll try to cover a different file, called the <strong>Top<\/strong> file, that brings together States and Targeting, that is <em>what<\/em> and <em>where<\/em> configurations should be applied. States and the Top file work together to create the core of SaltStack\u2019s configuration management capability.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Top Files<\/h2>\n\n\n\n<p>A Top file is used to apply multiple State files to your Salt Minions, this action is also called a highstate. The States that are applied to each system are determined by the targets that are specified in the Top file.<\/p>\n\n\n\n<p>A Top file has three elements:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Environment:<\/strong>&nbsp;that is the <code>saltenv<\/code>, a state tree directory containing a set of State files to configure Minions;<\/li><li><strong>Target:<\/strong>&nbsp;a grouping of Minions which will have a set of states applied to them;<\/li><li><strong>State files:<\/strong>&nbsp;a list of State files to be applied to a target. Each State file describes one or more configuration to be enforced on the targeted Minions.<\/li><\/ul>\n\n\n\n<p>The relationship between these three components is nested as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Environments contain Targets<\/li><li>Targets contain States<\/li><\/ul>\n\n\n\n<p>Here below there is a very basic Top file to introduce the structure just described.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>base:          # Apply SLS files for the 'base' environment\n  'web*':      # All minions with a minion_id that begins with 'web'\n    - apache   # Apply the state file apache<\/code><\/pre>\n\n\n\n<p>When Top file is applied, each Salt Minion is matched against the targets listed in the&nbsp;<code>top.sls<\/code>&nbsp;file. When a Salt Minion matches a target, it receives all of the State files defined in the list underneath that target. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Top File Example<\/h2>\n\n\n\n<p>In my opinion, Top file is one of those things that are best learned by example. Instead of further elaborating and digging into details, here after there is a simple Top file and further below we will go through each section.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>base:\n  '*':\n    - \/config\/users\n    - \/config\/scripts\n  '*web*':\n    - \/applications\/nginx\n  'application:mongodb':\n    - match: grain\n    - \/applications\/mongodb<\/code><\/pre>\n\n\n\n<p>All Minions get applied <code>users<\/code> and <code>scripts<\/code> States<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><meta charset=\"utf-8\">'*':\n    - \/config\/users\n    - \/config\/scripts<\/code><\/pre>\n\n\n\n<p>Every Minion having the string <code>web<\/code> in the ID gets applied with the <code>ngninx<\/code> State file<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><meta charset=\"utf-8\">'*web*':\n    - \/applications\/nginx<\/code><\/pre>\n\n\n\n<p>Every Minion having grain <code>application<\/code> : <code>mongodb<\/code> get applied <code>mongodb<\/code> State file. In a Top file you can use all the advanced targeting capabilities made available by SaltStack as documented <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.saltproject.io\/en\/latest\/ref\/states\/top.html#advanced-minion-targeting\" target=\"_blank\">here<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><meta charset=\"utf-8\">'application:mongodb':\n    - match: grain\n    - \/applications\/mongodb<\/code><\/pre>\n\n\n\n<p>Wait! I forgot the very first thing in our example! The <code>base<\/code> at the begin of the Top file identifies the applicable <code>saltenv<\/code> environment. You can have multiple environment sections in your Top file, of course all the states that you use within an environment section have to exists in that environment.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Get Started with Top Files<\/h2>\n\n\n\n<p>Before you get started with Top file you need to make sure <code>file_roots<\/code> property is defined for all your environments in the master configuration file, the following is what I have in my SaltStack deployment. Make sure to adjust root path as per your environment specifics as this is the place where you will store your Top file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>file_roots:\n   base:\n     - \/srv\/salt<\/code><\/pre>\n\n\n\n<p>Place your Top file in the specified path: <code>\/srv\/salt\/top.sls<\/code>. Please, note that <code>top.sls<\/code> is a kind of special name. Top files are named <code>top.sls<\/code> by default and they are so-named because they always exist in the &#8220;top&#8221; of a directory hierarchy that contains state files. That directory hierarchy is called a state tree.<\/p>\n\n\n\n<p>To apply a Top file you can simply use one of the the following commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>salt '*' state.apply<\/code><\/pre>\n\n\n\n<p>In the example above we are using the <code>state.apply<\/code> command that we already know, calling <code>state.apply<\/code> with no arguments starts a highstate (the highstate is the action to apply Top file). Alternatively we can explicitly use the <code>state.highstate<\/code> command as reported below.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>salt '*' state.highstate<\/code><\/pre>\n\n\n\n<p>If you are in a multiple environments Saltstack deployment you can use the <code>saltenv<\/code> argument to set the <code>saltenv<\/code> for the highstate.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><meta charset=\"utf-8\">salt '*' state.apply saltenv=dev\n<meta charset=\"utf-8\">salt '*' state.highstate saltenv=test<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Lab Time!<\/h2>\n\n\n\n<p>In my lab I have some minions, but for this activity I will restrict the scope to 3 minions having the string <code>secops<\/code> in their Minion IDs. One of them has a grain <code>application:nginx<\/code>.<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1242\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/09\/1.show_minions-1024x448.png\" alt=\"\" class=\"wp-image-1242\"\/><\/figure>\n<\/figure>\n\n\n\n<p>My Top file is reported below. Please, note that specifying <code>match: compound<\/code> is redundant as Compound is the default matcher for Top files.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>base:\n  '*':\n    - \/config\/users\n  'G@os:CentOS and G@application:apache':\n    - match: compound\n    - \/applications\/apache\n  'G@os:CentOS and G@application:nginx':\n    - match: compound\n    - \/applications\/nginx\n  'G@os:CentOS and G@application:mysql':\n    - match: compound\n    - \/applications\/mysql\n  'G@os:CentOS and G@application:mongodb':\n    - match: compound\n    - \/applications\/mongodb<\/code><\/pre>\n\n\n\n<p>Applying my Top file to the 3 Minions in scope of this activity enforces <code>users<\/code> to be present on any Minions and than install <code>nginx<\/code> on the <code>centos-secops.iberia.local<\/code>. User&#8217;s State file creates 3 local users by collecting data from a map file and using Jinja2 templating (I&#8217;ll cover templating and State files parameterization in a future post).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{% from 'config\/users\/map.jinja' import users with context %}\n\n{% for user in users %}\nadd_user_{{ user.username }}:\n  user.present:\n    - name: {{ user.username }}\n    - uid: {{ user.uid }}\n    - password: {{ user.password }}\n\n{% endfor %}<\/code><\/pre>\n\n\n\n<p>Here is the map.jinja file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{% set users = &#91;\n    {'username': 'luca', 'uid': 2001, 'password': 'be3bed2f000aae03f8cf880d77507e028280fb692a1e3b16cd3afb053e5ff30c'},\n    {'username': 'marco', 'uid': 2002, 'password': 'be3bed2f000aae03f8cf880d77507e028280fb692a1e3b16cd3afb053e5ff30c'},\n    {'username': 'pietro', 'uid': 2003, 'password': 'be3bed2f000aae03f8cf880d77507e028280fb692a1e3b16cd3afb053e5ff30c'},\n    ]\n%}<\/code><\/pre>\n\n\n\n<p>The Nginx&#8217;s State file includes 3 state IDs: install epel as it is a pre-requisites for Nginx, install Nginx and start Nginx.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Install NGINX on CentOS\/RHEL\n\ninstall_epel_release:\n  pkg.installed:\n    - name: epel-release\n\ninstall_nginx:\n  pkg.installed:\n    - name: nginx\n    - requres:\n      - install_epel_release\n\nstart_nginx:\n  service.running:\n    - name: nginx\n    - enable: True\n    - requires:\n      - install_nginx<\/code><\/pre>\n\n\n\n<p>Here is the CLI command and some section of the return:<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1244\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/09\/2.highstate-1024x372.png\" alt=\"\" class=\"wp-image-1244\"\/><\/figure>\n<\/figure>\n\n\n\n<p>The <code>ubuntu-secops.iberia.local<\/code> has 3 succeeded states as it get applied to User&#8217;s State file only (a state for each user).<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1245\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/09\/3.ubuntu.return-1024x373.png\" alt=\"\" class=\"wp-image-1245\"\/><\/figure>\n<\/figure>\n\n\n\n<p>Also the <code>windows-secops.iberia.local<\/code> has 3 <meta charset=\"utf-8\">succeeded states as it get applied to User&#8217;s state file only (a state for each user).<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1246\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/09\/4.windows.return-1024x374.png\" alt=\"\" class=\"wp-image-1246\"\/><\/figure>\n<\/figure>\n\n\n\n<p>The <code>centos-secops.iberia.local<\/code> has 6 <meta charset=\"utf-8\">succeeded states as it get applied to User&#8217;s State file (a state for each user) and the Nginx&#8217;s State file (that is made up of 3 state IDs).<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-5 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"1247\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/09\/5.centos.return-1024x374.png\" alt=\"\" class=\"wp-image-1247\"\/><\/figure>\n<\/figure>\n\n\n\n<p>This is post just provides the very basic to get started with Top files, you can use the snippets included in this post to replicate this in your lab and surely you can improve it! I hope this can help you in your Salt exploration journey. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>So far we played with Salt State files to apply configurations to Minions and we learned that these are generic by design and describe only&nbsp;what configuration should be achieved. And we used the concept of Targeting to specify where one, or more, State should be applied. In this post I\u2019ll try to cover a different&hellip; <a class=\"more-link\" href=\"https:\/\/nine30.nxt70.com\/index.php\/2021\/09\/30\/vra-saltstack-config-top-files\/\">Continue reading <span class=\"screen-reader-text\">vRA SaltStack Config \u2013 Top Files<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":586,"comment_status":"open","ping_status":"open","sticky":false,"template":"templates\/template-cover.php","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[4],"tags":[23,35,38,40,81,98,122,126,143,144,145,178,185,186],"class_list":["post-1230","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tech","tag-automation","tag-cloud","tag-cloudmanagement","tag-configuration","tag-handson","tag-lab","tag-opensource","tag-oss","tag-salt","tag-saltproject","tag-saltstack","tag-vmware","tag-vrealize","tag-vrealizeautomation","entry"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/posts\/1230","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/comments?post=1230"}],"version-history":[{"count":0,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/posts\/1230\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/"}],"wp:attachment":[{"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/media?parent=1230"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/categories?post=1230"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/tags?post=1230"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}