{"id":774,"date":"2021-04-12T13:01:09","date_gmt":"2021-04-12T12:01:09","guid":{"rendered":"https:\/\/nine30.info\/?p=774"},"modified":"2021-04-12T13:01:09","modified_gmt":"2021-04-12T12:01:09","slug":"vra-saltstack-config-declarative-configuration-management","status":"publish","type":"post","link":"https:\/\/nine30.nxt70.com\/index.php\/2021\/04\/12\/vra-saltstack-config-declarative-configuration-management\/","title":{"rendered":"vRA SaltStack Config \u2013 Declarative Configuration Management"},"content":{"rendered":"\n<p>So far we covered SaltStack remote execution (do you remember the command <code>salt myminionid pkg.install httpd<\/code> and the Salt Execution Module? If not check <a rel=\"noreferrer noopener\" href=\"https:\/\/nine30.info\/vra-saltstack-config-add-minions-and-commands\/\" target=\"_blank\">this post<\/a>) which is great and powerful, but it is more suited for spot activities. Actually when you have to manage complex systems configuration at scale you need a combination of many operations, commands and tests each with their peculiarity. This would turn out into a script which is procedural.<\/p>\n\n\n\n<p>Actually Salt also supports (and it is popular for) declarative approach. SaltStack lets you create a re-usable configuration template, called a <strong>State file<\/strong>, that describes everything required to put a system or application into a known configuration. <strong>With State file SaltStack adopts a declarative approach: you describe the desired state of your managed systems and SaltStack make sure this is applied to the Target you specify<\/strong>. States are described using YAML and are simple to create and read. Honestly, States are much easier to understand when you see them in action, so let\u2019s play with them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">States<\/h2>\n\n\n\n<p>States can install packages, manage files, manage users, restart services when changes are made, copy entire directories, explicitly require that other states run first, use variables, and much more. To get a introduction to these capabilities with a very simple, but non trivial, example we will create a State file that installs and provides basic configuration for an Apache Web Server on a CentOS 7 machine. We will do this in a single State file step by step.<\/p>\n\n\n\n<p>SaltStack cool kids work with YAML file editor (e.g. VS Code) and git repos and we&#8217;ll get there sooner or later, but here I think it is better to stick with the vRA SaltStack Config user interface so that we can focus on the heart of the matter. In order to create our state file you have to login in the UI and navigate to Elements &gt; File Server, here you select <code>base<\/code> in the Saltenv drop down menu and type <code>\/applications\/apache\/init.sls<\/code> in path name text field as in the picture below. Click on the Save button (that now should be blue and not greyed out) in order to create a (empty) State file named <code>init.sls<\/code> in the <code>base<\/code> environment (Saltenv) under the path <code>\/applications\/apache<\/code>. This nesting under Applications and Apache directories is not really needed now, but it will be useful in our future activities. In general it is best practice to keep directory structure as flat as possible. <\/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=\"776\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/03\/01.new_.state_.file_-1.png\" alt=\"\" class=\"wp-image-776\"\/><\/figure>\n<\/figure>\n\n\n\n<p>Here we just introduced a couple of new things: File Server and Environment, these are important concept and we might cover them in another post as I do not want to divert now from the main topic. So far it is enough to know that as in SaltStack all configurations are based on files, it comes with a simple <strong>File Server<\/strong> suitable to present files for use in the SaltStack state system. In addition to the default File Server backend (named <code>roots<\/code>) you can configure other backends (e.g. <code>gitfs<\/code>), <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.saltproject.io\/en\/latest\/ref\/file_server\/all\/index.html#all-salt-fileserver\" target=\"_blank\">here<\/a> you can access the list of available backends. The SaltStack File Server supports multiple <strong>Environments<\/strong>, allowing for State files and other files to be isolated for better organization. Each File Server backend comes with its own way to configure Environments.  <\/p>\n\n\n\n<p>Let&#8217;s start building our State file step by step. As a first thing we will install the Apache Web Server, the related software package in the Red Hat family is named httpd; it is important to know the package name in the OS family you are working with (remember to automate something you need to know how to do it manually). The piece of YAML configuration required is reported in the snippet below, easy no? Type the snippet below in your <code>init.sls<\/code> files and hit Save button.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Install and Configure Apache HTTPD on RHEL\/CoreOS\n\ninstall_apache:\n  pkg.installed:\n    - name: httpd<\/code><\/pre>\n\n\n\n<p>OK, what&#8217;s in there?<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code># Install and Configure<\/code> &#8230; this is a comment (so you now know how to add comments!);<\/li><li><code>install_apache<\/code> is the identifier declaration for the state section, this can be used to reference this section in other part of the state file;<\/li><li><code>pkg.intalled<\/code> is the State Module + Function that is respectively the name of the State Module to find the function in (in this case <code>pkg<\/code>) and the function to call in the named module (in our case <code>installed<\/code>);<\/li><li><code>name: httpd<\/code> is an argument, state function will accept a number of arguments depending on the function. In our example the argument name let&#8217;s you specify the package to be installed (in our case <code>hpptd<\/code>).<\/li><\/ul>\n\n\n\n<p>This is all you need to install Apache! To make it a little more useful we need to add at least a configuration file. Here is the section to be added to our State file to do that (once added make sure to hit Save button).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>confgiure_apache:\n  file.managed:\n    - name: \/etc\/httpd\/conf\/httpd.conf\n    - source: salt:\/\/applications\/apache\/files\/httpd.conf\n  require:\n    - pkg: install_apache <\/code><\/pre>\n\n\n\n<p>The snippet above simply copy a file named <code>httpd.conf<\/code> from the SaltStack master to the Target and make sure this can only happen if the Apache Web Server is actually installed<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>configure_apache<\/code> is the identifier (ID) declaration for the state section;<\/li><li><code>file.managed<\/code> is the State Module + Function we use to manage files;<\/li><li><code>name<\/code> it is the attribute that specifies the absolute path of the configuration file including the file name;<\/li><li><code>source<\/code> is the attribute that identifies the file on the SaltStack File Server to be copied on the Target;<\/li><li><code>require<\/code> is a statement that ensure that the named state section is evaluated before the state section requiring it. There are several other direct requisite statements that can be used in Salt that inherently implement failing hard behavior;<\/li><li><code>pkg: install_apache<\/code> is an attribute of the <code>require<\/code> statement that allows to define the requisite. In this case we use module:ID (<code>pkg:install_apache<\/code>), but we can also reference it with module:name (<code>pkg:httpd<\/code>) or simply by ID (<code>install_apache<\/code>).<\/li><\/ul>\n\n\n\n<p>To make this piece of State file actually works we need to make sure the <code>httpd.conf<\/code> file exists in our Master File Server at the specified path. In the vRA SaltStack Config user interface click on the + Create button in the bottom left of the page, then select <code>base<\/code> in the Saltenv drop down menu and type <code>\/applications\/apache\/files\/httpd.conf<\/code> in path name text field. Add the following text in the newly created file and than save it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># RHEL\/centos 7.5 (apache 2.4.6)\nServerRoot \"\/etc\/httpd\"\nListen 80\nInclude conf.modules.d\/*.conf\nUser apache\nGroup apache\nServerAdmin apache@mail.com\n&lt;Directory \/&gt;\n    AllowOverride none\n    Require all denied\n&lt;\/Directory&gt;\nDocumentRoot \"\/var\/www\/html\"\n&lt;Directory \"\/var\/www\"&gt;\n    AllowOverride None\n    Require all granted\n&lt;\/Directory&gt;\n&lt;Directory \"\/var\/www\/html\"&gt;\n    Options Indexes FollowSymLinks\n    AllowOverride None\n    Require all granted\n&lt;\/Directory&gt;\n&lt;IfModule dir_module&gt;\n    DirectoryIndex index.html\n&lt;\/IfModule&gt;\n&lt;Files \".ht*\"&gt;\n    Require all denied\n&lt;\/Files&gt;\nErrorLog \"logs\/error_log\"\nLogLevel warn\n&lt;IfModule log_config_module&gt;\n    LogFormat \"%h %l %u %t \\\"%r\\\" %&gt;s %b \\\"%{Referer}i\\\" \\\"%{User-Agent}i\\\"\" combined\n    LogFormat \"%h %l %u %t \\\"%r\\\" %&gt;s %b\" common\n    CustomLog \"logs\/access_log\" combined\n&lt;\/IfModule&gt;\n&lt;IfModule alias_module&gt;\n    ScriptAlias \/cgi-bin\/ \"\/var\/www\/cgi-bin\/\"\n&lt;\/IfModule&gt;\n&lt;Directory \"\/var\/www\/cgi-bin\"&gt;\n    AllowOverride None\n    Options None\n    Require all granted\n&lt;\/Directory&gt;\n&lt;IfModule mime_module&gt;\n    TypesConfig \/etc\/mime.types\n    AddType application\/x-compress .Z\n    AddType application\/x-gzip .gz .tgz\n    AddType text\/html .shtml\n    AddOutputFilter INCLUDES .shtml\n&lt;\/IfModule&gt;\nAddDefaultCharset UTF-8\n&lt;IfModule mime_magic_module&gt;\n    MIMEMagicFile conf\/magic\n&lt;\/IfModule&gt;\nEnableSendfile on\nIncludeOptional conf.d\/*.conf<\/code><\/pre>\n\n\n\n<p>The last bit of the Apache Web Server configuration is to place the <code>hpptd<\/code> service in the running state. Here is the section to be appended to our State file to do that (once added make sure to hit Save button).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>start_apache:\n  service.running:\n    - name: httpd\n    - enable: True\n    - watch:\n      - file: configure_apache<\/code><\/pre>\n\n\n\n<p>At this point I think the above snipped is pretty self explanatory with the exception of the <code>watch<\/code> statement. So let&#8217;s clarify it:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>watch<\/code> is a type of requisite, actually this statement is more advanced than the <code>require<\/code> statement. It executes the same logic as <code>require<\/code>: if something is watched it does not need to also be required with the addition of executing logic in case the required states have changed in some way. The <code>watch<\/code> requisite also checks to see if the watched states have returned any changes. If the watched state executes successfully and the state returns changes, then the watching state will execute a function that reacts to the changes in the watched states.<\/li><\/ul>\n\n\n\n<p>So our state files should look like this below:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Install and Configure Apache HTTPD on RHEL\/CoreOS\n\ninstall_apache:\n  pkg.installed:\n    - name: httpd\n\nconfgiure_apache:\n  file.managed:\n    - name: \/etc\/httpd\/conf\/httpd.conf\n    - source: salt:\/\/applications\/apache\/files\/httpd.conf\n  require:\n    - pkg: install_apache \n\nstart_apache:\n  service.running:\n    - name: httpd\n    - enable: True\n    - watch:\n      - file: configure_apache<\/code><\/pre>\n\n\n\n<p>Now it is time to run it, to do that select the Minion ID of a CentOS\/RHEL 7, as shown in the screenshot below, and then hit the button Run Command.<\/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=\"814\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/04\/02.select.minion.jpg\" alt=\"\" class=\"wp-image-814\"\/><\/figure>\n<\/figure>\n\n\n\n<p>Fill the form as in the screenshot below, please note that we do not need to specify the name of the state file as we used <code>init.sls<\/code> which is a sort of special state file name, within a folder <code>init.sls<\/code> is the default state file to be executed by <code>state.apply<\/code> command.<\/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=\"815\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/04\/03.run_.png\" alt=\"\" class=\"wp-image-815\"\/><\/figure>\n<\/figure>\n\n\n\n<p>You can check the progress either under the Activity tab or by selecting the Minion ID and then selecting Activity (1 in the screenshot below). Once the command appears as Completed you can click on the the corresponding Job ID (2 in the screenshot below) to access execution details.<\/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=\"816\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/04\/04.progress.jpg\" alt=\"\" class=\"wp-image-816\"\/><\/figure>\n<\/figure>\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=\"817\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/04\/05.results.jpg\" alt=\"\" class=\"wp-image-817\"\/><\/figure>\n<\/figure>\n\n\n\n<p>Finally you can check the Apache Web Server is actually working by simply connecting to http:\/\/&lt;your-minion-IP-or-FQDN&gt;:<\/p>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-6 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" data-id=\"818\" src=\"https:\/\/nine30.info\/wp-content\/uploads\/2021\/04\/06.home_.test_.jpg\" alt=\"\" class=\"wp-image-818\"\/><\/figure>\n<\/figure>\n\n\n\n<p>Let me close this post with a couple of considerations:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">State Module vs Execution Module, Declarative vs. Procedural<\/h3>\n\n\n\n<p>In our State file we used State Modules while in our <a rel=\"noreferrer noopener\" href=\"https:\/\/nine30.info\/vra-saltstack-config-add-minions-and-commands\/\" target=\"_blank\">previous post<\/a> we used Execution Modules in the CLI. There is nothing complex here, State Modules leverage Execution Modules but they add the required logic to support the declarative approach answering question like: What if the package is already installed? What if the service is already started? Does it need to be restarted? Is it required to set permissions and ownership on the file in addition to just pushing it down? Would that require additional calls?<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">YAML<\/h3>\n\n\n\n<p>SaltStack uses YAML format &#8230; well, actually sls files can be written in a variety of formats as an sls is just a data structure comprised of dictionaries, lists, strings and numbers, etc. YAML is just the most common format for SaltStack sls files &#8230; and we all know that YAML can became tricky, but it is a safe choice with unquestionable industry adoption, &#8220;used by kubernetes&#8221;. The best practice in Saltstack sls files is to use a 4 spaces indentation (use it!).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So far we covered SaltStack remote execution (do you remember the command salt myminionid pkg.install httpd and the Salt Execution Module? If not check this post) which is great and powerful, but it is more suited for spot activities. Actually when you have to manage complex systems configuration at scale you need a combination of&hellip; <a class=\"more-link\" href=\"https:\/\/nine30.nxt70.com\/index.php\/2021\/04\/12\/vra-saltstack-config-declarative-configuration-management\/\">Continue reading <span class=\"screen-reader-text\">vRA SaltStack Config \u2013 Declarative Configuration Management<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":593,"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":[13,23,40,41,51,88,99,122,126,143,145,178,184,186,196],"class_list":["post-774","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tech","tag-apache","tag-automation","tag-configuration","tag-configurationmanagement","tag-declarative","tag-iac","tag-linux","tag-opensource","tag-oss","tag-salt","tag-saltstack","tag-vmware","tag-vra","tag-vrealizeautomation","tag-yaml","entry"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/posts\/774","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=774"}],"version-history":[{"count":0,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/posts\/774\/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=774"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/categories?post=774"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nine30.nxt70.com\/index.php\/wp-json\/wp\/v2\/tags?post=774"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}