<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: koh-sh</title>
    <description>The latest articles on DEV Community by koh-sh (@koh_sh).</description>
    <link>https://dev.to/koh_sh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F267546%2F961a9df9-a330-4281-9536-e4be6c37b3dd.png</url>
      <title>DEV Community: koh-sh</title>
      <link>https://dev.to/koh_sh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/koh_sh"/>
    <language>en</language>
    <item>
      <title>How to do "if a package is installed, do something" with Ansible</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Sun, 14 Jun 2020 14:45:16 +0000</pubDate>
      <link>https://dev.to/koh_sh/how-to-do-if-a-package-is-installed-do-something-with-ansible-3fhi</link>
      <guid>https://dev.to/koh_sh/how-to-do-if-a-package-is-installed-do-something-with-ansible-3fhi</guid>
      <description>&lt;p&gt;When you create Playbook, sometimes you may want to do these kinds of tasks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if a package is installed, do something&lt;/li&gt;
&lt;li&gt;if a user exists, do something&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To only check the existence of packages or users without actually installing them.&lt;br&gt;
For this kind of task, &lt;code&gt;command&lt;/code&gt; or &lt;code&gt;shell&lt;/code&gt; modules works fine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  tasks:
    - name: check &lt;span class="k"&gt;if &lt;/span&gt;httpd is installed
      shell: rpm &lt;span class="nt"&gt;-qa&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;httpd
      register: httpd_installed
      ignore_errors: True
      check_mode: False
      changed_when: False

    - name: print
      debug:
        msg: &lt;span class="s2"&gt;"httpd is installed"&lt;/span&gt;
      when: httpd_installed.rc &lt;span class="o"&gt;==&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this is a little bit of trouble when you use it many times.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extra parameters like &lt;code&gt;changed_when&lt;/code&gt; or &lt;code&gt;ignore_errors&lt;/code&gt; should be set &lt;/li&gt;
&lt;li&gt;Warnings may be thrown at running Playbook or ansible-lint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this article introduces some modules which can replace your command modules and make your Playbook simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Environment
&lt;/h2&gt;

&lt;p&gt;ansible: v2.9.9&lt;br&gt;&lt;br&gt;
targetOS: CentOS7.7 and Ubuntu 18.04&lt;/p&gt;
&lt;h2&gt;
  
  
  stat
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.ansible.com/ansible/latest/modules/stat_module.html"&gt;https://docs.ansible.com/ansible/latest/modules/stat_module.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;stat&lt;/code&gt; module gets info of files.&lt;br&gt;
Not only existence, it also checks file type(file/directory/link) or owner/group etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  tasks:
    - name: check if /etc/hosts exists
      stat:
        path: /etc/hosts
      register: etchosts

    - name: print
      debug:
        msg: "/etc/hosts exists"
      when: etchosts.stat.exists

    - name: print
      debug:
        msg: "/etc/hosts is directory"
      when: etchosts.stat.isdir # this should be False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  package_facts
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.ansible.com/ansible/latest/modules/package_facts_module.html"&gt;https://docs.ansible.com/ansible/latest/modules/package_facts_module.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;package_facts&lt;/code&gt; module gets installed packages list.&lt;br&gt;
The info is available with &lt;code&gt;ansible_facts.packages&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  tasks:
    - name: check packages
      package_facts:
        manager: auto

    - name: print
      debug:
        msg: "Version of NetworkManager is {{ ansible_facts.packages['NetworkManager'][0]['version'] }}"
      when: "'NetworkManager' in ansible_facts.packages"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  getent
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.ansible.com/ansible/latest/modules/getent_module.html"&gt;https://docs.ansible.com/ansible/latest/modules/getent_module.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;getent&lt;/code&gt; module is a wrapper of getent command and can get info from passwd or group.&lt;br&gt;
The info is available with &lt;code&gt;getent_***&lt;/code&gt; (*** is the name of database)&lt;br&gt;
*Available databases varies on each OS and version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  tasks:
    - name: check users
      getent:
        database: passwd

    - name: print
      debug:
        msg: "app1 user exists"
      when: "'app1' in getent_passwd"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  service_facts
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.ansible.com/ansible/latest/modules/service_facts_module.html"&gt;https://docs.ansible.com/ansible/latest/modules/service_facts_module.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;service_facts&lt;/code&gt; module get services list.&lt;br&gt;
The info is available with &lt;code&gt;ansible_facts.services&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  tasks:
    - name: check services
      service_facts:

    - name: print
      debug:
        msg: "firewalld is {{ ansible_facts.services['firewalld.service']['status'] }}"
      when: "'firewalld.service' in ansible_facts.services"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By using each module instead of command module makes your Playbooks simpler and more useful for multiple OSs.&lt;/p&gt;

</description>
      <category>ansible</category>
    </item>
    <item>
      <title>Connectivity check WITH Ansible</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Sat, 21 Dec 2019 14:39:23 +0000</pubDate>
      <link>https://dev.to/koh_sh/connectivity-check-with-ansible-1po</link>
      <guid>https://dev.to/koh_sh/connectivity-check-with-ansible-1po</guid>
      <description>&lt;p&gt;Using telnet or nc command to make sure DNS, routing and firewalls are set correctly is a kind of common use case for server engineers.&lt;br&gt;
But these commands are not always installed on servers, and they don't seem to be usable for Ansible.&lt;br&gt;
In this situation, &lt;code&gt;wait_for&lt;/code&gt; module is the right module to use.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is wait_for
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.ansible.com/ansible/latest/modules/wait_for_module.html"&gt;https://docs.ansible.com/ansible/latest/modules/wait_for_module.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Main use cases for this module are,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wait until a port becomes LISTEN state after starting&lt;/li&gt;
&lt;li&gt;wait for specific strings by tailing log files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if you use this module with a very short timeout, it works as a port-level connectivity check.&lt;/p&gt;
&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;※Version of Ansible is 2.9.0&lt;br&gt;
I created the below Playbook for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cat test.yml
---
- hosts: Vag1
  gather_facts: False
  tasks:
    - name: check if github.com:22 is accessible
      wait_for:
        host: github.com
        port: 22
        state: started
        delay: 0
        timeout: 1

    - name: check if 192.168.33.12:25 is accessible
      wait_for:
        host: 192.168.33.12
        port: 25
        state: started
        delay: 0
        timeout: 1
        search_regex: Postfix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;checking access to github.com with 22 port at the 1st task&lt;/li&gt;
&lt;li&gt;checking access to 192.168.33.12 with 25 port and weather the string "Postfix" is shown at the 2nd task&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Executing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% ansible-playbook test.yml

PLAY [Vag1] *****************************************************************************************

TASK [check if github.com:22 is accessible] *********************************************************
ok: [Vag1]

TASK [check if 192.168.33.12:25 is accessible] ******************************************************
ok: [Vag1]

PLAY RECAP ******************************************************************************************
Vag1                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the destinations are accessible, its result should be &lt;code&gt;ok&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, I tried blocking accesses at 192.168.33.12 with firewalld.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[vagrant@Vag2] ~
% hostname -I 
10.0.2.15 192.168.33.12
[vagrant@Vag2] ~
% sudo systemctl start firewalld
[vagrant@Vag2] ~
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tried again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% ansible-playbook test.yml

PLAY [Vag1] *****************************************************************************************

TASK [check if github.com:22 is accessible] *********************************************************
ok: [Vag1]

TASK [check if 192.168.33.12:25 is accessible] ******************************************************
fatal: [Vag1]: FAILED! =&amp;gt; {"changed": false, "elapsed": 1, "msg": "Timeout when waiting for search string Postfix in 192.168.33.12:25"}

PLAY RECAP ******************************************************************************************
Vag1                       : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

zsh: exit 2     ansible-playbook test.yml
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An error is thrown and you can see you couldn't access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Googling &lt;code&gt;Ansible connectivity check&lt;/code&gt; always returns about connectivity between a play node and target node, so it is kind of hard to find out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ref
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://devops.stackexchange.com/questions/1658/ansible-other-option-available-for-telnet-check-of-open-ports"&gt;https://devops.stackexchange.com/questions/1658/ansible-other-option-available-for-telnet-check-of-open-ports&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ansible</category>
    </item>
    <item>
      <title>Configuration of ansible-lint</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Sun, 17 Nov 2019 14:27:54 +0000</pubDate>
      <link>https://dev.to/koh_sh/configuration-of-ansible-lint-5fgl</link>
      <guid>https://dev.to/koh_sh/configuration-of-ansible-lint-5fgl</guid>
      <description>&lt;p&gt;ansible-lint is a tool to check Ansible Playbook.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ansible" rel="noopener noreferrer"&gt;
        ansible
      &lt;/a&gt; / &lt;a href="https://github.com/ansible/ansible-lint" rel="noopener noreferrer"&gt;
        ansible-lint
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      ansible-lint checks playbooks for practices and behavior that could potentially be improved and can fix some of the most common ones for you
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://pypi.org/project/ansible-lint" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9858e8fd1c8ac375338ff62ee4486bc714070a1f51332942a733524b380aeee1/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f616e7369626c652d6c696e742e737667" alt="PyPI version"&gt;&lt;/a&gt;
&lt;a href="https://ansible.readthedocs.io/projects/lint/rules/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f71fabd252201d65b87548f2fd4f539781ee0e8fe0f494e7d9a9ca4cd84ef7cf/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f416e7369626c652d2d6c696e742d72756c65732d626c75652e737667" alt="Ansible-lint rules explanation"&gt;&lt;/a&gt;
&lt;a href="https://forum.ansible.com/tag/ansible-lint" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7e28b31eb97231f475dae52503c64f28ef7f68035ed6e86ecae2deeb3b4d4972/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f44697363757373696f6e732d677261792e737667" alt="Discussions"&gt;&lt;/a&gt;
&lt;a href="https://github.com/pre-commit/pre-commit" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c8dfc1d0c35fe0cc438cf57a44b9d915e0baa2aef9da75d07ad3ee2cdb237214/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7072652d2d636f6d6d69742d656e61626c65642d627269676874677265656e3f6c6f676f3d7072652d636f6d6d6974266c6f676f436f6c6f723d7768697465" alt="pre-commit"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Ansible-lint&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;ansible-lint&lt;/code&gt; checks playbooks for practices and behavior that could
potentially be improved. As a community-backed project ansible-lint supports
only the last two major versions of Ansible.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://ansible.readthedocs.io/projects/lint/" rel="nofollow noopener noreferrer"&gt;Visit the Ansible Lint docs site&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Using ansible-lint as a GitHub Action&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This action allows you to run &lt;code&gt;ansible-lint&lt;/code&gt; on your codebase without having to
install it yourself.&lt;/p&gt;
&lt;div class="highlight highlight-source-yaml notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; .github/workflows/ansible-lint.yml&lt;/span&gt;
&lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;ansible-lint&lt;/span&gt;
&lt;span class="pl-ent"&gt;on&lt;/span&gt;:
  &lt;span class="pl-ent"&gt;pull_request&lt;/span&gt;:
    &lt;span class="pl-ent"&gt;branches&lt;/span&gt;: &lt;span class="pl-s"&gt;["main", "stable", "release/v*"]&lt;/span&gt;
&lt;span class="pl-ent"&gt;jobs&lt;/span&gt;:
  &lt;span class="pl-ent"&gt;build&lt;/span&gt;:
    &lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;Ansible Lint &lt;/span&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Naming the build is important to use it as a status check&lt;/span&gt;
    &lt;span class="pl-ent"&gt;runs-on&lt;/span&gt;: &lt;span class="pl-s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="pl-ent"&gt;steps&lt;/span&gt;:
      - &lt;span class="pl-ent"&gt;uses&lt;/span&gt;: &lt;span class="pl-s"&gt;actions/checkout@v4&lt;/span&gt;
      - &lt;span class="pl-ent"&gt;name&lt;/span&gt;: &lt;span class="pl-s"&gt;Run ansible-lint&lt;/span&gt;
        &lt;span class="pl-ent"&gt;uses&lt;/span&gt;: &lt;span class="pl-s"&gt;ansible/ansible-lint@main&lt;/span&gt;
        &lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; optional (see below):&lt;/span&gt;
        &lt;span class="pl-ent"&gt;with&lt;/span&gt;:
          &lt;span class="pl-ent"&gt;args&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
          &lt;span class="pl-ent"&gt;setup_python&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;true&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
          &lt;span class="pl-ent"&gt;working_directory&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
          &lt;span class="pl-ent"&gt;requirements_file&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;All the arguments are optional and most users should not need them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;args&lt;/code&gt;: Arguments to be passed to ansible-lint…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ansible/ansible-lint" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;It helps you to find syntax problems like extra spaces or lines, or point out where doesn't follow Ansible best practice. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[201] Trailing whitespace
site.yml:6
        msg: hello

[403] Package installs should not use latest
site.yml:8
Task/Handler: install httpd

[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Below is the list of default rules.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.ansible.com/ansible-lint/rules/default_rules.html" rel="noopener noreferrer"&gt;https://docs.ansible.com/ansible-lint/rules/default_rules.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But each playbook or teams might have their own rules that oppose to Ansible best practice.&lt;/p&gt;

&lt;p&gt;Here is how to configure ansible-lint. &lt;br&gt;
*Version of ansible-lint is &lt;code&gt;4.1.0&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Config with command line options
&lt;/h2&gt;

&lt;p&gt;Rules are configurable with options of ansible-lint command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[koh@kohs-MBP] ~/work/linttest
% ansible-lint --help
Usage: ansible-lint [options] playbook.yml [playbook2 ...]

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -L                    list all the rules
  -q                    quieter, although not silent output
  -p                    parseable output in the format of pep8
  --parseable-severity  parseable output including severity of rule
  -r RULESDIR           specify one or more rules directories using one or
                        more -r arguments. Any -r flags override the default
                        rules in
                        /Users/koh/.pyenv/versions/3.7.3/lib/python3.7/site-
                        packages/ansiblelint/rules, unless -R is also used.
  -R                    Use default rules in
                        /Users/koh/.pyenv/versions/3.7.3/lib/python3.7/site-
                        packages/ansiblelint/rules in addition to any extra
                        rules directories specified with -r. There is no need
                        to specify this if no -r flags are used
  -t TAGS               only check rules whose id/tags match these values
  -T                    list all the tags
  -v                    Increase verbosity level
  -x SKIP_LIST          only check rules whose id/tags do not match these
                        values
  --nocolor             disable colored output
  --force-color         Try force colored output (relying on ansible's code)
  --exclude=EXCLUDE_PATHS
                        path to directories or files to skip. This option is
                        repeatable.
  -c C                  Specify configuration file to use.  Defaults to
                        ".ansible-lint"
[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Basically, you can configure everything with command line options but it is better to use a configuration file to share with your team, or to implement into CI.&lt;/p&gt;

&lt;p&gt;Next is how to configure with a file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration file
&lt;/h2&gt;

&lt;p&gt;It should be placed at &lt;code&gt;./.ansible-lint&lt;/code&gt; by default, or a file which specified with the ​option &lt;code&gt;-c&lt;/code&gt;.&lt;br&gt;
This is an example from the official doc.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

exclude_paths:
  - ./my/excluded/directory/
  - ./my/other/excluded/directory/
  - ./last/excluded/directory/
parseable: true
quiet: true
rulesdir:
  - ./rule/directory/
skip_list:
  - skip_this_tag
  - and_this_one_too
  - skip_this_id
  - '401'
tags:
  - run_this_tag
use_default_rules: true
verbosity: 1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://docs.ansible.com/ansible-lint/configuring/configuring.html#configuration-file" rel="noopener noreferrer"&gt;https://docs.ansible.com/ansible-lint/configuring/configuring.html#configuration-file&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  exclude_paths (--exclude)
&lt;/h3&gt;

&lt;p&gt;Specify paths or files to exclude from lint.&lt;/p&gt;

&lt;h3&gt;
  
  
  parseable (-p)
&lt;/h3&gt;

&lt;p&gt;Change the format of the output.&lt;br&gt;
Each error will be converted to one line.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# parseable: false

[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[201] Trailing whitespace
/Users/koh/work/linttest/roles/201/tasks/main.yml:4
    msg: hello

[202] Octal file permissions must contain leading zero or be a string
/Users/koh/work/linttest/roles/202/tasks/main.yml:2
Task/Handler: error 202

[203] Most files should not contain tabs
/Users/koh/work/linttest/roles/203/tasks/main.yml:4
    msg: "     tab"

[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# parseable: true

[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
/Users/koh/work/linttest/roles/201/tasks/main.yml:4: [E201] Trailing whitespace
/Users/koh/work/linttest/roles/202/tasks/main.yml:2: [E202] Octal file permissions must contain leading zero or be a string
/Users/koh/work/linttest/roles/203/tasks/main.yml:4: [E203] Most files should not contain tabs
[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  quiet (-q)
&lt;/h3&gt;

&lt;p&gt;Reduce output.&lt;br&gt;
Not completely 0 but a bit reduced.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# quiet: true

[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[201] /Users/koh/work/linttest/roles/201/tasks/main.yml:4
[202] /Users/koh/work/linttest/roles/202/tasks/main.yml:2
[203] /Users/koh/work/linttest/roles/203/tasks/main.yml:4
[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  rulesdir (-r)
&lt;/h3&gt;

&lt;p&gt;Specify files or directories in which you put original rule files.&lt;/p&gt;
&lt;h3&gt;
  
  
  skip_list (-x)
&lt;/h3&gt;

&lt;p&gt;Specify tags or error IDs that should be skipped.&lt;br&gt;
You can check about tags with &lt;code&gt;-T&lt;/code&gt; option.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[koh@kohs-MBP] ~/work/linttest
% ansible-lint -T
ANSIBLE0002 ['[201]']
ANSIBLE0004 ['[401]']
ANSIBLE0005 ['[402]']
ANSIBLE0006 ['[303]']
ANSIBLE0007 ['[302]']
ANSIBLE0008 ['[103]']
ANSIBLE0009 ['[202]']
ANSIBLE0010 ['[403]']
ANSIBLE0011 ['[502]']
ANSIBLE0012 ['[301]']
ANSIBLE0013 ['[305]']
ANSIBLE0014 ['[304]']
ANSIBLE0015 ['[104]']
ANSIBLE0016 ['[503]']
ANSIBLE0017 ['[501]']
ANSIBLE0018 ['[101]']
ANSIBLE0019 ['[102]']
behaviour ['[503]']
bug ['[304]']
command-shell ['[305]', '[302]', '[304]', '[306]', '[301]', '[303]']
deprecated ['[105]', '[104]', '[103]', '[101]', '[102]']
formatting ['[104]', '[203]', '[201]', '[204]', '[206]', '[205]', '[202]']
idempotency ['[301]']
idiom ['[601]', '[602]']
metadata ['[701]', '[704]', '[703]', '[702]']
module ['[404]', '[401]', '[403]', '[402]']
oddity ['[501]']
readability ['[502]']
repeatability ['[401]', '[403]', '[402]']
resources ['[302]', '[303]']
safety ['[305]']
task ['[502]', '[503]', '[504]', '[501]']
[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  tags (-t)
&lt;/h3&gt;

&lt;p&gt;Opposite of skip_list, specify tags that you want to check.&lt;/p&gt;
&lt;h3&gt;
  
  
  use_default_rules (-R)
&lt;/h3&gt;

&lt;p&gt;If True, default rules are applied.&lt;br&gt;
If you want to check only your original rules, set it to False.&lt;/p&gt;
&lt;h3&gt;
  
  
  verbosity (-v)
&lt;/h3&gt;

&lt;p&gt;Specify the verbosity of the output.&lt;br&gt;
It only takes 2 kinds of values which are 0 or greater than 0.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

        for file in files:
            if self.verbosity &amp;gt; 0:
                print("Examining %s of type %s" % (file['path'], file['type']))
            matches.extend(self.rules.run(file, tags=set(self.tags),
                           skip_list=self.skip_list))


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/ansible/ansible-lint/blob/5170c04201e71400421b27255280902c211f8548/lib/ansiblelint/__init__.py#L281" rel="noopener noreferrer"&gt;https://github.com/ansible/ansible-lint/blob/5170c04201e71400421b27255280902c211f8548/lib/ansiblelint/__init__.py#L281&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure inside Playbook
&lt;/h2&gt;

&lt;p&gt;By adding a comment, you can skip checks by lines.&lt;/p&gt;

&lt;p&gt;Below is an example of the Playbook.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[koh@kohs-MBP] ~/work/linttest
% cat site.yml
---
- hosts: all
  tasks:
    - name: install latest httpd
      yum:
        name: httpd
        state: latest

    - name: install mysql
      yum:
        name: mysql
        state: installed
[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This playbook throws 403 error.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[403] Package installs should not use latest
site.yml:4
Task/Handler: install latest httpd

[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you really want to keep your httpd updated but not other packages, you can do like below. (you still should not do that though.)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[koh@kohs-MBP] ~/work/linttest
% cat site.yml
---
- hosts: all
  tasks:
    - name: install latest httpd
      yum:
        name: httpd
        state: latest # noqa 403

    - name: install mysql
      yum:
        name: mysql
        state: installed
[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By adding &lt;code&gt;# noqa ID&lt;/code&gt;, the line will be skipped from checks.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Original rules
&lt;/h2&gt;

&lt;p&gt;You can create your own rules.&lt;br&gt;
There are some explanations on README and also I recommend you to have a look at scripts of the default rules.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ansible/ansible-lint#creating-custom-rules" rel="noopener noreferrer"&gt;https://github.com/ansible/ansible-lint#creating-custom-rules&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ansible/ansible-lint/tree/master/lib/ansiblelint/rules" rel="noopener noreferrer"&gt;https://github.com/ansible/ansible-lint/tree/master/lib/ansiblelint/rules&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is my example of how to create my own rule.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[koh@kohs-MBP] ~/work/linttest
% cat origrules/True4BooleanRule.py
from ansiblelint import AnsibleLintRule


class True4BooleanRule(AnsibleLintRule):
    id = '99'
    shortdesc = 'Use "True" for boolean'
    description = 'We should "True" for boolean not "yes" or "true".'
    tags = ['formatting']

    def match(self, file, line):
        return ': yes' in line or ': true' in line
[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Playbook can take &lt;code&gt;yes&lt;/code&gt; , &lt;code&gt;true&lt;/code&gt; to set &lt;code&gt;True&lt;/code&gt; for boolean.&lt;br&gt;
With this rule, it throws errors if &lt;code&gt;yes&lt;/code&gt; or  &lt;code&gt;true&lt;/code&gt; are used.&lt;br&gt;
*This is a really cheap script only for this explanation please use it with your own risk.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;.ansible-lint&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[koh@kohs-MBP] ~/work/linttest
% cat .ansible-lint
rulesdir:
  - ./origrules/
[koh@kohs-MBP] ~/work/linttest
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With this site.yml, it throws 2 errors as intended.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;[koh@kohs-MBP] ~/work/linttest&lt;/p&gt;
&lt;h2&gt;
  
  
  % cat site.yml
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;hosts: all&lt;br&gt;
tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name: this should be error
service:
name: httpd
state: started
enabled: yes&lt;/li&gt;
&lt;li&gt;name: this should be error too
service:
name: mysqld
state: started
enabled: true&lt;/li&gt;
&lt;li&gt;name: this is ok
service:
name: haproxy
state: started
enabled: True
[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[99] Use "True" for boolean
site.yml:8
enabled: yes&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[99] Use "True" for boolean&lt;br&gt;
site.yml:14&lt;br&gt;
        enabled: true&lt;/p&gt;

&lt;p&gt;[koh@kohs-MBP] ~/work/linttest&lt;br&gt;
%&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Creating own rules is much easier than I expected.&lt;br&gt;
So it is good to try one.&lt;/p&gt;

</description>
      <category>ansible</category>
    </item>
    <item>
      <title>Using Testinfra with Ansible</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Sun, 10 Nov 2019 06:38:31 +0000</pubDate>
      <link>https://dev.to/koh_sh/using-testinfra-with-ansible-4n7b</link>
      <guid>https://dev.to/koh_sh/using-testinfra-with-ansible-4n7b</guid>
      <description>&lt;p&gt;Testinfra which tests infrastructure works really well with Ansible.&lt;br&gt;
I posted about Testinfra previously so please check if you like.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/koh_sh" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tspPSyIl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--jOnNmmN0--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/267546/961a9df9-a330-4281-9536-e4be6c37b3dd.png" alt="koh_sh"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/koh_sh/play-with-testinfra-which-tests-states-of-infrastructure-1bl2" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Play with Testinfra which tests states of infrastructure&lt;/h2&gt;
      &lt;h3&gt;koh-sh ・ Nov 9 '19 ・ 4 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#python&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#linux&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Sharing Inventory
&lt;/h2&gt;

&lt;p&gt;Testinfra can refer to Inventories of Ansible.&lt;br&gt;
So you don't have to re-define hosts information for Ansible and tests too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://testinfra.readthedocs.io/en/latest/backends.html#ansible"&gt;https://testinfra.readthedocs.io/en/latest/backends.html#ansible&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ py.test --hosts='ansible://all' # tests all inventory hosts
$ py.test --hosts='ansible://host1,ansible://host2'
$ py.test --hosts='ansible://web*'
$ py.test --force-ansible --hosts='ansible://all'
$ py.test --hosts='ansible://host?force_ansible=True'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the inventory file is not specified with &lt;code&gt;ansible.cfg&lt;/code&gt;, you can specify with &lt;code&gt;--ansible-inventory=ANSIBLE_INVENTORY&lt;/code&gt; in command lines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing modules of Ansible
&lt;/h2&gt;

&lt;p&gt;You can execute modules of Ansible while testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://testinfra.readthedocs.io/en/latest/modules.html#ansible"&gt;https://testinfra.readthedocs.io/en/latest/modules.html#ansible&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% ipython
Python 3.7.3 (default, May  1 2019, 16:07:48)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.5.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import testinfra

In [2]: host = testinfra.get_host("ansible://Vag1")

In [3]: host.ansible("command", "echo foo", check=False)
Out[3]:
{'ansible_facts': {'discovered_interpreter_python': '/usr/bin/python'},
 'changed': True,
 'cmd': ['echo', 'foo'],
 'delta': '0:00:00.004734',
 'end': '2019-10-05 15:07:42.251008',
 'rc': 0,
 'start': '2019-10-05 15:07:42.246274',
 'stderr': '',
 'stderr_lines': [],
 'stdout': 'foo',
 'stdout_lines': ['foo']}

In [4]:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an example of executing command module of Ansible with Testinfra.&lt;br&gt;&lt;br&gt;
As a result of executing a module, you can get like &lt;code&gt;changed&lt;/code&gt;, &lt;code&gt;rc&lt;/code&gt; or &lt;code&gt;stdout&lt;/code&gt; same as Ansible.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;setup&lt;/code&gt; module would fit well with testing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% cat test_ansible.py
def test_dns(host):
    nameservers = host.ansible("setup")["ansible_facts"]["ansible_dns"]["nameservers"]
    assert '10.1.1.1' in nameservers
[koh@kohs-MBP] ~/vag_test
% 
[koh@kohs-MBP] ~/vag_test
% py.test -v test_ansible.py --hosts='ansible://Vag1'
======================================== test session starts ========================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.9.0 -- /Users/koh/.pyenv/versions/3.7.3/bin/python3.7
cachedir: .pytest_cache
rootdir: /Users/koh/vag_test, inifile: pytest.ini
plugins: xonsh-0.8.12, testinfra-3.0.5
collected 1 item

test_ansible.py::test_dns[ansible://Vag1] FAILED                                              [100%]

============================================= FAILURES ==============================================
_____________________________________ test_dns[ansible://Vag1] ______________________________________

host = &amp;lt;testinfra.host.Host object at 0x10e9be748&amp;gt;

    def test_dns(host):
        nameservers = host.ansible("setup")["ansible_facts"]["ansible_dns"]["nameservers"]
&amp;gt;       assert '10.1.1.1' in nameservers
E       AssertionError: assert '10.1.1.1' in ['10.0.2.3']

test_ansible.py:3: AssertionError
===================================== 1 failed in 2.17 seconds ======================================
zsh: exit 1     py.test -v test_ansible.py --hosts='ansible://Vag1'
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an example of checking nameserver of resolv.conf with setup module.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refering Variable
&lt;/h2&gt;

&lt;p&gt;You can refer to variables of Ansible.&lt;br&gt;
&lt;code&gt;host_vars&lt;/code&gt;, &lt;code&gt;group_vars&lt;/code&gt; and magic variables like &lt;code&gt;inventory_hostname&lt;/code&gt; can be referred from Testinfra.&lt;br&gt;
Variables defined with &lt;code&gt;include_vars&lt;/code&gt; in Playbooks cannot be referred.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% ipython
Python 3.7.3 (default, May  1 2019, 16:07:48)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.5.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import testinfra

In [2]: host = testinfra.get_host("ansible://Vag1")

In [3]: host.ansible.get_variables()
Out[3]:
{'aaa': 'bbb',
 'foo': 'bar',
 'hoge': 'fuga',
 'inventory_hostname': 'Vag1',
 'group_names': ['Vag'],
 'groups': {'Vag': ['Vag1', 'Vag2', 'Vag3'], 'all': ['Vag1', 'Vag2', 'Vag3']}}

In [4]:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As currently, Molecule use Testinfra as the default test tool, Testinfra works really well with Ansible.&lt;br&gt;
Testinfra can be used with Docker or Kubernetes too, so I would keep trying them out.&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>testing</category>
      <category>python</category>
    </item>
    <item>
      <title>Automatic ansible-lint with Github Actions</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Sat, 09 Nov 2019 15:45:45 +0000</pubDate>
      <link>https://dev.to/koh_sh/automatic-ansible-lint-with-github-actions-52oe</link>
      <guid>https://dev.to/koh_sh/automatic-ansible-lint-with-github-actions-52oe</guid>
      <description>&lt;p&gt;Now my account has access to &lt;a href="https://github.com/features/actions"&gt;Github Actions&lt;/a&gt; beta so I am trying to use it for syntax check and run ansible-lint for my Ansible playbook repository.&lt;br&gt;
This article is based on the specification of Github Actions on 7th Sep 2019.&lt;/p&gt;
&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;I referred to the official doc for setting up.&lt;br&gt;
&lt;a href="https://help.github.com/en/categories/automating-your-workflow-with-github-actions"&gt;https://help.github.com/en/categories/automating-your-workflow-with-github-actions&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Until the first run
&lt;/h3&gt;

&lt;p&gt;This time I use my repository which has Ansible Playbook to set up my MacBook.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/koh-sh"&gt;
        koh-sh
      &lt;/a&gt; / &lt;a href="https://github.com/koh-sh/macbook-playbook"&gt;
        macbook-playbook
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      ansible playbook to setup macbook
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
macbook-playbook&lt;/h1&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/koh-sh/macbook-playbook/workflows/Ansible%20test/badge.svg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dHv24EFa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/koh-sh/macbook-playbook/workflows/Ansible%2520test/badge.svg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ansible playbook to setup macbook&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/koh-sh/macbook-playbook"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Clicking Actions tab which is newly added.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pbtfYO2P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3jwfpoxl5n4h12na6cko.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pbtfYO2P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3jwfpoxl5n4h12na6cko.png" alt="Alt Text" width="880" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use many templates of workflow provided by Github and I am using &lt;code&gt;python package&lt;/code&gt;.&lt;br&gt;
After clicking the template, you can modify the workflow template for your repo.&lt;br&gt;
I edited the file like below. (I also changed the name of the file too)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Ansible lint

  on: [push]

  jobs:
   build:

      runs-on: macOS-latest
     strategy:
       max-parallel: 4
       matrix:
         python-version: [2.7, 3.5, 3.6, 3.7]

      steps:
     - uses: actions/checkout@v1
     - name: Set up Python ${{ matrix.python-version }}
       uses: actions/setup-python@v1
       with:
         python-version: ${{ matrix.python-version }}
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
         pip install ansible ansible-lint
     - name: Lint playbook
       run: |
         ansible-playbook site.yml --syntax-check
         ansible-lint site.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The Playbook is for macOS, so I changed &lt;code&gt;runs-on&lt;/code&gt; to macOS-latest.&lt;br&gt;&lt;br&gt;
Below tasks are supposed to run.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install ansible and ansible-lint with pip&lt;/li&gt;
&lt;li&gt;run ansible-playbook with --syntax-check option&lt;/li&gt;
&lt;li&gt;run ansible-lint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After committing this file, tests were run automatically.&lt;br&gt;&lt;br&gt;
You can see the result at Actions tab.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BOwzV_2g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7j5ezx84xg73n8sfoatf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BOwzV_2g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7j5ezx84xg73n8sfoatf.png" alt="Alt Text" width="880" height="489"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/koh-sh/macbook-playbook/commit/3daeb98a056981335938e74c530ebb5f6ae1f6e3/checks"&gt;https://github.com/koh-sh/macbook-playbook/commit/3daeb98a056981335938e74c530ebb5f6ae1f6e3/checks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The number of &lt;code&gt;python-version&lt;/code&gt; is 4 and &lt;code&gt;max-parallel&lt;/code&gt; is 4 too so 4 tests were run concurrently.&lt;br&gt;
You can refer to the official doc about the limit of resources.&lt;br&gt;
&lt;a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#usage-limits"&gt;https://help.github.com/en/articles/workflow-syntax-for-github-actions#usage-limits&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can click each version of builds for details.&lt;br&gt;
This time ansible-lint threw some errors so the status is failed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Until test success
&lt;/h3&gt;

&lt;p&gt;ansible-lint threw errors so fixing with this commit.&lt;br&gt;
Removing trailing space and omit the error about shell modules with .ansible-lint file as I needed them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/koh-sh/macbook-playbook/commit/577519c6213c4a1e7a3c047808ef146ca2d67f86"&gt;https://github.com/koh-sh/macbook-playbook/commit/577519c6213c4a1e7a3c047808ef146ca2d67f86&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I pushed to the master branch and the tests run automatically.&lt;br&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vPWUwms9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kgbmxhvesjgnz1dk3qo2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vPWUwms9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kgbmxhvesjgnz1dk3qo2.png" alt="Alt Text" width="880" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/koh-sh/macbook-playbook/commit/577519c6213c4a1e7a3c047808ef146ca2d67f86/checks"&gt;https://github.com/koh-sh/macbook-playbook/commit/577519c6213c4a1e7a3c047808ef146ca2d67f86/checks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tests are completed without problems.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m-przT4M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/xmv68ix5hp917rzxn5w7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m-przT4M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/xmv68ix5hp917rzxn5w7.png" alt="Alt Text" width="880" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, you can see the results of tests for each commit with symbols.&lt;/p&gt;
&lt;h3&gt;
  
  
  Trying Pull Requests
&lt;/h3&gt;

&lt;p&gt;How about pull requests?&lt;br&gt;
Let's see how they work.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/koh-sh/macbook-playbook/pull/1"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg"&gt;
      &lt;span class="issue-title"&gt;
        to trigger github actions test
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#1&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/koh-sh"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--_rBDi1DE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars0.githubusercontent.com/u/34917718%3Fv%3D4" alt="koh-sh avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/koh-sh"&gt;koh-sh&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/koh-sh/macbook-playbook/pull/1"&gt;&lt;time&gt;Sep 07, 2019&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;This is test PR to trigger Github actions test&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/koh-sh/macbook-playbook/pull/1"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;By opening a pull request, tests run automatically and the results are available at PR summary.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0PuOrc8C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/cr65dm0pm3kwxpsljfyd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0PuOrc8C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/cr65dm0pm3kwxpsljfyd.png" alt="Alt Text" width="880" height="711"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this repository is integrated into my slack workspace and the result was notified too.&lt;br&gt;
&lt;a href="https://slack.github.com"&gt;https://slack.github.com&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gEHf6Ovo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uhyegnl7oympon5sogtd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gEHf6Ovo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/uhyegnl7oympon5sogtd.png" alt="Alt Text" width="880" height="641"&gt;&lt;/a&gt;&lt;br&gt;
But when I pushed to master, the test result was not notified.&lt;br&gt;
Another setting might be necessary but I haven't checked yet.&lt;/p&gt;
&lt;h3&gt;
  
  
  Testing with multiple version of Ansible
&lt;/h3&gt;

&lt;p&gt;Currently, these tests are run with the latest version of Ansible and 4 versions of python.&lt;br&gt;
Let's change it to 2.7.x, 2.8.x of Ansible and 2.x and 3.x of python matrix.&lt;/p&gt;

&lt;p&gt;I modified the workflow file as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Ansible lint

on: [push]

jobs:
  build:

    runs-on: macOS-latest
    strategy:
      max-parallel: 4
      matrix:
        python-version: [2.7, 3.7]
        ansible-version: [2.7.13, 2.8.4]

    steps:
    - uses: actions/checkout@v1
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v1
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install Ansible ${{ matrix.ansible-version }}
      run: |
        python -m pip install --upgrade pip
        pip install ansible-lint ansible==${{ matrix.ansible-version }}
    - name: Lint playbook
      run: |
        ansible-playbook site.yml --syntax-check
        ansible-lint site.yml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a push, the test setting was updated and run as I intended.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l1kF7vDD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3r8irds6o0cokepf7rvk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l1kF7vDD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3r8irds6o0cokepf7rvk.png" alt="Alt Text" width="880" height="484"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/koh-sh/macbook-playbook/commit/0ffab4e73391ab8f3d39d5c149307bab9c06714f/checks"&gt;https://github.com/koh-sh/macbook-playbook/commit/0ffab4e73391ab8f3d39d5c149307bab9c06714f/checks&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With Github Actions, I can ansible-lint automatically for each commit.&lt;br&gt;
All of the settings in this article took only 1 hour since these are very simple and easy to use.&lt;br&gt;
Also, Github Actions are available not only tests but also deploys too so I will keep trying them out.&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>github</category>
    </item>
    <item>
      <title>How to check if an IP address is within a range in Ansible Playbook</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Sat, 09 Nov 2019 14:59:08 +0000</pubDate>
      <link>https://dev.to/koh_sh/how-to-check-if-an-ip-address-is-within-a-range-in-ansible-playbook-3307</link>
      <guid>https://dev.to/koh_sh/how-to-check-if-an-ip-address-is-within-a-range-in-ansible-playbook-3307</guid>
      <description>&lt;p&gt;I was trying to have tasks for each site and multiple regions in Cloud respectively.&lt;br&gt;
My idea was to use the IP address to determine where the host is, but it was kind of struggling to create the condition.&lt;br&gt;
So here is my memo down below.&lt;/p&gt;
&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;This when statement checks if the IP address is within the specified range.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: test
  debug:
    msg: work
  when: ansible_default_ipv4.address | ipaddr('10.0.2.0/24') | ipaddr('bool')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This task prints "work" if ansible_default_ipv4.address is within 10.0.2.0/24&lt;/p&gt;

&lt;h2&gt;
  
  
  Explanation
&lt;/h2&gt;

&lt;p&gt;I am using ipaddr filter&lt;br&gt;
&lt;a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters_ipaddr.html"&gt;https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters_ipaddr.html&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  First half
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[IP list] | ipaddr('172.30.0.0/16')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Above syntax extracts IP addresses in [IP list] which is within 172.30.0.0/16&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cat test.yml
---
- hosts: Vag1
  gather_facts: True
  tasks:
    - set_fact:
        testip:
          - "192.168.1.2"
          - "10.0.2.15"

    - name: test
      debug:
        msg: "{{ testip | ipaddr('10.0.2.0/24') }}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By Running test.yml above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MacBook-Pro] ~/vag_test
% ansible-playbook test.yml
PLAY [Vag1] ***************************************************************************************************************************

TASK [set_fact] ***********************************************************************************************************************
ok: [Vag1]

TASK [test] ***************************************************************************************************************************
ok: [Vag1] =&amp;gt; {
    "msg": [
        "10.0.2.15"
    ]
}

PLAY RECAP ****************************************************************************************************************************
Vag1                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[koh@kohs-MacBook-Pro] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are 2 IPs in testip and only 10.0.2.15 was printed since it is within 10.0.2.0/24&lt;/p&gt;

&lt;h3&gt;
  
  
  The second half
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[IP address] | ipaddr('bool')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns True if [IP address] is a valid IP address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cat test2.yml
---
- hosts: Vag1
  gather_facts: True
  tasks:
    - set_fact:
        testip:
          - "192.168.1.2"
          - "10.0.2.15.14.22"
          - "hogehoge"
          - ""

    - name: test
      debug:
        msg: "{{ item | ipaddr('bool')  }}"
      with_items: "{{ testip }}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By Running test2.yml above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MacBook-Pro] ~/vag_test
% ansible-playbook test2.yml

PLAY [Vag1] ****************************************************************************************************************************

TASK [set_fact] ****************************************************************************************************************************
ok: [Vag1]

TASK [test] ****************************************************************************************************************************
ok: [Vag1] =&amp;gt; (item=192.168.1.2) =&amp;gt; {
    "msg": true
}
ok: [Vag1] =&amp;gt; (item=10.0.2.15.14.22) =&amp;gt; {
    "msg": false
}
ok: [Vag1] =&amp;gt; (item=hogehoge) =&amp;gt; {
    "msg": false
}
ok: [Vag1] =&amp;gt; (item=) =&amp;gt; {
    "msg": false
}

PLAY RECAP ****************************************************************************************************************************
Vag1                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

[koh@kohs-MacBook-Pro] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these 2 syntaxes, you can check if an IP address of hosts is within a range automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/38725204/regular-expression-matching-for-ip-range-in-ansible-playbooks-for-grouping"&gt;https://stackoverflow.com/questions/38725204/regular-expression-matching-for-ip-range-in-ansible-playbooks-for-grouping&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ansible</category>
    </item>
    <item>
      <title>Redis can make Ansible only a bit faster</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Sat, 09 Nov 2019 14:27:26 +0000</pubDate>
      <link>https://dev.to/koh_sh/redis-can-make-ansible-only-a-bit-faster-39g7</link>
      <guid>https://dev.to/koh_sh/redis-can-make-ansible-only-a-bit-faster-39g7</guid>
      <description>&lt;p&gt;Ansible has a function called "Gather Facts" which retrieves variables from target hosts.&lt;br&gt;
By default, the facts are cached in memory and gathered every time you run Playbook.&lt;br&gt;
Usually, it takes only a few seconds but I know some people get annoyed by it.&lt;/p&gt;

&lt;p&gt;So in this post, I will try to avoid the struggles with Redis instead of memory.&lt;/p&gt;
&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;

&lt;p&gt;Local Machine: MacOS Mojave 10.14.5&lt;br&gt;
Target Host: CentOS 7.5 on Vagrant&lt;br&gt;
Ansible: 2.8.1&lt;br&gt;
Redis: 5.0.5&lt;/p&gt;
&lt;h3&gt;
  
  
  Redis
&lt;/h3&gt;

&lt;p&gt;It is only a test so I am using docker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% docker run -d -p 6379:6379 --name ansibleredis redis
Unable to find image 'redis:latest' locally
latest: Pulling from library/redis
f5d23c7fed46: Pull complete
a4a5c04dafc1: Pull complete
605bafc84bc9: Pull complete
f07a4e35cd96: Pull complete
17944e5e3eb7: Pull complete
6f875a8605e0: Pull complete
Digest: sha256:8888f6cd2509062a377e903e17777b4a6d59c92769f6807f034fa345da9eebcf
Status: Downloaded newer image for redis:latest
cbb0b15a703b2044b8a3d0d7b5b58f6dbd8d0b09d7b16bb5560cec57a221c39e
[koh@kohs-MBP] ~/vag_test
% docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
cbb0b15a703b        redis               "docker-entrypoint.s…"   8 seconds ago       Up 7 seconds        0.0.0.0:6379-&amp;gt;6379/tcp   ansibleredis
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. Docker is awesome as you know.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Ansible
&lt;/h3&gt;

&lt;p&gt;Using the official document as a reference, I added the below entries to ansible.cfg.&lt;br&gt;
&lt;a href="https://docs.ansible.com/ansible/latest/plugins/cache.html"&gt;https://docs.ansible.com/ansible/latest/plugins/cache.html&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% cat ansible.cfg
[defaults]

# Specify cache plugin
fact_caching = redis
# Prefix of key name
fact_caching_prefix = ansible_facts_
# Connection info of Redis(host:port)
fact_caching_connection = localhost:6379
# timeout until cache expire(s)
fact_caching_timeout = 60
# Policy of using cache. smart: if valid cache exists, Ansible would use.
gathering = smart
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I set timeout short for testing. Please set it as you like.&lt;/p&gt;

&lt;h3&gt;
  
  
  Playbook
&lt;/h3&gt;

&lt;p&gt;I prepared the below simple Playbook.&lt;br&gt;
After gather_facts, prints ansible_hostname.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% cat test.yml
---
- hosts: Vag1
  gather_facts: True
  tasks:
    - name: debug
      debug:
        var: ansible_hostname
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Default(memory)
&lt;/h3&gt;

&lt;p&gt;First, I commented out all fact_caching_foobar lines. Then check the time with time command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% time ansible-playbook test.yml

PLAY [Vag1] *****************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [Vag1]

TASK [debug] ****************************************************************************************
ok: [Vag1] =&amp;gt; {
    "ansible_hostname": "Vag1"
}

PLAY RECAP ******************************************************************************************
Vag1                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

ansible-playbook test.yml  1.02s user 0.30s system 67% cpu 1.955 total
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It took about 2 seconds.&lt;br&gt;
I tested multiple times but it takes about 1.8 to 2.0 seconds.&lt;/p&gt;
&lt;h3&gt;
  
  
  Redis
&lt;/h3&gt;

&lt;p&gt;Now enabled fact_caching_foobar lines in ansible.cfg and check time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% cat ansible.cfg
[defaults]

# Specify cache plugin
fact_caching = redis
# Prefix of key name
fact_caching_prefix = ansible_facts_
# Connection info of Redis(host:port)
fact_caching_connection = localhost:6379
# timeout until cache expire(s)
fact_caching_timeout = 60
# Policy of using cache. smart: if valid cache exists, Ansible would use.
gathering = smart
[koh@kohs-MBP] ~/vag_test
% time ansible-playbook test.yml

PLAY [Vag1] *****************************************************************************************

TASK [Gathering Facts] ******************************************************************************
ok: [Vag1]

TASK [debug] ****************************************************************************************
ok: [Vag1] =&amp;gt; {
    "ansible_hostname": "Vag1"
}

PLAY RECAP ******************************************************************************************
Vag1                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

ansible-playbook test.yml  1.02s user 0.30s system 77% cpu 1.713 total
[koh@kohs-MBP] ~/vag_test
% time ansible-playbook test.yml

PLAY [Vag1] *****************************************************************************************

TASK [debug] ****************************************************************************************
ok: [Vag1] =&amp;gt; {
    "ansible_hostname": "Vag1"
}

PLAY RECAP ******************************************************************************************
Vag1                       : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

ansible-playbook test.yml  0.69s user 0.20s system 97% cpu 0.901 total
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first run after enabling was pretty much the same as the default since it retrieved the facts, but the second run took only 0.9 second which was 0.8-second faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Redis works
&lt;/h2&gt;

&lt;p&gt;Let's check what kind of values are in Redis DB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% docker exec -it ansibleredis redis-cli
127.0.0.1:6379&amp;gt; keys *
1) "ansible_facts_Vag1"
2) "ansible_cache_keys"
127.0.0.1:6379&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are 2 keys. ansible_cache_keys and { fact_cache_prefix } { hostname }&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
[koh@kohs-MBP] ~/vag_test
% docker exec -it ansibleredis redis-cli
127.0.0.1:6379&amp;gt; ZRANGE ansible_cache_keys 0 -1
1) "Vag1"
127.0.0.1:6379&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ansible_cache_keys has a list of cached hosts.&lt;br&gt;&lt;br&gt;
I have only one target so the number of value should be one too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% docker exec -it ansibleredis redis-cli
127.0.0.1:6379&amp;gt; get ansible_facts_Vag1
"{\n    \"_ansible_facts_gathered\": true,\n    \"ansible_all_ipv4_addresses\": [\n        \"10.0.2.15\",\n        \"192.168.33.11\"\n    ],\n    \"ansible_all_ipv6_addresses\": [\n        \"fe80::590e:8e97:c90c:cc33\",\n        \"fe80::a00:27ff:fe71:612b\"\n    ],\n    \"ansible_apparmor\": {\n        \"status\": \"disabled\"\n    },\n    \"ansible_architecture\": \"x86_64\",\n    \"ansible_bios_date\": \"12/01/2006\",\n    \"ansible_bios_version\": \"VirtualBox\",\n    \"ansible_cmdline\": {\n        \"BOOT_IMAGE\": \"/vmlinuz-3.10.0-862.11.6.el7.x86_64\",\n        \"LANG\": \"en_US.UTF-8\",\n        \"biosdevname\": \"0\",\n        \"crashkernel\": \"auto\",\n        \"net.ifnames\": \"0\",\n        \"quiet\": true,\n        \"rd.lvm.lv\": \"centos/swap\",\n        \"rhgb\": true,\n        \"ro\": true,\n        \"root\": \"/dev/mapper/centos-root\"\n    },\n    \"ansible_date_time\": {\n        \"date\": \"2019-07-17\",\n        \"day\": \"17\",\n        \"epoch\": \"1563371875\",\n        \"hour\": \"22\",\n        \"iso8601\": \"2019-07-17T13:57:55Z\",\n        \"iso8601_basic\": \"20190717T225755697435\",\n        \"iso8601_basic_short\": \"20190717T225755\",\n        \"iso8601_micro\": \"2019-07-17T13:57:55.697505Z\",\n        \"minute\": \"57\",\n        \"month\": \"07\",\n        \"second\": \"55\",\n        \"time\": \"22:57:55\",\n        \"tz\": \"JST\",\n        \"tz_offset\": \"+0900\",\n        \"weekday\": \"Wednesday\",\n        \"weekday_number\": \"3\",\n        \"weeknumber\": \"28\",\n        \"year\": \"2019\"\n    },\n    \"ansible_default_ipv4\": {\n        \"address\": \"10.0.2.15\",\n        \"alias\": \"eth0\",\n        \"broadcast\": \"10.0.2.255\",\n        \"gateway\": \"10.0.2.2\",\n        \"interface\": \"eth0\",\n        \"macaddress\": \"08:00:27:8b:c9:3f\",\n        \"mtu\": 1500,\n        \"netmask\": \"255.255.255.0\",\n        \"network\": \"10.0.2.0\",\n        \"type\": \"ether\"\n    },\n    \"ansible_default_ipv6\": {},\n    \"ansible_device_links\": {\n        \"ids\": {\n            \"dm-0\": [\n                \"dm-name-centos-root\",\n                \"dm-uuid-LVM-cXud4zK75fureDdfCQfo5enloeKDIc3rbL1yYbzzPZGdVlveHAelfn7TdiL4PPMK\"\n            ],\n            \"dm-1\": [\n                \"dm-name-centos-swap\",\n                \"dm-uuid-LVM-cXud4zK75fureDdfCQfo5enloeKDIc3r5Se12VYk5F7OofGC3mzqUxBtHLOc6f0i\"\n            ],\n            \"dm-2\": [\n                \"dm-name-centos-home\",\n                \"dm-uuid-LVM-cXud4zK75fureDdfCQfo5enloeKDIc3rBnDGTj2yA0ImV13Ife64zvRL20DXAcBp\"\n            ],\n            \"sda\": [\n                \"ata-VBOX_HARDDISK_VB1c9995b6-54c424af\"\n            ],\n            \"sda1\": [\n                \"ata-VBOX_HARDDISK_VB1c9995b6-54c424af-part1\"\n            ],\n            \"sda2\": [\n                \"ata-VBOX_HARDDISK_VB1c9995b6-54c424af-part2\",\n                \"lvm-pv-uuid-xkveE6-q5bs-AFQm-GG2X-lWDs-nZNn-v1DuLs\"\n            ]\n        },\n        \"labels\": {},\n        \"masters\": {\n            \"sda2\": [\n                \"dm-0\",\n                \"dm-1\",\n                \"dm-2\"\n            ]\n        },\n        \"uuids\": {\n            \"dm-0\": [\n                \"214cf212-d7f8-41fe-89a4-6b5e1f1d469c\"\n            ],\n            \"dm-1\": [\n                \"0f5a6474-6d09-4220-8eb4-f97e79b41ea0\"\n            ],\n            \"dm-2\": [\n                \"0fb2cf77-ad36-4728-a3f5-b53dc134e3fd\"\n            ],\n            \"sda1\": [\n                \"ec9d8bfa-8da0-43ce-b469-f0178aa904b5\"\n            ]\n        }\n    },\n    \"ansible_devices\": {\n        \"dm-0\": {\n            \"holders\": [],\n            \"host\": \"\",\n            \"links\": {\n                \"ids\": [\n                    \"dm-name-centos-root\",\n                    \"dm-uuid-LVM-cXud4zK75fureDdfCQfo5enloeKDIc3rbL1yYbzzPZGdVlveHAelfn7TdiL4PPMK\"\n                ],\n                \"labels\": [],\n                \"masters\": [],\n                \"uuids\": [\n                    \"214cf212-d7f8-41fe-89a4-6b5e1f1d469c\"\n                ]\n            },\n            \"model\": null,\n            \"partitions\": {},\n            \"removable\": \"0\",\n            \"rotational\": \"1\",\n            \"sas_address\": null,\n            \"sas_device_handle\": null,\n            \"scheduler_mode\": \"\",\n            \"sectors\": \"85950464\",\n            \"sectorsize\": \"512\",\n            \"size\": \"40.98 GB\",\n            \"support_discard\": \"0\",\n            \"vendor\": null,\n            \"virtual\": 1\n        },\n        \"dm-1\": {\n            \"holders\": [],\n            \"host\": \"\",\n            \"links\": {\n                \"ids\": [\n                    \"dm-name-centos-swap\",\n                    \"dm-uuid-LVM-cXud4zK75fureDdfCQfo5enloeKDIc3r5Se12VYk5F7OofGC3mzqUxBtHLOc6f0i\"\n                ],\n                \"labels\": [],\n                \"masters\": [],\n                \"uuids\": [\n                    \"0f5a6474-6d09-4220-8eb4-f97e79b41ea0\"\n                ]\n            },\n            \"model\": null,\n            \"partitions\": {},\n            \"removable\": \"0\",\n            \"rotational\": \"1\",\n            \"sas_address\": null,\n            \"sas_device_handle\": null,\n            \"scheduler_mode\": \"\",\n            \"sectors\": \"4194304\",\n            \"sectorsize\": \"512\",\n            \"size\": \"2.00 GB\",\n            \"support_discard\": \"0\",\n            \"vendor\": null,\n            \"virtual\": 1\n        },\n        \"dm-2\": {\n            \"holders\": [],\n            \"host\": \"\",\n            \"links\": {\n                \"ids\": [\n                    \"dm-name-centos-home\",\n                    \"dm-uuid-LVM-cXud4zK75fureDdfCQfo5enloeKDIc3rBnDGTj2yA0ImV13Ife64zvRL20DXAcBp\"\n                ],\n                \"labels\": [],\n                \"masters\": [],\n                \"uuids\": [\n                    \"0fb2cf77-ad36-4728-a3f5-b53dc134e3fd\"\n                ]\n            },\n            \"model\": null,\n            \"partitions\": {},\n            \"removable\": \"0\",\n            \"rotational\": \"1\",\n            \"sas_address\": null,\n            \"sas_device_handle\": null,\n            \"scheduler_mode\": \"\",\n            \"sectors\": \"41959424\",\n            \"sectorsize\": \"512\",\n            \"size\": \"20.01 GB\",\n            \"support_discard\": \"0\",\n            \"vendor\": null,\n            \"virtual\": 1\n        },\n        \"sda\": {\n            \"holders\": [],\n            \"host\": \"\",\n            \"links\": {\n                \"ids\": [\n                    \"ata-VBOX_HARDDISK_VB1c9995b6-54c424af\"\n                ],\n                \"labels\": [],\n                \"masters\": [],\n                \"uuids\": []\n            },\n            \"model\": \"VBOX HARDDISK\",\n            \"partitions\": {\n                \"sda1\": {\n                    \"holders\": [],\n                    \"links\": {\n                        \"ids\": [\n                            \"ata-VBOX_HARDDISK_VB1c9995b6-54c424af-part1\"\n                        ],\n                        \"labels\": [],\n                        \"masters\": [],\n                        \"uuids\": [\n                            \"ec9d8bfa-8da0-43ce-b469-f0178aa904b5\"\n                        ]\n                    },\n                    \"sectors\": \"2097152\",\n                    \"sectorsize\": 512,\n                    \"size\": \"1.00 GB\",\n                    \"start\": \"2048\",\n                    \"uuid\": \"ec9d8bfa-8da0-43ce-b469-f0178aa904b5\"\n                },\n                \"sda2\": {\n                    \"holders\": [\n                        \"centos-root\",\n                        \"centos-swap\",\n                        \"centos-home\"\n                    ],\n                    \"links\": {\n                        \"ids\": [\n                            \"ata-VBOX_HARDDISK_VB1c9995b6-54c424af-part2\",\n                            \"lvm-pv-uuid-xkveE6-q5bs-AFQm-GG2X-lWDs-nZNn-v1DuLs\"\n                        ],\n                        \"labels\": [],\n                        \"masters\": [\n                            \"dm-0\",\n                            \"dm-1\",\n                            \"dm-2\"\n                        ],\n                        \"uuids\": []\n                    },\n                    \"sectors\": \"132118528\",\n                    \"sectorsize\": 512,\n                    \"size\": \"63.00 GB\",\n                    \"start\": \"2099200\",\n                    \"uuid\": null\n                }\n            },\n            \"removable\": \"0\",\n            \"rotational\": \"1\",\n            \"sas_address\": null,\n            \"sas_device_handle\": null,\n            \"scheduler_mode\": \"deadline\",\n            \"sectors\": \"134217728\",\n            \"sectorsize\": \"512\",\n            \"size\": \"64.00 GB\",\n            \"support_discard\": \"0\",\n            \"vendor\": \"ATA\",\n            \"virtual\": 1\n        }\n    },\n    \"ansible_distribution\": \"CentOS\",\n    \"ansible_distribution_file_parsed\": true,\n    \"ansible_distribution_file_path\": \"/etc/redhat-release\",\n    \"ansible_distribution_file_variety\": \"RedHat\",\n    \"ansible_distribution_major_version\": \"7\",\n    \"ansible_distribution_release\": \"Core\",\n    \"ansible_distribution_version\": \"7\",\n    \"ansible_dns\": {},\n    \"ansible_domain\": \"\",\n    \"ansible_effective_group_id\": 1000,\n    \"ansible_effective_user_id\": 1000,\n    \"ansible_env\": {\n        \"HOME\": \"/home/vagrant\",\n        \"LANG\": \"C\",\n        \"LC_ALL\": \"C\",\n        \"LC_CTYPE\": \"UTF-8\",\n        \"LC_MESSAGES\": \"C\",\n        \"LOGNAME\": \"vagrant\",\n        \"MAIL\": \"/var/mail/vagrant\",\n        \"PATH\": \"/usr/local/bin:/usr/bin\",\n        \"PWD\": \"/home/vagrant\",\n        \"SELINUX_LEVEL_REQUESTED\": \"\",\n        \"SELINUX_ROLE_REQUESTED\": \"\",\n        \"SELINUX_USE_CURRENT_RANGE\": \"\",\n        \"SHELL\": \"/usr/bin/zsh\",\n        \"SHLVL\": \"1\",\n        \"SSH_CLIENT\": \"192.168.33.1 57299 22\",\n        \"SSH_CONNECTION\": \"192.168.33.1 57299 192.168.33.11 22\",\n        \"SSH_TTY\": \"/dev/pts/0\",\n        \"TERM\": \"xterm-256color\",\n        \"USER\": \"vagrant\",\n        \"XDG_RUNTIME_DIR\": \"/run/user/1000\",\n        \"XDG_SESSION_ID\": \"17\",\n        \"_\": \"/usr/bin/python\"\n    },\n    \"ansible_eth0\": {\n        \"active\": true,\n        \"device\": \"eth0\",\n        \"features\": {\n            \"busy_poll\": \"off [fixed]\",\n            \"fcoe_mtu\": \"off [fixed]\",\n            \"generic_receive_offload\": \"on\",\n            \"generic_segmentation_offload\": \"on\",\n            \"highdma\": \"off [fixed]\",\n            \"hw_tc_offload\": \"off [fixed]\",\n            \"l2_fwd_offload\": \"off [fixed]\",\n            \"large_receive_offload\": \"off [fixed]\",\n            \"loopback\": \"off [fixed]\",\n            \"netns_local\": \"off [fixed]\",\n            \"ntuple_filters\": \"off [fixed]\",\n            \"receive_hashing\": \"off [fixed]\",\n            \"rx_all\": \"off\",\n            \"rx_checksumming\": \"off\",\n            \"rx_fcs\": \"off\",\n            \"rx_udp_tunnel_port_offload\": \"off [fixed]\",\n            \"rx_vlan_filter\": \"on [fixed]\",\n            \"rx_vlan_offload\": \"on\",\n            \"rx_vlan_stag_filter\": \"off [fixed]\",\n            \"rx_vlan_stag_hw_parse\": \"off [fixed]\",\n            \"scatter_gather\": \"on\",\n            \"tcp_segmentation_offload\": \"on\",\n            \"tx_checksum_fcoe_crc\": \"off [fixed]\",\n            \"tx_checksum_ip_generic\": \"on\",\n            \"tx_checksum_ipv4\": \"off [fixed]\",\n            \"tx_checksum_ipv6\": \"off [fixed]\",\n            \"tx_checksum_sctp\": \"off [fixed]\",\n            \"tx_checksumming\": \"on\",\n            \"tx_fcoe_segmentation\": \"off [fixed]\",\n            \"tx_gre_csum_segmentation\": \"off [fixed]\",\n            \"tx_gre_segmentation\": \"off [fixed]\",\n            \"tx_gso_partial\": \"off [fixed]\",\n            \"tx_gso_robust\": \"off [fixed]\",\n            \"tx_ipip_segmentation\": \"off [fixed]\",\n            \"tx_lockless\": \"off [fixed]\",\n            \"tx_nocache_copy\": \"off\",\n            \"tx_scatter_gather\": \"on\",\n            \"tx_scatter_gather_fraglist\": \"off [fixed]\",\n            \"tx_sctp_segmentation\": \"off [fixed]\",\n            \"tx_sit_segmentation\": \"off [fixed]\",\n            \"tx_tcp6_segmentation\": \"off [fixed]\",\n            \"tx_tcp_ecn_segmentation\": \"off [fixed]\",\n            \"tx_tcp_mangleid_segmentation\": \"off\",\n            \"tx_tcp_segmentation\": \"on\",\n            \"tx_udp_tnl_csum_segmentation\": \"off [fixed]\",\n            \"tx_udp_tnl_segmentation\": \"off [fixed]\",\n            \"tx_vlan_offload\": \"on [fixed]\",\n            \"tx_vlan_stag_hw_insert\": \"off [fixed]\",\n            \"udp_fragmentation_offload\": \"off [fixed]\",\n            \"vlan_challenged\": \"off [fixed]\"\n        },\n        \"hw_timestamp_filters\": [],\n        \"ipv4\": {\n            \"address\": \"10.0.2.15\",\n            \"broadcast\": \"10.0.2.255\",\n            \"netmask\": \"255.255.255.0\",\n            \"network\": \"10.0.2.0\"\n        },\n        \"ipv6\": [\n            {\n                \"address\": \"fe80::590e:8e97:c90c:cc33\",\n                \"prefix\": \"64\",\n                \"scope\": \"link\"\n            }\n        ],\n        \"macaddress\": \"08:00:27:8b:c9:3f\",\n        \"module\": \"e1000\",\n        \"mtu\": 1500,\n        \"pciid\": \"0000:00:03.0\",\n        \"promisc\": false,\n        \"speed\": 1000,\n        \"timestamping\": [\n            \"tx_software\",\n            \"rx_software\",\n            \"software\"\n        ],\n        \"type\": \"ether\"\n    },\n    \"ansible_eth1\": {\n        \"active\": true,\n        \"device\": \"eth1\",\n        \"features\": {\n            \"busy_poll\": \"off [fixed]\",\n            \"fcoe_mtu\": \"off [fixed]\",\n            \"generic_receive_offload\": \"on\",\n            \"generic_segmentation_offload\": \"on\",\n            \"highdma\": \"off [fixed]\",\n            \"hw_tc_offload\": \"off [fixed]\",\n            \"l2_fwd_offload\": \"off [fixed]\",\n            \"large_receive_offload\": \"off [fixed]\",\n            \"loopback\": \"off [fixed]\",\n            \"netns_local\": \"off [fixed]\",\n            \"ntuple_filters\": \"off [fixed]\",\n            \"receive_hashing\": \"off [fixed]\",\n            \"rx_all\": \"off\",\n            \"rx_checksumming\": \"off\",\n            \"rx_fcs\": \"off\",\n            \"rx_udp_tunnel_port_offload\": \"off [fixed]\",\n            \"rx_vlan_filter\": \"on [fixed]\",\n            \"rx_vlan_offload\": \"on\",\n            \"rx_vlan_stag_filter\": \"off [fixed]\",\n            \"rx_vlan_stag_hw_parse\": \"off [fixed]\",\n            \"scatter_gather\": \"on\",\n            \"tcp_segmentation_offload\": \"on\",\n            \"tx_checksum_fcoe_crc\": \"off [fixed]\",\n            \"tx_checksum_ip_generic\": \"on\",\n            \"tx_checksum_ipv4\": \"off [fixed]\",\n            \"tx_checksum_ipv6\": \"off [fixed]\",\n            \"tx_checksum_sctp\": \"off [fixed]\",\n            \"tx_checksumming\": \"on\",\n            \"tx_fcoe_segmentation\": \"off [fixed]\",\n            \"tx_gre_csum_segmentation\": \"off [fixed]\",\n            \"tx_gre_segmentation\": \"off [fixed]\",\n            \"tx_gso_partial\": \"off [fixed]\",\n            \"tx_gso_robust\": \"off [fixed]\",\n            \"tx_ipip_segmentation\": \"off [fixed]\",\n            \"tx_lockless\": \"off [fixed]\",\n            \"tx_nocache_copy\": \"off\",\n            \"tx_scatter_gather\": \"on\",\n            \"tx_scatter_gather_fraglist\": \"off [fixed]\",\n            \"tx_sctp_segmentation\": \"off [fixed]\",\n            \"tx_sit_segmentation\": \"off [fixed]\",\n            \"tx_tcp6_segmentation\": \"off [fixed]\",\n            \"tx_tcp_ecn_segmentation\": \"off [fixed]\",\n            \"tx_tcp_mangleid_segmentation\": \"off\",\n            \"tx_tcp_segmentation\": \"on\",\n            \"tx_udp_tnl_csum_segmentation\": \"off [fixed]\",\n            \"tx_udp_tnl_segmentation\": \"off [fixed]\",\n            \"tx_vlan_offload\": \"on [fixed]\",\n            \"tx_vlan_stag_hw_insert\": \"off [fixed]\",\n            \"udp_fragmentation_offload\": \"off [fixed]\",\n            \"vlan_challenged\": \"off [fixed]\"\n        },\n        \"hw_timestamp_filters\": [],\n        \"ipv4\": {\n            \"address\": \"192.168.33.11\",\n            \"broadcast\": \"192.168.33.255\",\n            \"netmask\": \"255.255.255.0\",\n            \"network\": \"192.168.33.0\"\n        },\n        \"ipv6\": [\n            {\n                \"address\": \"fe80::a00:27ff:fe71:612b\",\n                \"prefix\": \"64\",\n                \"scope\": \"link\"\n            }\n        ],\n        \"macaddress\": \"08:00:27:71:61:2b\",\n        \"module\": \"e1000\",\n        \"mtu\": 1500,\n        \"pciid\": \"0000:00:08.0\",\n        \"promisc\": false,\n        \"speed\": 1000,\n        \"timestamping\": [\n            \"tx_software\",\n            \"rx_software\",\n            \"software\"\n        ],\n        \"type\": \"ether\"\n    },\n    \"ansible_fibre_channel_wwn\": [],\n    \"ansible_fips\": false,\n    \"ansible_form_factor\": \"Other\",\n    \"ansible_fqdn\": \"Vag1\",\n    \"ansible_hostname\": \"Vag1\",\n    \"ansible_hostnqn\": \"\",\n    \"ansible_interfaces\": [\n        \"lo\",\n        \"eth1\",\n        \"eth0\"\n    ],\n    \"ansible_is_chroot\": true,\n    \"ansible_iscsi_iqn\": \"\",\n    \"ansible_kernel\": \"3.10.0-862.11.6.el7.x86_64\",\n    \"ansible_lo\": {\n        \"active\": true,\n        \"device\": \"lo\",\n        \"features\": {\n            \"busy_poll\": \"off [fixed]\",\n            \"fcoe_mtu\": \"off [fixed]\",\n            \"generic_receive_offload\": \"on\",\n            \"generic_segmentation_offload\": \"on\",\n            \"highdma\": \"on [fixed]\",\n            \"hw_tc_offload\": \"off [fixed]\",\n            \"l2_fwd_offload\": \"off [fixed]\",\n            \"large_receive_offload\": \"off [fixed]\",\n            \"loopback\": \"on [fixed]\",\n            \"netns_local\": \"on [fixed]\",\n            \"ntuple_filters\": \"off [fixed]\",\n            \"receive_hashing\": \"off [fixed]\",\n            \"rx_all\": \"off [fixed]\",\n            \"rx_checksumming\": \"on [fixed]\",\n            \"rx_fcs\": \"off [fixed]\",\n            \"rx_udp_tunnel_port_offload\": \"off [fixed]\",\n            \"rx_vlan_filter\": \"off [fixed]\",\n            \"rx_vlan_offload\": \"off [fixed]\",\n            \"rx_vlan_stag_filter\": \"off [fixed]\",\n            \"rx_vlan_stag_hw_parse\": \"off [fixed]\",\n            \"scatter_gather\": \"on\",\n            \"tcp_segmentation_offload\": \"on\",\n            \"tx_checksum_fcoe_crc\": \"off [fixed]\",\n            \"tx_checksum_ip_generic\": \"on [fixed]\",\n            \"tx_checksum_ipv4\": \"off [fixed]\",\n            \"tx_checksum_ipv6\": \"off [fixed]\",\n            \"tx_checksum_sctp\": \"on [fixed]\",\n            \"tx_checksumming\": \"on\",\n            \"tx_fcoe_segmentation\": \"off [fixed]\",\n            \"tx_gre_csum_segmentation\": \"off [fixed]\",\n            \"tx_gre_segmentation\": \"off [fixed]\",\n            \"tx_gso_partial\": \"off [fixed]\",\n            \"tx_gso_robust\": \"off [fixed]\",\n            \"tx_ipip_segmentation\": \"off [fixed]\",\n            \"tx_lockless\": \"on [fixed]\",\n            \"tx_nocache_copy\": \"off [fixed]\",\n            \"tx_scatter_gather\": \"on [fixed]\",\n            \"tx_scatter_gather_fraglist\": \"on [fixed]\",\n            \"tx_sctp_segmentation\": \"on\",\n            \"tx_sit_segmentation\": \"off [fixed]\",\n            \"tx_tcp6_segmentation\": \"on\",\n            \"tx_tcp_ecn_segmentation\": \"on\",\n            \"tx_tcp_mangleid_segmentation\": \"on\",\n            \"tx_tcp_segmentation\": \"on\",\n            \"tx_udp_tnl_csum_segmentation\": \"off [fixed]\",\n            \"tx_udp_tnl_segmentation\": \"off [fixed]\",\n            \"tx_vlan_offload\": \"off [fixed]\",\n            \"tx_vlan_stag_hw_insert\": \"off [fixed]\",\n            \"udp_fragmentation_offload\": \"on\",\n            \"vlan_challenged\": \"on [fixed]\"\n        },\n        \"hw_timestamp_filters\": [],\n        \"ipv4\": {\n            \"address\": \"127.0.0.1\",\n            \"broadcast\": \"host\",\n            \"netmask\": \"255.0.0.0\",\n            \"network\": \"127.0.0.0\"\n        },\n        \"ipv6\": [\n            {\n                \"address\": \"::1\",\n                \"prefix\": \"128\",\n                \"scope\": \"host\"\n            }\n        ],\n        \"mtu\": 65536,\n        \"promisc\": false,\n        \"timestamping\": [\n            \"rx_software\",\n            \"software\"\n        ],\n        \"type\": \"loopback\"\n    },\n    \"ansible_local\": {},\n    \"ansible_lsb\": {},\n    \"ansible_machine\": \"x86_64\",\n    \"ansible_machine_id\": \"b8ae4e7c6e42490b801633d8d903c9a0\",\n    \"ansible_memfree_mb\": 769,\n    \"ansible_memory_mb\": {\n        \"nocache\": {\n            \"free\": 874,\n            \"used\": 117\n        },\n        \"real\": {\n            \"free\": 769,\n            \"total\": 991,\n            \"used\": 222\n        },\n        \"swap\": {\n            \"cached\": 0,\n            \"free\": 2047,\n            \"total\": 2047,\n            \"used\": 0\n        }\n    },\n    \"ansible_memtotal_mb\": 991,\n    \"ansible_mounts\": [\n        {\n            \"block_available\": 226495,\n            \"block_size\": 4096,\n            \"block_total\": 259584,\n            \"block_used\": 33089,\n            \"device\": \"/dev/sda1\",\n            \"fstype\": \"xfs\",\n            \"inode_available\": 523962,\n            \"inode_total\": 524288,\n            \"inode_used\": 326,\n            \"mount\": \"/boot\",\n            \"options\": \"rw,seclabel,relatime,attr2,inode64,noquota\",\n            \"size_available\": 927723520,\n            \"size_total\": 1063256064,\n            \"uuid\": \"ec9d8bfa-8da0-43ce-b469-f0178aa904b5\"\n        },\n        {\n            \"block_available\": 10398487,\n            \"block_size\": 4096,\n            \"block_total\": 10738562,\n            \"block_used\": 340075,\n            \"device\": \"/dev/mapper/centos-root\",\n            \"fstype\": \"xfs\",\n            \"inode_available\": 21453369,\n            \"inode_total\": 21487616,\n            \"inode_used\": 34247,\n            \"mount\": \"/\",\n            \"options\": \"rw,seclabel,relatime,attr2,inode64,noquota\",\n            \"size_available\": 42592202752,\n            \"size_total\": 43985149952,\n            \"uuid\": \"214cf212-d7f8-41fe-89a4-6b5e1f1d469c\"\n        },\n        {\n            \"block_available\": 5233400,\n            \"block_size\": 4096,\n            \"block_total\": 5242367,\n            \"block_used\": 8967,\n            \"device\": \"/dev/mapper/centos-home\",\n            \"fstype\": \"xfs\",\n            \"inode_available\": 10489816,\n            \"inode_total\": 10489856,\n            \"inode_used\": 40,\n            \"mount\": \"/home\",\n            \"options\": \"rw,seclabel,relatime,attr2,inode64,noquota\",\n            \"size_available\": 21436006400,\n            \"size_total\": 21472735232,\n            \"uuid\": \"0fb2cf77-ad36-4728-a3f5-b53dc134e3fd\"\n        }\n    ],\n    \"ansible_nodename\": \"Vag1\",\n    \"ansible_os_family\": \"RedHat\",\n    \"ansible_pkg_mgr\": \"yum\",\n    \"ansible_proc_cmdline\": {\n        \"BOOT_IMAGE\": \"/vmlinuz-3.10.0-862.11.6.el7.x86_64\",\n        \"LANG\": \"en_US.UTF-8\",\n        \"biosdevname\": \"0\",\n        \"crashkernel\": \"auto\",\n        \"net.ifnames\": \"0\",\n        \"quiet\": true,\n        \"rd.lvm.lv\": [\n            \"centos/root\",\n            \"centos/swap\"\n        ],\n        \"rhgb\": true,\n        \"ro\": true,\n        \"root\": \"/dev/mapper/centos-root\"\n    },\n    \"ansible_processor\": [\n        \"0\",\n        \"GenuineIntel\",\n        \"Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz\"\n    ],\n    \"ansible_processor_cores\": 1,\n    \"ansible_processor_count\": 1,\n    \"ansible_processor_threads_per_core\": 1,\n    \"ansible_processor_vcpus\": 1,\n    \"ansible_product_name\": \"VirtualBox\",\n    \"ansible_product_serial\": \"NA\",\n    \"ansible_product_uuid\": \"NA\",\n    \"ansible_product_version\": \"1.2\",\n    \"ansible_python\": {\n        \"executable\": \"/usr/bin/python\",\n        \"has_sslcontext\": true,\n        \"type\": \"CPython\",\n        \"version\": {\n            \"major\": 2,\n            \"micro\": 5,\n            \"minor\": 7,\n            \"releaselevel\": \"final\",\n            \"serial\": 0\n        },\n        \"version_info\": [\n            2,\n            7,\n            5,\n            \"final\",\n            0\n        ]\n    },\n    \"ansible_python_version\": \"2.7.5\",\n    \"ansible_real_group_id\": 1000,\n    \"ansible_real_user_id\": 1000,\n    \"ansible_selinux\": {\n        \"config_mode\": \"enforcing\",\n        \"mode\": \"enforcing\",\n        \"policyvers\": 31,\n        \"status\": \"enabled\",\n        \"type\": \"targeted\"\n    },\n    \"ansible_selinux_python_present\": true,\n    \"ansible_service_mgr\": \"systemd\",\n    \"ansible_ssh_host_key_ecdsa_public\": \"AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBA5XlGiLVt6/NnCPwaH89VKPo+cvKjyzwnje1z9LkaiFXRNhWTsxYsMYPjx5cf5HQbJs4VCKIaPxK20QFYSabLc=\",\n    \"ansible_ssh_host_key_ed25519_public\": \"AAAAC3NzaC1lZDI1NTE5AAAAIGhrt2KMmJ0a2QdNNsFElTnHSdhufURJmAIo39+5R1hP\",\n    \"ansible_ssh_host_key_rsa_public\": \"AAAAB3NzaC1yc2EAAAADAQABAAABAQC99JJpb04/QLprQKr1Duz7dBfAHvbwuaouvVkMPKVoxQ7u2xUiTqKMWwckPBw3GfRC+soM6KXj+WnaIFsIFmYBYOwN1dl4ldpJxvp/+rz4VUvOsjqiAK6Ju7Hi2zlvN/Cz8n8NMC7+BT295s1jGYJU7SGVVJ/uLDVoiDa/dcptk17V4bgN8Wqe3hiEDbtbRMgZdwQ01o8b1uM6GQAAbz1S6kwnZ3fOXHU7Z29lZu2g5/xIYX48yhV8YnqwWmI2+i0zd06b+HoXwQH2+OVlZEMfv2Gc+xp4E0Pqu6VDyOPJGIkRuV0aBX6qT/6FDBUWvcGXs7gVdUL2wdvi5V8uf/rV\",\n    \"ansible_swapfree_mb\": 2047,\n    \"ansible_swaptotal_mb\": 2047,\n    \"ansible_system\": \"Linux\",\n    \"ansible_system_capabilities\": [\n        \"\"\n    ],\n    \"ansible_system_capabilities_enforced\": \"True\",\n    \"ansible_system_vendor\": \"innotek GmbH\",\n    \"ansible_uptime_seconds\": 3839,\n    \"ansible_user_dir\": \"/home/vagrant\",\n    \"ansible_user_gecos\": \"vagrant\",\n    \"ansible_user_gid\": 1000,\n    \"ansible_user_id\": \"vagrant\",\n    \"ansible_user_shell\": \"/usr/bin/zsh\",\n    \"ansible_user_uid\": 1000,\n    \"ansible_userspace_architecture\": \"x86_64\",\n    \"ansible_userspace_bits\": \"64\",\n    \"ansible_virtualization_role\": \"guest\",\n    \"ansible_virtualization_type\": \"virtualbox\",\n    \"discovered_interpreter_python\": \"/usr/bin/python\",\n    \"gather_subset\": [\n        \"all\"\n    ],\n    \"module_setup\": true\n}"
127.0.0.1:6379&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see that is how facts are registered to Redis.&lt;/p&gt;

&lt;p&gt;Right after running Playbook, I checked TTL of the key and the value was the same as  fact_caching_timeout.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% docker exec -it ansibleredis redis-cli
127.0.0.1:6379&amp;gt; ttl ansible_facts_Vag1
(integer) 57
127.0.0.1:6379&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now we know how to make Ansible only a bit faster.&lt;br&gt;
It is only a few seconds but might be useful when you have to run Playbook many times.&lt;br&gt;
Also please be noted that if Redis is down, Ansible cannot be run.&lt;br&gt;
So if you are interested in using this for production CI/CD, you have to ensure the availability of Redis.&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>redis</category>
    </item>
    <item>
      <title>Difference between Ansible's copy and template module</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Sat, 09 Nov 2019 09:26:12 +0000</pubDate>
      <link>https://dev.to/koh_sh/difference-between-ansible-s-copy-and-template-module-41e6</link>
      <guid>https://dev.to/koh_sh/difference-between-ansible-s-copy-and-template-module-41e6</guid>
      <description>&lt;p&gt;Ansible has copy module and template module.&lt;br&gt;
Basically, both modules are to copy files from local machine to remote machines, but technically behaviors are a bit different.&lt;br&gt;
In this note, I would like to go through the difference between them and points to care.&lt;/p&gt;

&lt;p&gt;*Version of Ansible is 2.8.1&lt;/p&gt;
&lt;h2&gt;
  
  
  copy
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.ansible.com/ansible/latest/modules/copy_module.html#copy-module"&gt;https://docs.ansible.com/ansible/latest/modules/copy_module.html#copy-module&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Basic features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Variables cannot be used in the file&lt;/li&gt;
&lt;li&gt;default path to src files are under &lt;code&gt;roles/{{ rolename }}/files&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;with remote_src parameter, you can copy files from remote machines to the machine's other place&lt;/li&gt;
&lt;li&gt;with content parameter, you can specify the contents of files directly without src files&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  template
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.ansible.com/ansible/latest/modules/template_module.html#template-module"&gt;https://docs.ansible.com/ansible/latest/modules/template_module.html#template-module&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Basic features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;with Jinja2, you can program like for loop or if conditions in files&lt;/li&gt;
&lt;li&gt;Variables can be used in files&lt;/li&gt;
&lt;li&gt;default path to src files are under &lt;code&gt;roles/{{ rolename }}/templates&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  About Jinja2
&lt;/h3&gt;

&lt;p&gt;I would like to explain about Jinja2 a bit.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://jinja.pocoo.org/docs/2.10/#"&gt;http://jinja.pocoo.org/docs/2.10/#&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Jinja2 is a modern and designer-friendly templating language for Python, modelled after Django’s templates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are simple examples of for loop and if conditions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% cat test.j2
{% for item in ["foo","bar","baz"] %}
{{ item }}
{% endfor %}

{% if inventory_hostname == "Vag2" %}
hostname is Vag2
{% else %}
hostname is not Vag2
{% endif %}
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With for loop it prints foo,bar,baz.&lt;br&gt;
After that, if inventory_hostname is Vag2, then print &lt;code&gt;hostname is Vag2&lt;/code&gt;&lt;br&gt;
if not, print &lt;code&gt;hostname is not Vag2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Below is the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% ansible Vag1 -m template -a "src=test.j2 dest=."
Vag1 | CHANGED =&amp;gt; {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": true,
    "checksum": "c2383df182afda3f4de83ce7171885ce7fd4839a",
    "dest": "././test.j2",
    "gid": 1000,
    "group": "vagrant",
    "md5sum": "54a03d50ba7a7751f6d647afdeb80e02",
    "mode": "0644",
    "owner": "vagrant",
    "secontext": "unconfined_u:object_r:user_home_t:s0",
    "size": 34,
    "src": "/home/vagrant/.ansible/tmp/ansible-tmp-1562164682.016716-96505856164811/source",
    "state": "file",
    "uid": 1000
}
[koh@kohs-MBP] ~/vag_test
% ssh Vag1 "cat test.j2"
foo
bar
baz

hostname is not Vag2
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using Jinja2 or Ansible's variables, your Playbook would be much better for practical uses like the below cases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using for loops for configs of reverse proxies like HAProxy or Nginx&lt;/li&gt;
&lt;li&gt;using variables is useful to share the same templates for prod/stg/dev environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Important points
&lt;/h3&gt;

&lt;p&gt;As I explained template module is very convenient, but as long as it modifies original files at execution of Ansible, there is a possibility of miss configurations.&lt;/p&gt;

&lt;p&gt;Wrong syntax is common mistakes, but worse cases are wrong recognition of Jinja2 format by Ansible.&lt;/p&gt;

&lt;p&gt;For example, Apache's config about LogFormat might be recognized as Jinja2.&lt;br&gt;
Here is a template with Logformat entry and running Ansible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% cat logformat.j2
LogFormat "%{%d/%b/%Y %T}t.%{msec_frac}t %{%z}t"
[koh@kohs-MBP] ~/vag_test
%
[koh@kohs-MBP] ~/vag_test
% ansible Vag1 -m template -a "src=logformat.j2 dest=."
Vag1 | FAILED! =&amp;gt; {
    "changed": false,
    "msg": "AnsibleError: template error while templating string: Encountered unknown tag 'd'.. String: LogFormat \"%{%d/%b/%Y %T}t.%{msec_frac}t %{%z}t\"\n"
}
zsh: exit 2     ansible Vag1 -m template -a "src=logformat.j2 dest=."
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;{%d&lt;/code&gt; in the template is recognized as a Tag of Jinja2 and Ansible threw the error.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to avoid these errors
&lt;/h3&gt;

&lt;p&gt;Below ideas are good for avoiding the above errors and miss configurations.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use copy module when Jinja2 templating or variables are not used
&lt;/h4&gt;

&lt;p&gt;Copy module never modifies the source file so using copy module is properly is the best way to make Playbook safer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use validate parameter
&lt;/h4&gt;

&lt;p&gt;Template module has validate parameter which executes a command to check the validity of templates.&lt;br&gt;
It really works when setting up critical configurations that cannot be failed like sshd or sudoers.&lt;br&gt;
Copy module also has this parameter so it is still useful for copy module too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Copy a new sudoers file into place, after passing validation with visudo
  template:
    src: /mine/sudoers
    dest: /etc/sudoers
    validate: /usr/sbin/visudo -cf %s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Use check mode
&lt;/h4&gt;

&lt;p&gt;Ansible has check mode(-C) you can check how the Playbook works without making any changes to the actual environment.&lt;br&gt;
It works great with Diff option(-D).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% ansible Vag1 -m template -a "src=test.j2 dest=." -D -C
--- before: ./test.j2
+++ after: /Users/koh/.ansible/tmp/ansible-local-90545ps884h5s/tmpuvs9nt1z/test.j2
@@ -1,4 +1,4 @@
-foo
+fooooo
 bar
 baz


Vag1 | CHANGED =&amp;gt; {
    "changed": true
}
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By using template module effectively, your Playbook would be more practical.&lt;br&gt;
Ansible is famous for simplicity, but template can bring chaos to your Playbook so please use with consideration not to use too much.&lt;/p&gt;

</description>
      <category>ansible</category>
    </item>
    <item>
      <title>Play with Testinfra which tests states of infrastructure</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Sat, 09 Nov 2019 05:14:46 +0000</pubDate>
      <link>https://dev.to/koh_sh/play-with-testinfra-which-tests-states-of-infrastructure-1bl2</link>
      <guid>https://dev.to/koh_sh/play-with-testinfra-which-tests-states-of-infrastructure-1bl2</guid>
      <description>&lt;p&gt;This is my note about Testinfra which can be an alternative of ServerSpec.&lt;br&gt;
I previously wrote about goss which is also a testing tool for infrastructure.&lt;br&gt;
This might be nice to compare with.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/koh_sh" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tspPSyIl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--jOnNmmN0--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/267546/961a9df9-a330-4281-9536-e4be6c37b3dd.png" alt="koh_sh"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/koh_sh/work-with-serverspec-alternative-tool-goss-1pj1" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Work with Serverspec alternative tool Goss&lt;/h2&gt;
      &lt;h3&gt;koh-sh ・ Nov 8 '19 ・ 4 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#go&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#testing&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#linux&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  What is Testinfra
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://testinfra.readthedocs.io/en/latest/"&gt;https://testinfra.readthedocs.io/en/latest/&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;About
With Testinfra you can write unit tests in Python to test actual state of your servers configured by management tools like Salt, Ansible, Puppet, Chef and so on.

Testinfra aims to be a Serverspec equivalent in python and is written as a plugin to the powerful Pytest test engine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To put it simply, Testinfra is like ServerSpec but written in Python, and works great with configuration management tools like Ansible, Chef.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;Compared with ServerSpec, Testinfra has the below features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lots of Connection Backend
&lt;/h3&gt;

&lt;p&gt;Testinfra has several options for connecting remote hosts other than plain SSH.&lt;br&gt;
Testinfra can refer to an inventory of Ansible, also able to connect containers by docker or kubectl.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://testinfra.readthedocs.io/en/latest/backends.html"&gt;https://testinfra.readthedocs.io/en/latest/backends.html&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;local&lt;/li&gt;
&lt;li&gt;paramiko&lt;/li&gt;
&lt;li&gt;docker&lt;/li&gt;
&lt;li&gt;ssh&lt;/li&gt;
&lt;li&gt;salt&lt;/li&gt;
&lt;li&gt;ansible&lt;/li&gt;
&lt;li&gt;kubectl&lt;/li&gt;
&lt;li&gt;winrm&lt;/li&gt;
&lt;li&gt;LXC/LXD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Above is the list of connection backend.&lt;/p&gt;
&lt;h3&gt;
  
  
  Interactive testing
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://testinfra.readthedocs.io/en/latest/api.html"&gt;https://testinfra.readthedocs.io/en/latest/api.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It can connect to host and test interactively so you don't even have to write a test file.&lt;br&gt;
And I think Testinfra works great with ipython.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% ipython
Python 3.7.3 (default, May  1 2019, 16:07:48)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.5.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import testinfra

In [2]: host = testinfra.get_host("paramiko://vagrant@Vag1:22", sudo=True)

In [3]: host.file("/etc/passwd").mode == 0o644
Out[3]: True

In [4]:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let's try
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Environment
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Client
&lt;/h4&gt;

&lt;p&gt;MacOS Mojave 10.14.5&lt;br&gt;
Python 3.7.3&lt;/p&gt;
&lt;h4&gt;
  
  
  Remote host
&lt;/h4&gt;

&lt;p&gt;CentOS 7.5.1804 on Vagrant&lt;br&gt;
Python 2.7.5  &lt;/p&gt;
&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;p&gt;Installing with pip on the client machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ pip install testinfra
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  writing a test
&lt;/h3&gt;

&lt;p&gt;Writing a test file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def test_passwd_file(host):
    passwd = host.file("/etc/passwd")
    assert passwd.contains("root")
    assert passwd.user == "root"
    assert passwd.group == "root"
    assert passwd.mode == 0o644


def test_nginx_running_and_enabled(host):
    nginx = host.service("nginx")
    assert nginx.is_running
    assert nginx.is_enabled


def test_selinux(host):
    cmd = host.run("/usr/sbin/getenforce")
    assert cmd.stdout == "Enforcing\n"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this test example, it tests&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contents, owner/permission of /etc/passwd&lt;/li&gt;
&lt;li&gt;is-active, is-enabled of NGINX
&lt;/li&gt;
&lt;li&gt;status of selinux
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Test execution
&lt;/h3&gt;

&lt;p&gt;So from here, I am running Testinfra.&lt;br&gt;
Testing from local machine to CentOS on Vagrant with SSH.&lt;br&gt;
Also, NGINX is running on the remote machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% py.test -v test_first.py --connection=ssh --host=Vag1
======================================== test session starts ========================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.9.0 -- /Users/koh/.pyenv/versions/3.7.3/bin/python3.7
cachedir: .pytest_cache
rootdir: /Users/koh/vag_test
plugins: xonsh-0.8.12, testinfra-3.0.5
collected 3 items

test_first.py::test_passwd_file[ssh://Vag1] PASSED                                            [ 33%]
test_first.py::test_nginx_running_and_enabled[ssh://Vag1] PASSED                              [ 66%]
test_first.py::test_selinux[ssh://Vag1] PASSED                                                [100%]

===================================== 3 passed in 3.22 seconds ======================================
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is clear and easy to check the result.&lt;br&gt;
And now I stop NGINX.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% py.test -v test_first.py --connection=ssh --host=Vag1
======================================== test session starts ========================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.9.0 -- /Users/koh/.pyenv/versions/3.7.3/bin/python3.7
cachedir: .pytest_cache
rootdir: /Users/koh/vag_test
plugins: xonsh-0.8.12, testinfra-3.0.5
collected 3 items

test_first.py::test_passwd_file[ssh://Vag1] PASSED                                            [ 33%]
test_first.py::test_nginx_running_and_enabled[ssh://Vag1] FAILED                              [ 66%]
test_first.py::test_selinux[ssh://Vag1] PASSED                                                [100%]

============================================= FAILURES ==============================================
____________________________ test_nginx_running_and_enabled[ssh://Vag1] _____________________________

host = &amp;lt;testinfra.host.Host object at 0x103826438&amp;gt;

    def test_nginx_running_and_enabled(host):
        nginx = host.service("nginx")
&amp;gt;       assert nginx.is_running
E       assert False
E        +  where False = &amp;lt;service nginx&amp;gt;.is_running

test_first.py:11: AssertionError
================================ 1 failed, 2 passed in 3.06 seconds =================================
zsh: exit 1     py.test -v test_first.py --connection=ssh --host=Vag1
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is obvious that which item is failed and how it failed.&lt;br&gt;
Also able to test multiple hosts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[koh@kohs-MBP] ~/vag_test
% py.test -v test_first.py --connection=ssh --host=Vag1,Vag2
======================================== test session starts ========================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.9.0 -- /Users/koh/.pyenv/versions/3.7.3/bin/python3.7
cachedir: .pytest_cache
rootdir: /Users/koh/vag_test
plugins: xonsh-0.8.12, testinfra-3.0.5
collected 6 items

test_first.py::test_passwd_file[ssh://Vag1] PASSED                                            [ 16%]
test_first.py::test_nginx_running_and_enabled[ssh://Vag1] PASSED                              [ 33%]
test_first.py::test_selinux[ssh://Vag1] PASSED                                                [ 50%]
test_first.py::test_passwd_file[ssh://Vag2] PASSED                                            [ 66%]
test_first.py::test_nginx_running_and_enabled[ssh://Vag2] FAILED                              [ 83%]
test_first.py::test_selinux[ssh://Vag2] FAILED                                                [100%]

============================================= FAILURES ==============================================
____________________________ test_nginx_running_and_enabled[ssh://Vag2] _____________________________

host = &amp;lt;testinfra.host.Host object at 0x11026f4e0&amp;gt;

    def test_nginx_running_and_enabled(host):
        nginx = host.service("nginx")
&amp;gt;       assert nginx.is_running
E       assert False
E        +  where False = &amp;lt;service nginx&amp;gt;.is_running

test_first.py:11: AssertionError
_____________________________________ test_selinux[ssh://Vag2] ______________________________________

host = &amp;lt;testinfra.host.Host object at 0x11026f4e0&amp;gt;

    def test_selinux(host):
        cmd = host.run("/usr/sbin/getenforce")
&amp;gt;       assert cmd.stdout == "Enforcing\n"
E       AssertionError: assert 'Permissive\n' == 'Enforcing\n'
E         - Permissive
E         + Enforcing

test_first.py:17: AssertionError
================================ 2 failed, 4 passed in 6.14 seconds =================================
zsh: exit 1     py.test -v test_first.py --connection=ssh --host=Vag1,Vag2
[koh@kohs-MBP] ~/vag_test
%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Compared with ServerSpec, ServerSpec has more resources, and many more documents on the internet (especially in Japanese).&lt;br&gt;
But as I mentioned there are some pros of Testinfra so if you prefer Python, it is worth trying at least once.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>python</category>
      <category>linux</category>
    </item>
    <item>
      <title>Finally I am using journalctl</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Fri, 08 Nov 2019 13:17:22 +0000</pubDate>
      <link>https://dev.to/koh_sh/finally-i-am-using-journalctl-147m</link>
      <guid>https://dev.to/koh_sh/finally-i-am-using-journalctl-147m</guid>
      <description>&lt;p&gt;I know it is too late but now I found out journalctl is convenient.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is journalctl
&lt;/h2&gt;

&lt;p&gt;From the output of &lt;code&gt;man journalctl&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME
       journalctl - Query the systemd journal

SYNOPSIS
       journalctl [OPTIONS...] [MATCHES...]

DESCRIPTION
       journalctl may be used to query the contents of the systemd(1) journal as written by
       systemd-journald.service(8).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, then what is journald?&lt;br&gt;
Let's see &lt;code&gt;man systemd-journald&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DESCRIPTION
       systemd-journald is a system service that collects and stores logging data. It creates and
       maintains structured, indexed journals based on logging information that is received from a
       variety of sources:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To put it simply, journald corrects and manages many kinds of logs. &lt;br&gt;
It can correct the below logs. Pretty much every log.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kernel log messages, via kmsg&lt;/li&gt;
&lt;li&gt;Simple system log messages, via the libc syslog(3) call&lt;/li&gt;
&lt;li&gt;Structured system log messages via the native Journal API, see sd_journal_print(3)&lt;/li&gt;
&lt;li&gt;Standard output and standard error of service units. For further details see below.&lt;/li&gt;
&lt;li&gt;Audit records, originating from the kernel audit subsystem&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Work with journalctl
&lt;/h2&gt;

&lt;p&gt;So let's play with journalctl.&lt;br&gt;
Environment: CentOS 7.5.1804 on Vagrant.&lt;/p&gt;

&lt;p&gt;Without any options, it prints all logs stated above.&lt;br&gt;
Older entries come top and operated with a pager like less command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;% sudo journalctl&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Logs begin at Sat 2019-04-13 14:05:21 JST, end at Sat 2019-04-13 14:26:56 JST. --
Apr 13 14:05:21 localhost.localdomain systemd-journal[84]: Runtime journal is using 6.1M (max allowed 49.5M, trying to leave 74.3M free of 489.6M available &amp;lt;E2&amp;gt;&amp;lt;86&amp;gt;&amp;lt;92&amp;gt; current limit 49.5M).
Apr 13 14:05:21 localhost.localdomain kernel: Initializing cgroup subsys cpuset
Apr 13 14:05:21 localhost.localdomain kernel: Initializing cgroup subsys cpu
&amp;lt;ellipsis&amp;gt;
Apr 13 14:20:01 Vag2 systemd[1]: Stopping User Slice of root.
Apr 13 14:20:32 Vag2 systemd[1]: Starting Cleanup of Temporary Directories...
Apr 13 14:20:32 Vag2 systemd[1]: Started Cleanup of Temporary Directories.
Apr 13 14:23:18 Vag2 sudo[2428]:  vagrant : TTY=pts/0 ; PWD=/home/vagrant ; USER=root ; COMMAND=/bin/journalctl

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Options can be used to filter logs.&lt;br&gt;
Here are some useful options.&lt;/p&gt;
&lt;h3&gt;
  
  
  Kernel messages
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;-k&lt;/code&gt; prints kernel messages like dmesg command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;% sudo journalctl -k&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Logs begin at Sat 2019-04-13 14:05:21 JST, end at Sat 2019-04-13 14:34:48 JST. --
Apr 13 14:05:21 localhost.localdomain kernel: Initializing cgroup subsys cpuset
Apr 13 14:05:21 localhost.localdomain kernel: Initializing cgroup subsys cpu
Apr 13 14:05:21 localhost.localdomain kernel: Initializing cgroup subsys cpuacct
Apr 13 14:05:21 localhost.localdomain kernel: Linux version 3.10.0-862.11.6.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC) ) #1 SMP Tue Aug 14 21:49:04 UTC 2018
Apr 13 14:05:21 localhost.localdomain kernel: Command line: BOOT_IMAGE=/vmlinuz-3.10.0-862.11.6.el7.x86_64 root=/dev/mapper/centos-root ro net.ifnames=0 biosdevname=0 crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Units
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;-u&lt;/code&gt; prints specific unit logs.&lt;br&gt;
Printing HAproxy's log for example.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;% sudo journalctl -u haproxy&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Logs begin at Sat 2019-04-13 14:05:21 JST, end at Sat 2019-04-13 15:00:48 JST. --
Apr 13 14:05:31 Vag2 systemd[1]: Started HAProxy Load Balancer.
Apr 13 14:05:31 Vag2 systemd[1]: Starting HAProxy Load Balancer...
Apr 13 14:05:31 Vag2 haproxy-systemd-wrapper[1019]: haproxy-systemd-wrapper: executing /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds
Apr 13 15:00:45 Vag2 systemd[1]: Reloaded HAProxy Load Balancer.
Apr 13 15:00:45 Vag2 haproxy-systemd-wrapper[1019]: haproxy-systemd-wrapper: re-executing on SIGUSR2.
Apr 13 15:00:45 Vag2 haproxy-systemd-wrapper[1019]: haproxy-systemd-wrapper: executing /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -Ds -sf 1036
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Priority
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;-p&lt;/code&gt; prints a specific priority level of logs.&lt;br&gt;
Specified with below numbers or strings.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;emerg(0)&lt;/li&gt;
&lt;li&gt;alert(1)&lt;/li&gt;
&lt;li&gt;crit(2)&lt;/li&gt;
&lt;li&gt;err(3)&lt;/li&gt;
&lt;li&gt;warning(4)&lt;/li&gt;
&lt;li&gt;notice(5)&lt;/li&gt;
&lt;li&gt;info(6)&lt;/li&gt;
&lt;li&gt;debug(7)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;% sudo journalctl -p err&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Logs begin at Sat 2019-04-13 14:05:21 JST, end at Sat 2019-04-13 14:48:50 JST. --
Apr 13 14:05:31 Vag2 systemd[1]: Failed to start Crash recovery kernel arming.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Priorities can be multiple.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;% sudo journalctl -p err -p warning&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Logs begin at Sat 2019-04-13 14:05:21 JST, end at Sat 2019-04-13 14:49:58 JST. --
&amp;lt;ellipsis&amp;gt;
Apr 13 05:05:29 Vag2 kernel: 00:00:00.000268 main     Executable: /opt/VBoxGuestAdditions-5.2.18/sbin/VBoxService
                             00:00:00.000268 main     Process ID: 906
                             00:00:00.000269 main     Package type: LINUX_64BITS_GENERIC
Apr 13 05:05:29 Vag2 kernel: 00:00:00.003419 main     5.2.18 r124319 started. Verbose level = 0
Apr 13 14:05:31 Vag2 chronyd[647]: Forward time jump detected!
Apr 13 14:05:31 Vag2 systemd[1]: Failed to start Crash recovery kernel arming.
Apr 13 14:05:31 Vag2 systemd[1]: kdump.service failed.
Apr 13 14:05:41 Vag2 kernel: 00:00:10.017183 timesync vgsvcTimeSyncWorker: Radical guest time change: 32 411 887 294 000ns (GuestNow=1 555 131 941 050 133 000 ns GuestLast=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Other than filtering
&lt;/h3&gt;

&lt;p&gt;There are some options which change how to print.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reverse order
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;-r&lt;/code&gt; prints newer logs first.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;% sudo journalctl -r&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Logs begin at Sat 2019-04-13 14:05:21 JST, end at Sat 2019-04-13 14:56:44 JST. --
Apr 13 14:56:44 Vag2 sudo[2609]:  vagrant : TTY=pts/0 ; PWD=/home/vagrant ; USER=root ; COMMAND=/bin/journalctl -r
Apr 13 14:56:24 Vag2 sudo[2605]:  vagrant : TTY=pts/0 ; PWD=/home/vagrant ; USER=root ; COMMAND=/bin/journalctl -r
Apr 13 14:50:01 Vag2 systemd[1]: Stopping User Slice of root.
Apr 13 14:50:01 Vag2 systemd[1]: Removed slice User Slice of root.
Apr 13 14:50:01 Vag2 CROND[2596]: (root) CMD (/usr/lib64/sa/sa1 1 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Follow
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;-f&lt;/code&gt; keep printing new entries while using it. Like &lt;code&gt;tail -f&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;% sudo journalctl -f&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Logs begin at Sat 2019-04-13 14:05:21 JST. --
Apr 13 14:50:01 Vag2 systemd[1]: Created slice User Slice of root.
Apr 13 14:50:01 Vag2 systemd[1]: Starting User Slice of root.
Apr 13 14:50:01 Vag2 systemd[1]: Started Session 8 of user root.
Apr 13 14:50:01 Vag2 systemd[1]: Starting Session 8 of user root.
Apr 13 14:50:01 Vag2 CROND[2596]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Apr 13 14:50:01 Vag2 systemd[1]: Removed slice User Slice of root.
Apr 13 14:50:01 Vag2 systemd[1]: Stopping User Slice of root.
Apr 13 14:56:24 Vag2 sudo[2605]:  vagrant : TTY=pts/0 ; PWD=/home/vagrant ; USER=root ; COMMAND=/bin/journalctl -r
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Non pager
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;-no-pager&lt;/code&gt; prints logs without pager. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;% sudo journalctl --no-pager&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Logs begin at Sat 2019-04-13 14:05:21 JST, end at Sat 2019-04-13 15:02:30 JST. --
Apr 13 14:05:21 localhost.localdomain systemd-journal[84]: Runtime journal is using 6.1M (max allowed 49.5M, trying to leave 74.3M free of 489.6M available → current limit 49.5M).
Apr 13 14:05:21 localhost.localdomain kernel: Initializing cgroup subsys cpuset
Apr 13 14:05:21 localhost.localdomain kernel: Initializing cgroup subsys cpu
&amp;lt;ellipsis&amp;gt;
Apr 13 15:01:01 Vag2 anacron[2654]: Will run job `cron.daily' in 30 min.
Apr 13 15:01:01 Vag2 anacron[2654]: Will run job `cron.weekly' in 50 min.
Apr 13 15:01:01 Vag2 anacron[2654]: Jobs will be executed sequentially
Apr 13 15:02:30 Vag2 sudo[2661]:  vagrant : TTY=pts/0 ; PWD=/home/vagrant ; USER=root ; COMMAND=/bin/journalctl --no-pager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I think if you are familiar with these options, journalctl should be very convenient for you.&lt;br&gt;
I know some people don't like it but I personally like it.&lt;/p&gt;

</description>
      <category>linux</category>
    </item>
    <item>
      <title>Work with Serverspec alternative tool Goss</title>
      <dc:creator>koh-sh</dc:creator>
      <pubDate>Fri, 08 Nov 2019 10:51:47 +0000</pubDate>
      <link>https://dev.to/koh_sh/work-with-serverspec-alternative-tool-goss-1pj1</link>
      <guid>https://dev.to/koh_sh/work-with-serverspec-alternative-tool-goss-1pj1</guid>
      <description>&lt;h2&gt;
  
  
  What is Goss?
&lt;/h2&gt;

&lt;p&gt;Goss is a YAML based server testing tool written in Go.&lt;br&gt;
It checks statuses of process, ports and else.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/goss-org" rel="noopener noreferrer"&gt;
        goss-org
      &lt;/a&gt; / &lt;a href="https://github.com/goss-org/goss" rel="noopener noreferrer"&gt;
        goss
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Quick and Easy server testing/validation
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Goss - Quick and Easy server validation&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://travis-ci.org/goss-org/goss" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ab6ce210cce4a6f20661c93d916a2c245a253eaf4ee1a098575289ba20a7c8de/68747470733a2f2f7472617669732d63692e6f72672f676f73732d6f72672f676f73732e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://github.com/goss-org/goss/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/02a54ba71cc12518accf3fc69087182e4a61ac2eeb14c8cf3bf4ae6cdbd878fd/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f676f73732d6f72672f676f73732f746f74616c2e7376673f6d61784167653d363034383030" alt="Github All Releases"&gt;&lt;/a&gt;
&lt;a href="https://goss.rocks/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ea1adae5bd3b5721701b55a51810d261af7714e3028b3787492156ac605f7d35/68747470733a2f2f72656164746865646f63732e6f72672f70726f6a656374732f676f73732f62616467652f" alt="Documentation Status"&gt;&lt;/a&gt;
**
&lt;a href="https://medium.com/@aelsabbahy" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ef8a99378e729f7dafedca31fc9fb42190a8ec4a07e5d23393ed5f283a1cf004/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f666f6c6c6f772d626c6f672d627269676874677265656e2e737667" alt="Blog"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Goss in 45 seconds&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://asciinema.org/a/4suhr8p42qcn6r7crfzt6cc3e?autoplay=1" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcloud.githubusercontent.com%2Fassets%2F6783261%2F17330426%2Fce7ad066-5894-11e6-84ea-29fd4207af58.gif" alt="asciicast"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For testing containers see the &lt;a href="https://github.com/goss-org/goss/tree/master/extras/dgoss" rel="noopener noreferrer"&gt;dgoss&lt;/a&gt; wrapper.
Also, user submitted wrapper scripts for Kubernetes &lt;a href="https://github.com/goss-org/goss/tree/master/extras/kgoss" rel="noopener noreferrer"&gt;kgoss&lt;/a&gt;
and Docker Compose &lt;a href="https://github.com/goss-org/goss/tree/master/extras/dcgoss" rel="noopener noreferrer"&gt;dcgoss&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For some Docker/Kubernetes healthcheck, health endpoint, and
container ordering examples, see my blog post
&lt;a href="https://medium.com/@aelsabbahy/docker-1-12-kubernetes-simplified-health-checks-and-container-ordering-with-goss-fa8debbe676c" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Introduction&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;What is Goss?&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Goss is a YAML based &lt;a href="http://serverspec.org/" rel="nofollow noopener noreferrer"&gt;serverspec&lt;/a&gt; alternative tool for validating a server's configuration.
It eases the process of writing tests by allowing the user to generate tests from the current system state.
Once the test suite is written they can be executed, waited-on, or served as a health endpoint.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Why use Goss?&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Goss is EASY! - &lt;a href="https://github.com/goss-org/goss#goss-in-45-seconds" rel="noopener noreferrer"&gt;Goss in 45 seconds&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Goss is FAST! - small-medium test suites are near instantaneous, see &lt;a href="https://github.com/goss-org/goss/wiki/Benchmarks" rel="noopener noreferrer"&gt;benchmarks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Goss is SMALL! - &amp;lt;10MB single self-contained binary&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For macOS and Windows, see: &lt;a href="https://goss.rocks/platforms" rel="nofollow noopener noreferrer"&gt;platform-feature-parity&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This will install goss and &lt;a href="https://github.com/goss-org/goss/tree/master/extras/dgoss" rel="noopener noreferrer"&gt;dgoss&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/goss-org/goss" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Differences from Serverspec
&lt;/h2&gt;

&lt;p&gt;As it is Serverspec alternative tool, there are some differences between them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros of Goss
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Easier to write as it is YAML
&lt;/h4&gt;

&lt;p&gt;Tests can be defined by a single YAML file, easier to manage and doesn't require much time to learn.&lt;/p&gt;

&lt;h4&gt;
  
  
  Able to create test suite within a second.
&lt;/h4&gt;

&lt;p&gt;Goss provides a command to define a test state automatically.&lt;/p&gt;

&lt;h4&gt;
  
  
  Easy to install
&lt;/h4&gt;

&lt;p&gt;Goss comes with one single binary so no need to think about dependency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros of Serverspec
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Executable from remote
&lt;/h4&gt;

&lt;p&gt;Like Ansible or Chef, able to execute from a remote node with SSH&lt;/p&gt;

&lt;h4&gt;
  
  
  More Resources
&lt;/h4&gt;

&lt;p&gt;Goss supports about 20 Resources but Serverspec has twice (as of Mar 28th, 2019)&lt;/p&gt;

&lt;h4&gt;
  
  
  More flexible
&lt;/h4&gt;

&lt;p&gt;Serverspec is more flexible as it allows us to code with Ruby.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's try
&lt;/h2&gt;

&lt;p&gt;CentOS 7.5.1804  on Vagrant.&lt;br&gt;
Goss v0.3.6.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;p&gt;A script is prepared officially so it cannot be easier to install.&lt;br&gt;
Also, &lt;code&gt;dgoss&lt;/code&gt; which is a command for Docker container would be installed but I am not going to use it this time.&lt;/p&gt;

&lt;p&gt;And please be noted that the script is not recommended for production environment.&lt;br&gt;
Try manual install instead.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[vagrant@Vag2] ~
% curl -fsSL https://goss.rocks/install | sudo sh
Downloading https://github.com/aelsabbahy/goss/releases/download/v0.3.6/goss-linux-amd64
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   606    0   606    0     0    808      0 --:--:-- --:--:-- --:--:--   809
100 8324k  100 8324k    0     0   236k      0  0:00:35  0:00:35 --:--:--  240k
Goss v0.3.6 has been installed to /usr/local/bin/goss
goss --version
goss version v0.3.6
Downloading https://raw.githubusercontent.com/aelsabbahy/goss/master/extras/dgoss/dgoss
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3803  100  3803    0     0   9722      0 --:--:-- --:--:-- --:--:--  9726
dgoss master has been installed to /usr/local/bin/dgoss
[vagrant@Vag2] ~
% which goss
/usr/local/bin/goss
[vagrant@Vag2] ~
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Create a test suite
&lt;/h3&gt;

&lt;p&gt;As I mentioned earlier, Goss has commands to create a test suite automatically.&lt;br&gt;
goss.yaml will be created by &lt;code&gt;goss autoadd&lt;/code&gt; or &lt;code&gt;goss add [resource]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this post, I will work on a host which HAProxy is installed.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[vagrant@Vag2] ~/work
% goss autoadd haproxy
Adding Group to './goss.yaml':

haproxy:
  exists: true
  gid: 188


Adding Package to './goss.yaml':

haproxy:
  installed: true
  versions:
  - 1.5.18


Adding Process to './goss.yaml':

haproxy:
  running: true


Adding Service to './goss.yaml':

haproxy:
  enabled: true
  running: true


Adding User to './goss.yaml':

haproxy:
  exists: true
  uid: 188
  gid: 188
  groups:
  - haproxy
  home: /var/lib/haproxy
  shell: /sbin/nologin


[vagrant@Vag2] ~/work
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After &lt;code&gt;goss autoadd&lt;/code&gt;, the created goss.yaml is here.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[vagrant@Vag2] ~/work
% ls -l goss.yaml
-rw-r--r-- 1 vagrant vagrant 347 Mar 23 03:55 goss.yaml
[vagrant@Vag2] ~/work
% cat goss.yaml
package:
  haproxy:
    installed: true
    versions:
    - 1.5.18
service:
  haproxy:
    enabled: true
    running: true
user:
  haproxy:
    exists: true
    uid: 188
    gid: 188
    groups:
    - haproxy
    home: /var/lib/haproxy
    shell: /sbin/nologin
group:
  haproxy:
    exists: true
    gid: 188
process:
  haproxy:
    running: true
[vagrant@Vag2] ~/work
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Just a single command, below test items are created.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Test items vary on the target.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installed packages&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;is-active, is-enabled of service&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User definition&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Group definition&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Process status&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use &lt;code&gt;add [resource]&lt;/code&gt; command to specify each item one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test execution
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Success
&lt;/h4&gt;

&lt;p&gt;Then Let's try testing.&lt;br&gt;
Of course, it is easy to execute.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[vagrant@Vag2] ~/work
% goss validate
.............

Total Duration: 0.033s
Count: 13, Failed: 0, Skipped: 0
[vagrant@Vag2] ~/work
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Each dots(...) mean each test.&lt;br&gt;
The speed of the test is incredible.&lt;br&gt;
It takes only 0.033 sec to test 13 items.&lt;/p&gt;

&lt;h4&gt;
  
  
  Fail
&lt;/h4&gt;

&lt;p&gt;So next, we let the test fail.&lt;br&gt;
Stopped the process.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[vagrant@Vag2] ~/work
% sudo systemctl stop haproxy
[vagrant@Vag2] ~/work
% sudo systemctl is-active haproxy
inactive
zsh: exit 3     sudo systemctl is-active haproxy
[vagrant@Vag2] ~/work
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then retry.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[vagrant@Vag2] ~/work
% goss validate
..F.........F

Failures/Skipped:

Process: haproxy: running:
Expected
    &amp;lt;bool&amp;gt;: false
to equal
    &amp;lt;bool&amp;gt;: true

Service: haproxy: running:
Expected
    &amp;lt;bool&amp;gt;: false
to equal
    &amp;lt;bool&amp;gt;: true

Total Duration: 0.051s
Count: 13, Failed: 2, Skipped: 0
zsh: exit 1     goss validate
[vagrant@Vag2] ~/work
%


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As expected, process/service checks failed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Changing format
&lt;/h4&gt;

&lt;p&gt;Goss has several formats to output the result.&lt;br&gt;
It has like JSON, and tap is the most human readable I think.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;[vagrant@Vag2] ~/work&lt;br&gt;
% goss validate --format tap&lt;br&gt;
1..13&lt;br&gt;
ok 1 - Group: haproxy: exists: matches expectation: [true]&lt;br&gt;
ok 2 - Group: haproxy: gid: matches expectation: [188]&lt;br&gt;
not ok 3 - Process: haproxy: running: doesn't match, expect: [true] found: [false]&lt;br&gt;
ok 4 - User: haproxy: exists: matches expectation: [true]&lt;br&gt;
ok 5 - User: haproxy: uid: matches expectation: [188]&lt;br&gt;
ok 6 - User: haproxy: gid: matches expectation: [188]&lt;br&gt;
ok 7 - User: haproxy: home: matches expectation: ["/var/lib/haproxy"]&lt;br&gt;
ok 8 - User: haproxy: groups: matches expectation: [["haproxy"]]&lt;br&gt;
ok 9 - User: haproxy: shell: matches expectation: ["/sbin/nologin"]&lt;br&gt;
ok 10 - Package: haproxy: installed: matches expectation: [true]&lt;br&gt;
ok 11 - Package: haproxy: version: matches expectation: [["1.5.18"]]&lt;br&gt;
ok 12 - Service: haproxy: enabled: matches expectation: [true]&lt;br&gt;
not ok 13 - Service: haproxy: running: doesn't match, expect: [true] found: [false]&lt;br&gt;
zsh: exit 1     goss validate --format tap&lt;br&gt;
[vagrant@Vag2] ~/work&lt;br&gt;
%&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Check with http&lt;br&gt;
&lt;/h4&gt;

&lt;p&gt;Goss can serve http mode and work as Healthcheck endpoint.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;[vagrant@Vag2] ~/work&lt;br&gt;
% goss serve &amp;amp;&lt;br&gt;
2019/03/23 04:00:20 Starting to listen on: :8080&lt;/p&gt;

&lt;p&gt;[vagrant@Vag2] ~/work&lt;br&gt;
% curl localhost:8080/healthz&lt;br&gt;
2019/03/23 04:00:23 [::1]:48704: requesting health probe&lt;br&gt;
2019/03/23 04:00:23 [::1]:48704: Stale cache, running tests&lt;br&gt;
..F.........F&lt;/p&gt;

&lt;p&gt;Failures/Skipped:&lt;/p&gt;

&lt;p&gt;Process: haproxy: running:&lt;br&gt;
Expected&lt;br&gt;
    &amp;lt;bool&amp;gt;: false&lt;br&gt;
to equal&lt;br&gt;
    &amp;lt;bool&amp;gt;: true&lt;/p&gt;

&lt;p&gt;Service: haproxy: running:&lt;br&gt;
Expected&lt;br&gt;
    &amp;lt;bool&amp;gt;: false&lt;br&gt;
to equal&lt;br&gt;
    &amp;lt;bool&amp;gt;: true&lt;/p&gt;

&lt;p&gt;Total Duration: 0.044s&lt;br&gt;
Count: 13, Failed: 2, Skipped: 0&lt;br&gt;
[vagrant@Vag2] ~/work&lt;br&gt;
%&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;As I tried, Goss is extremely great since it allows us to test within a minute.&lt;br&gt;
In this post, it was only a simple test but it can be applied to production environment with more customize.&lt;/p&gt;

&lt;p&gt;I assume Ansible can be a good match with Goss when comes to production use.&lt;br&gt;
Or maybe it can extend monitoring accuracy with Goss healthcheck mode.&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>linux</category>
    </item>
  </channel>
</rss>
