pyenvとansible-lintとfileに文字列が含まれなかったらtask作動など

Ansible2.7で非推奨な書き方をしないようにというご要望があったのでその備忘録です。
https://docs.ansible.com/ansible/latest/porting_guides/porting_guide_2.7.html#deprecated
OSはCentOS7でためしています。

#### pyenv

複数のpythonバージョンを同居させて切り替えて使うためのもの。（rubyのrbenvと同様）
（ansible複数だけならvirtualenvとかもありますね）
python3.6でansible2.7でDepulicateメッセージ撲滅ということでついでにベストプラクティスに沿おうとしてansible-lintいれたりなどで、python2.7だとansible-lintのDepulicateモジュール判別するルール入りの4が入らないな～と思ってpyenvでpython3.6を用意。

```
$ sudo vi /etc/yum.conf ####exclude=kernel*をコメントにする
$ sudo yum -y install gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel glibc-headers
  
$ curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash

$ vi ~/.bashrc

export PATH="/home/myuser1/.pyenv/bin:$PATH" 
eval "$(pyenv init -)" 
eval "$(pyenv virtualenv-init -)" 

$ source ~/.bashrc
$ pyenv
pyenv 1.2.9
Usage: pyenv <command> [<args>]

Some useful pyenv commands are:
   commands    List all available pyenv commands
   local       Set or show the local application-specific Python version

$ pyenv install 3.6.8
Downloading Python-3.6.8.tar.xz...
-> https://www.python.org/ftp/python/3.6.8/Python-3.6.8.tar.xz
Installing Python-3.6.8...
Installed Python-3.6.8 to /home/myuser1/.pyenv/versions/3.6.8

$ python --version
Python 2.7.5
$ pyenv global 3.6.8
$ python --version
Python 3.6.8

$ pip install ansible==2.7
$ ansible --version
ansible 2.7.0
  config file = /home/myuser1/infra-setup-plugins/ansible.cfg
  configured module search path = ['/home/myuser1/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/myuser1/.pyenv/versions/3.6.8/lib/python3.6/site-packages/ansible
  executable location = /home/myuser1/.pyenv/versions/3.6.8/bin/ansible
  python version = 3.6.8 (default, Feb  4 2019, 14:18:59) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]

$ pip install ansible-lint
Successfully installed ansible-lint-4.0.1

$ ansible-lint --version
ansible-lint 4.0.1
```

参考
https://qiita.com/Kodaira_/items/feadfef9add468e3a85b
https://qiita.com/silverskyvicto/items/424a002065d7b0090802

AmazonLinux2の参考
https://qiita.com/tisk_jdb/items/01bd6ef9209acc3a275f

#### ansible-lint

ベストプラクティスに沿った書き方をするように確認してメッセージ出すツールです。
roleを羅列したplaybookを指定すると色々でてきます。

```
$ ansible-lint playbook.yml
```

デフォルトルールはこちら
https://docs.ansible.com/ansible-lint/rules/default_rules.html

スキップさしたいやつは-xオプションで指定することも設定ファイルに書くこともできるっぽいです。

```
$ ansible-lint -x 405,403 playbook.yml
```

https://docs.ansible.com/ansible-lint/configuring/configuring.html#configuration-file
405のルールはansible-lint4.1から消されるようなissueを見かけました。
https://github.com/ansible/ansible-lint/issues/456

#### ファイルに文字列が含まれなかったらtask作動

lintかけたらcommandやshellつかうときは条件定義しろというようなオコだったためwhen足したら2.9からパイプな書き方がダメっぽいWarnでたのでその対応。

```
$ cat grub.yml 
- hosts: localhost
  gather_facts: no
  tasks:

  - name: fuga
    debug: var=filecontent
    vars:
#      filecontent: "{{ lookup('file', '/tmp/cmdline') }}" 
      filecontent: "{{ lookup('file', '/tmp/cmdline2') }}" 

  - name: hoge
    shell: /bin/echo "file not much(ok)" >> /tmp/hoge/ttt.txt
#    shell: /bin/echo "file much(ok)" >> /tmp/hoge/ttt.txt
    when: filecontent is not search("transparent_hugepage")
    vars:
#      filecontent: "{{ lookup('file', '/tmp/cmdline') }}" 
      filecontent: "{{ lookup('file', '/tmp/cmdline2') }}" 

$ cat /tmp/cmdline
BOOT_IMAGE=/boot/vmlinuz-3.10.0-514.26.2.el7.x86_64 root=UUID=63eec43b-cebd-4fd0-b92f-5518d45cfb00 ro crashkernel=auto console=ttyS0,38400n8 transparent_hugepage=never

$ cat /tmp/cmdline2

$ ansible-playbook -c local grub.yml -vv
TASK [fuga] ************************************************************************************************************************************************
task path: /home/myuser1/myrepo/grub.yml:5
ok: [localhost] => {
    "filecontent": "" 
}

TASK [hoge] ************************************************************************************************************************************************
task path: /home/myuser1/myrepo/grub.yml:11
changed: [localhost] => {"changed": true, "cmd": "/bin/echo \"file not much(ok)\" >> /tmp/hoge/ttt.txt", "delta": "0:00:00.003179", "end": "2019-02-05 11:43:08.959428", "rc": 0, "start": "2019-02-05 11:43:08.956249", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}

$ cat /tmp/hoge/ttt.txt 
file not much(ok)
file much(ok)
file much(ok)
file not much(ok)
```

参考：
https://docs.ansible.com/ansible/latest/user_guide/playbooks_tests.html
https://docs.ansible.com/ansible/latest/user_guide/playbooks_lookups.html
https://confluence.sharuru07.jp/pages/viewpage.action?pageId=5898263
https://qiita.com/ryurock/items/639e5f7e49d25c3b6d75

ちなみにDepulicateメッセージでてたの↓こちら。

```
[DEPRECATION WARNING]: Using tests as filters is deprecated. Instead of using `result|search` use `result is search`. This feature will be removed in 
version 2.9. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
```

以下のあたりだとパイプでやってるのでそれをもとに書いたら上記のワーニング出たかんじです。
https://qiita.com/waterada/items/69e607a4c227d232eabd

#### statモジュールのregisterのwith_itemsのなおしかた

statモジュールのregisterのwith_itemsのなおしかたがちょっと惑って単体テストしてみていい感じに動いたので貼っておきます。
ふつうのwith_itemsのリストだったらポーティングガイドどおりなおせばよさそう。
要はloopをつかう感じかな。

```
$ cat disable.yml 
- hosts: localhost
  gather_facts: no
  tasks:

  - name: Check if log exists
    stat:
      path: "/tmp/hoge/{{ item }}" 
    loop:
        - aaa
        - bbb
        - vvv
    register: check_file

  - name: debug check_registers
    debug: var=check_file.results

  - name: Disable Config
    command: mv /tmp/hoge/{{ item.item }} /tmp/hoge/{{ item.item }}.org
    when: item.stat.exists
    loop: "{{ check_file.results }}" 

$ ansible-playbook -c local disable.yml 
```

参考：
https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html?highlight=register#using-register-with-a-loop

あとwithとloopの違いに言及されていらっしゃる方が。flattenの動作が異なるようです。
https://tekunabe.hatenablog.jp/entry/2018/06/05/ansible_loop_with_list

```
 - name: install httpd
   yum:
-    pkg: "{{ pkg_name }}"
+    pkg: "{{ item }}"
     state: latest
+  loop: "{{ pkg_name | flatten(levels=1) }}"
+  vars:
+    pkg_name:
+      - "{{ packages1 }}" 
+      - "{{ packages2 }}"
```
なんか依存のあるやつをループさすというよりはまとめてドーンと入れたいときにflattenさすとそういう動きになるようです。loopを書き忘れて以下のようなエラーが出ていました。

```
The error was: AttributeError: 'list' object has no attribute 'endswith'
```

追記。ディレクトリやシンボリックリンクといったstatが存在しない場合にエラーが出るが判別したいというときは定義されているかどうかを見てみるかんじにするとエラーでないです。

```
- name: create Symbolic link
  file:
    src: /path_to_src_file
    dest: /path_to_dest_file
    state: link
  when:
    - not destfile1.stat.islink is defined
```