Ansibleを使ってStorage(ONTAP)を管理する3【変数編1】

## はじめに

本記事では[Ansibleを使ってStorage(ONTAP)を管理する1 【Rocky LinuxへAnsible Install編](https://qiita.com/s_yosh1d/items/f437b8ea284a6e90936f)】の続きとして、ONTAP管理の為のインベントリファイルやPlaybook作成に関する内容となります。
今回は内容は狭いですが**主にインベントリファイルのグループ化や変数について記載を致します。**

## 何をしたい？できる？
- インベントリファイルへグループ名を記載してAnsibleのPlaybookを実行する
- インベントリファイルに変数を追記してみる
- ONTAPの操作の際にインベントリファイルへ変数を記載してみる

## ONTAPの Ansibleモジュールについて
AnsibleからONTAPのVolume作成やLIF作成とタスクを実施する際には、いわゆるCIL操作のコマンド毎に対応するAnsibleモジュールが存在しますので、関係するモジュールをそれぞれ使用して管理操作を行います。
また、各モジュールを実行するにあたってONTAPの認証情報が必要になります。
(省略できない)

以下の図のように、仮にDNS設定とVolume削除の内容を同一のPlaybookに記載して実行しようとしても認証情報をそれぞれ記載しなくてはいけない為、各タスクに直接記載するのは冗長な形になります。
この記事では、その手間を減らすために、インベントリファイルに変数を記載して動作を確認してみるといった内容となります。
|<img width="500" alt="qiita-square" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268577/9d6eaca6-9b73-b1d8-ed10-41891376daf0.png>
|:-:|
## インベントリファイルへの変数について
別ファイルに変数を記載する事を除くと、以下の2つが設定可能です。

- ホスト変数
- グループ変数

インベントリファイルでは、操作対象のターゲット(サーバ等)を記載することになりますが、
この操作対象について、ファイル内でグループ化することができます。
インベントリファイルに記載しているターゲットであるホスト名以下に記載している変数がホスト変数となり、作成したグループに対してvars:以下に記載している変数がグループ変数になります。


|<img width="600" alt="qiita-square" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268577/a411855e-1fe7-ed22-0145-1f7692d7a7bb.png>
|:-:|

## 記事における環境情報
本記事では、以下の環境で実施した内容となります。
- Rocky Linux : 9.1
- Python      : 3.9.14
- Ansible (Core): 2.14.1
- netapp-lib    : 2021.6.25
- netapp.ontap  : 22.1.0

環境のイメージとしては以下の通りです。

|<img width="500" alt="qiita-square" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268577/25d87743-80fd-3ba6-dc03-e5ef5956f30f.png>
|:-:|
## 設定手順
**まずは、グループ指定の挙動の違いについてまずは確認してからインベントリファイルへ変数を記載してどのような挙動になるか確認**していきます。
そして最後に、インベントリファイルにONTAP用の変数を記載し動作するのか確認します。


### 1. インベントリファイルの修正

以下のような形でインベントリファイルを記載します。
- 全ホストはallというグループに所属
- Linuxというホストは階層化された子グループに所属しない
- Ansibleというホストはall以下にあるgroup01という子グループに所属

```bash:
> cat inventory.yml
---
all:
  hosts:
    Linux:
      ansible_host: 172.16.10.148
  children:
    group01:
      hosts:
        Ansible:
          ansible_host: 172.16.10.180
...
```

### 2. Playbookの作成

とりあえず、インベントリファイル内の全ホストにpingを実行するPlaybookを作成します。
ここでは[前回の記事](https://qiita.com/s_yosh1d/items/6774760fd046c0314618)で記載したChatGPTを使ってPlaybookを作成してます。
<img width="500" alt="qiita-square" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268577/55dbed09-f0bc-470a-3885-11af36a9f977.png>

```bash:
>  cat playbook_ping.yml
---
- name: "Ping all hosts"
  hosts: all
  gather_facts: no
  tasks:
    - name: "Ping all hosts"
      ping:
...
```

### 3. 全ターゲットへのPlaybookの実行
Playbookに記載されているhosts: all宛(登録しているホスト)にpingが実施されるので、インベントリファイルの2つのホストへpingが実行されます。

```bash:
>  ansible-playbook -i inventory.yml  -u user01 playbook_ping.yml --ask-pass
SSH password:

PLAY [Ping all hosts] ***************************************************************************************************************

TASK [Ping all hosts] ***************************************************************************************************************
ok: [Linux]
ok: [Ansible]

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

```

### 4. group01を指定してPlaybookの実行
同じインベントリファイルとPlaybookを使用しますが、ansible-playbookで-lオプションを使いgroup01を指定する事で、操作対象を指定する事ができます。

```bash:
>  ansible-playbook -i inventory.yml -l group01 -u user01 playbook_ping.yml --ask-pass
SSH password:

PLAY [Ping all hosts] ***************************************************************************************************************

TASK [Ping all hosts] ***************************************************************************************************************
ok: [Ansible]

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

### 5. インベントリファイルにホスト変数とグループ変数を記載してPlaybookの実行
今まではansible-playbookコマンドで--u user01でユーザ名指定と--ask-passでパスワードを都度入力していましたが、**インベントリファイルにアカウント情報を記載する事で--ask-passを指定無しで動く事を確認**します。

グループ変数はホスト名下のvars:へ記載を実施します。

なお、インベントリファイルは以下の通りアカウントを直書きしています。
(ここではあえて暗号化してないです)
```bash:
>  cat inventory2.yml
---
all:
  hosts:
    Linux:
      ansible_host: 172.16.10.148
      ansible_user: user01
      ansible_password: XXXXXXX

  children:
    group01:
      vars:
        ansible_user: user02
        ansible_password: XXXXXXX
      hosts:
        Ansible:
          ansible_host: 172.16.10.180
```

**インベントリファイルへアカウントの記載がされる事で、-u でのユーザ名指定と--ask-passのオプションを指定しないでPlaybookが動く事を確認します。**
```bash:
>  ansible-playbook -i inventory2.yml playbook_ping.yml

PLAY [Ping all hosts] ***************************************************************************************************************

TASK [Ping all hosts] ***************************************************************************************************************
ok: [Linux]
ok: [Ansible]

PLAY RECAP **************************************************************************************************************************
Ansible                    : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
Linux                      : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

### 6. 変数の値を暗号化する場合
アカウント情報のようなセキュリティの観点から直接記載したくないものについては、Ansible Vaultを使用して変数の値を暗号化することができます。

以下の例のように、**ansible-vault encrypt_stringコマンドを利用し、出力された!vault |の行から始まる暗号化された文字列をインベントリファイルへ記載**します。

コマンド実行後の**New Vault password部分については、ansible-playbookコマンドの引数に--ask-vault-passを指定し復号用で使うパスワードを入力**します。

**Reading plaintext input from stdinの後に暗号化したい文字列を入力し、[Ctrl+d]で入力終了**となります。
コマンド例ではpasstest123456という文字列を暗号化した例です。

```bash:
>   ansible-vault encrypt_string
New Vault password:
Confirm New Vault password:
Reading plaintext input from stdin. (ctrl-d to end input, twice if your content does not already have a newline)
passtest123456
Encryption successful
!vault |
          $ANSIBLE_VAULT;1.1;AES256
          34656638373035666334323431646138383437386132646230386132386237653934346532366538
          3833636438333237316135303262613066336531646338340a393563633838633636653530356235
          37363262343362303338643835666637653638373434643463306135383636653034386365353434
          6266366463316166300a663166353165383061633235363135343066646561656138643561343163
          3534
```

インベントリファイルへ記載すると以下のような形になります。
```bash:
>   cat inventory3.yml
---
all:
  hosts:
    Linux:
      ansible_host: 172.16.10.148
      ansible_user: user01
      ansible_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          34656638373035666334323431646138383437386132646230386132386237653934346532366538
          3833636438333237316135303262613066336531646338340a393563633838633636653530356235
          37363262343362303338643835666637653638373434643463306135383636653034386365353434
          6266366463316166300a663166353165383061633235363135343066646561656138643561343163
          3534

  children:
    group01:
      vars:
        ansible_user: user02
        ansible_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          34656638373035666334323431646138383437386132646230386132386237653934346532366538
          3833636438333237316135303262613066336531646338340a393563633838633636653530356235
          37363262343362303338643835666637653638373434643463306135383636653034386365353434
          6266366463316166300a663166353165383061633235363135343066646561656138643561343163
          3534
      hosts:
        Ansible:
          ansible_host: 172.16.10.180
```

暗号化された情報を使ってPlaybookを実行する場合は、--ask-vault-passオプションを使います。
(ansible-vault encrypt_stringで指定した復号化パスワードを入力します)

```bash:
>  ansible-playbook -i inventory3.yml playbook_ping.yml --ask-vault-pass
Vault password:

PLAY [Ping all hosts] ***************************************************************************************************************

TASK [Ping all hosts] ***************************************************************************************************************
ok: [Linux]
ok: [Ansible]

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

```


### 7. ONTAP用アカウントをインベントリファイルへ記載しPlayBook実行

グループ変数を使ったONTAP管理でインベントリファイルへ修正する前にPlaybookは以下の点を修正しています。

- **svm_userとsvm_passwordをの値部分を変数で表記　(実際の値を記載しない)**
- **hostsをgroup01に変更**


```bash:
>  cat playbook_svm_info2.yml
---
- name: ONTAP Info
  hosts: group01　　　　　　　　　　　　　　　<===localhostからgroup01に変更
  collections: netapp.ontap
  gather_facts: no
  become: no
  vars:
    ansible_python_interpreter: /usr/bin/python3
  tasks:
    - name: run ONTAP gather facts for vserver info
      na_ontap_rest_info:
        hostname: 172.16.10.147
        username: "{{ svm_user }}"　　　　　　<===インベントリファイルへ記載する変数で表記
        password: "{{ svm_password }}"　　　　<===インベントリファイルへ記載する変数で表記
        https: true
        validate_certs: false
        use_rest: Always
        gather_subset:
        - svm/svms
```

インベントリファイルに対しては、Playbookで使用している変数を記載します。
この例では、変数の値を暗号化していますが、以下の点を追記しています

- **svm_userとsvm_passwordという変数と値をgroup01のvarsに追記**



```bash:
>  cat inventory3.yml
---
all:
  hosts:
    Linux:
      ansible_host: 172.16.10.148
      ansible_user: user01
      ansible_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          33353737376639653965653233323430323862313632343565316131333165343830333734313364
          3661363233333031646339613563336464323537383562310a366533653838326431613364653962
          34346237303536356634633732626339306633393730383161626462356333306161653430616635
          3931393763303335320a623461363535346566643930373435373738613361663164303461383731
          3735

  children:
    group01:
      vars:
        ansible_user: user02
        ansible_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          36353130623338613735653864656431633735316464303133373964323066383632643434323735
          6564343162636463343736656530646233343839326338620a363036313734663931303931663630
          66396166383830396662306263326361653062303230373863313166353964616630363131363263
          3334616537616365360a383633383762363665353634303036653866386165646635386133336266
          3165
        svm_user: testuser
        svm_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          33353737376639653965653233323430323862313632343565316131333165343830333734313364
          3661363233333031646339613563336464323537383562310a366533653838326431613364653962
          34346237303536356634633732626339306633393730383161626462356333306161653430616635
          3931393763303335320a623461363535346566643930373435373738613361663164303461383731
          3735
      hosts:
        Ansible:
          ansible_host: 172.16.10.180
```

### 8. ONTAP用Playbookの実行
この例ではアカウント情報を暗号化しているので、ansible-playbook実行の際には--ask-vault-passオプションを使い復号化パスワードを入力して実行しています。

```bash:
>  ansible-playbook -i inventory3.yml playbook_svm_info2.yml --ask-vault-pass -v
No config file found; using defaults
Vault password:

PLAY [ONTAP Info] *******************************************************************************************************************

TASK [run ONTAP gather facts for vserver info] **************************************************************************************
ok: [Ansible] => {"changed": false, "ontap_info": {"svm/svms": {"_links": {"self": {"href": "/api/svm/svms?max_records=1024&fields="}}, "num_records": 1, "records": [{"_links": {"self": {"href": "/api/svm/svms/0cda076f-59a4-11ed-9583-d039ea17268b"}}, "name": "cifs100", "uuid": "0cda076f-59a4-11ed-9583-d039ea17268b"}]}}}

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




## 参考及びリンク
[Ansibleを使ってStorage(ONTAP)を管理する1 【Rocky LinuxへAnsible Install編](https://qiita.com/s_yosh1d/items/f437b8ea284a6e90936f)】

[Ansibleを使ってStorage(ONTAP)を管理する2【ChatGPTでVolume作成用Playbookを作成】](https://qiita.com/s_yosh1d/items/6774760fd046c0314618)