Sunday, 13 November 2016

Getting started with Saltstack part 4 (Configuration management using states)

We implement Salt's configuration management aspect via states. A state in Salt terminology is a file which basically represents the desired state of configuration that we need our minions to be in. By default, state files are stored in /srv/salt directory. Any Salt specific file that is not a python script has a .sls extension.

I've created a state file apache.sls in /srv/salt directory with the following content:

[root@cserver salt]# cat apache.sls
install_apache:
 pkg.installed:
  - name: httpd

ensure apache is started:
 service.running:
  - name: httpd
  - enable: True

Implementation of this state will install httpd service on the minions, start eh service & make sure that service starts on system boot.

To execute the state, use the state.sls module:

[root@cserver salt]# salt '*' state.sls apache
secondminion:
----------
          ID: install_apache
    Function: pkg.installed
        Name: httpd
      Result: True
     Comment: Package httpd is already installed
     Started: 06:03:24.373785
    Duration: 606.13 ms
     Changes:
----------
          ID: ensure apache is started
    Function: service.running
        Name: httpd
      Result: True
     Comment: The service httpd is already running
     Started: 06:03:24.980703
    Duration: 37.723 ms
     Changes:

Summary for secondminion
------------
Succeeded: 2
Failed:    0
------------
Total states run:     2
Total run time: 643.853 ms


Like the modules we used for remote execution, we can get information on modules pertaining to state executions by querying them using the sys module as shown below:

[root@cserver salt]# salt '*' sys.list_state_functions pkg
secondminion:
    - pkg.group_installed
    - pkg.installed
    - pkg.latest
    - pkg.mod_aggregate
    - pkg.mod_init
    - pkg.mod_watch
    - pkg.purged
    - pkg.removed
    - pkg.uptodate
firstminion:
    - pkg.group_installed
    - pkg.installed
    - pkg.latest
    - pkg.mod_aggregate
    - pkg.mod_init
    - pkg.mod_watch
    - pkg.purged
    - pkg.removed
    - pkg.uptodate
[root@cserver salt]# salt '*' sys.list_state_functions service
secondminion:
    - service.dead
    - service.disabled
    - service.enabled
    - service.mod_watch
    - service.running
firstminion:
    - service.dead
    - service.disabled
    - service.enabled
    - service.mod_watch
    - service.running
[root@cserver salt]#


To view documentation related to a module using sys.state_doc module.

[root@cserver salt]# salt '*' sys.state_doc service
secondminion:
    ----------
    service:

        Starting or restarting of services and daemons
        ==============================================

        Services are defined as system daemons typically started with system init or
        rc scripts. The service state uses whichever service module that is loaded on
        the minion with the virtualname of ``service``. Services can be defined as
        running or dead.

        If you need to know if your init system is supported, see the list of supported
        :mod:`service modules <salt.modules.service.py>` for your desired init system
        (systemd, sysvinit, launchctl, etc.).

        Note that Salt's service execution module, and therefore this service state,
        uses OS grains to ascertain which service module should be loaded and used to
        execute service functions. As existing distributions change init systems or
        new distributions are created, OS detection can sometimes be incomplete.
        If your service states are running into trouble with init system detection,
        please see the :ref:`Overriding Virtual Module Providers <module-provider-override>`
        section of Salt's module documentation to work around possible errors.

        Note:
            The current status of a service is determined by the return code of the init/rc
            script status command. A status return code of 0 it is considered running.  Any
            other return code is considered dead.

            httpd:
              service.running: []

        The service can also be set to be started at runtime via the enable option:

            openvpn:
              service.running:
                - enable: True


The basic structure of a state file is as follows:

<ID Declaration>:  
<State Module>.<Function>:   
   - name: <name>    
   - <Function Arg>   
   - <Function Arg>    
   - <Function Arg>    
  - <Requisite Declaration>:     
   - <Requisite Reference> 

The file are written in YAML so syntax is very important.

The ID declaration is the description of the state. Next is the execution module that we'll be using followed by the name of the item which will serve as the input to the execution module. The final part is the requisite declaration which can be used to enforce dependencies. 

The require requisite:
The require requisite is useful in enforcing dependencies between states & an order of execution.
For example in the state file created earlier we can put a require dependency to ensure that the state responsible for starting the httpd service is executed only when the state responsible for installing the package is executed successfully.

make sure apache is running: 
 service.running:    
  - name: apache2    
  - enable: True    
  - require:      
    - pkg: install_apache

install_apache:  
 pkg.installed:    
 - name: apache


The watch requisite:
The watch requisite is similar to the require requisite such that the watching state gets executed only if the watched state gets successfully executed first.

The _in requisite:
This also sets a dependency but slightly differently. The common for of the _in requisite in require_in. Here is a example of how I modified the apache.sls state file to use require_in instead of the require requisite:

make sure apache is running: 
 service.running:    
  - name: apache2    
  - enable: True    

install_apache:  
 pkg.installed:    
 - name: apache
 - require_in:
   - service: make sure apache is running

The above code is functionally equivalent to the example described earlier using the require requisite.

No comments:

Post a Comment

Using capture groups in grep in Linux

Introduction Let me start by saying that this article isn't about capture groups in grep per se. What we are going to do here with gr...