AnsibleでNetApp Solidfire Storage設定 

#AnsibleでNetApp Solidfire Storage設定 
NetApp は 積極的にAnsibleモジュールの開発をしており、NetApp Solidfireストレージの ElementOS用だけでも多数のモジュールが提供されています。
SolidfireはGUIで簡単に操作が可能ですが、繰り返し作業を実施したり、大量のVolumeを追加したりする際は、APIやAnsibleを利用すると便利です。

この記事では、Ansibleでのストレージ運用自動化の一例として、Ansible管理サーバの役割をするLinuxサーバへの Ansibleの導入から、簡単なPlaybookを実行するところまでを紹介しています。



##前提
以下の環境で試しています

- Cent 7.7
- Solidfire 12.2
- Ansible 2.10
- Python 3.6.8
- solidfire-sdk-python 1.7.0.152

なお、この記事で書かれている 手順やPlayBookは動作を保証されたものではありません。
各環境に合わせてテスト・確認をしたうえで自己責任にて利用していただければと思います。

##やってみること
1. Linuxサーバに Ansibleインストール 
2. 簡単なplaybookを実行
3. 複数ボリュームを作成するplaybookを実行


## 1. Ansibleインストール
まずはAnsibleを実行するための管理サーバの準備をします。

NetAppのサイトで、インストールからplaybookの実行までを解説しているサイトがあるので
こちらの手順を参考に作業を実施します。

[NetApp Ansible "getting-install-ansible" ページ](https://netapp.io/2018/10/08/getting-started-with-netapp-and-ansible-install-ansible/ )


前提にも記載している通り、今回はCentOS 7を利用した場合の作業例を記載します。


```shell:
$ sudo yum install epel-release -y
$ sudo yum install python3 -y
$ sudo pip3 install --upgrade pip setuptools
$ sudo pip3 install ansible-base
$ sudo pip3 install netapp-lib solidfire-sdk-python requests
```

Ansible 2.10からは 一部のBaseモジュールを除きAnsible Collectionからモジュール提供されるようになっています。
NetApp用モジュールを ansible-galaxyコマンドでインストールして実行可能な状態にしています。

```shell:
$ sudo ansible-galaxy collection install netapp.ontap netapp.elementsw -p /usr/share/ansible/collections
$ sudo chmod +rx /usr/share/ansible/collections
```  
※ "sudo: ansible-galaxy: コマンドが見つかりません"となった場合は、"/usr/local/bin"にPATHが通っていない可能性がありますので、sudoのPATH設定を確認してみてください。


これで、Ansibleがインストールされ、Solidfire用のモジュール(ElementSoftware)が使用できるようになりました。



## 2. 簡単なplaybookを実行してみる
volumeを作成する簡単なAnsibleのplaybookを作成します。

「na_elementsw_check_connections」というモジュールをつかって、
Ansibleを導入したLinuxサーバから、Solidfireへの接続確認を行います。

####ファイルの準備

まず最初にplaybookファイルを配置する作業ディレクトリを作成します。


```shell:
$ mkdir -p ~/ansible/tasks ~/ansible/vars
$ cd ~/ansible/tasks/
```

tasksディレクトリ配下に、sample.yamlというファイルを作成します。


```yaml:sample.yaml
---
- name: SF Playbook
  hosts: localhost
  connection: local
  gather_facts: no
  tasks:
    - name: sf check connection
      na_elementsw_check_connections:
        hostname: "<< Solidfire Management VIP >>"
        username: "<< Solidfire ユーザ名 >>"
        password: "<< Solidfire パスワード >>"
      register: result

```

####playbookの実行

ansible-playbookコマンドを実行してみます。
以下は正しく実行できたときの実行例となります。

```shell:実行例
$ cd ~/ansible/tasks
$ ansible-playbook  sample.yaml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [SF Playbook] *****************************************************************************************************

TASK [sf check connection] *********************************************************************************************
ok: [localhost]

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

$ 

```

## 3. 複数ボリュームを作成するplaybookを実行
次に、Linuxサーバ用にiSCSiボリュームを払い出すケースを想定して
以下の操作をまとめて行う playbookを作成します。

1. iSCSIボリュームを２つ作成
2. VAG(volumes access group)を作成し、LinuxサーバのInitiatorとボリュームを紐付け

利用するパラメータ値は以下となります。

| パラメータ名 | 値 | 備考
|:---:|---|---|
|ボリューム名|sfvol01 , sfvol02 | 
|ボリュームサイズ| 100GB|
|VAG名|sfvag01|
|Initiator| iqn.1994-05.com.redhat:fc7281d07007|

Ansibleのパラメータは別ファイルにすることも可能です。
共通パラメータや、可変パラメータは別ファイルにしておくとなにかと便利です。


####ファイルの準備

今回は ~/ansibleディレクトリ配下のvarsディレクトリ配下に3つのパラメータファイル、tasksディレクトリ配下に １つのplaybookファイルを作成します。

```shell:
~/ansible
├─ tasks
|  └─ main.yaml
└─ vars
   ├─ sf-common.yaml
   ├─ sf-volume.yaml
   └─ sf-vag.yaml
   
```

まずは~/ansible/varsディレクトリ配下に、sf-common,yaml , sf-volume.yaml , sf-vag.yaml の３つのパラメータファイルを作成します。

```yaml:①sf-common.yaml
cluster_mvip      : "<< Solidfire Management VIP >>"
cluster_login     : "<< Solidfire ユーザ名 >>"
cluster_pass      : "<< Solidfire パスワード >>"

```

```yaml:②sf-volume.yaml
sf_volume_create_list:
  - { name: sfvol01, size: 100 }
  - { name: sfvol02, size: 100 }

```


```yaml:③sf-vag.yaml
vag_create_list:
  - { name: sfvag01, ini: "iqn.1994-05.com.redhat:fc7281d07007", volid: [ sfvol01,sfvol02 ] }
```

次に、~/ansible/tasksディレクトリ配下に main.yamlファイルを準備します。

```yaml:main.yaml
---
- name: SF Volume Create
  hosts: localhost
  connection: local
  gather_facts: no
  vars:
    volume_account_id : "1"
  vars_files:
    - ../vars/sf-common.yaml
    - ../vars/sf-vag.yaml
    - ../vars/sf-volume.yaml
  tasks:
    - name: Create Volume
      na_elementsw_volume:
        hostname: "{{ cluster_mvip }}"
        username: "{{ cluster_login }}"
        password: "{{ cluster_pass }}"
        state: present
        name: "{{ item.name }}"
        account_id: "{{ volume_account_id }}"
        qos: {minIOPS: 100, maxIOPS: "15000", burstIOPS: "15000"}
        size: "{{ item.size }}"
        size_unit: gb
        enable512e: True
      with_items:
        - "{{ sf_volume_create_list }}"

    - name: Create Volume Access Group
      na_elementsw_access_group:
        hostname: "{{ cluster_mvip }}"
        username: "{{ cluster_login }}"
        password: "{{ cluster_pass }}"
        state: present
        name: "{{ item.name }}"
        initiators: "{{ item.ini }}"
        volumes: "{{ item.volid }}"
        account_id: "{{ volume_account_id }}"
      with_items:
        - "{{ vag_create_list }}"

```

これでplaybookを実行する準備は完了しました。

####playbookの実行

準備したファイルを使ってansible-playbookコマンドを実行します。

```shell:実行例
$ cd ~/ansible/tasks
$ ansible-playbook main.yaml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [SF Volume Create] *******************************************************************************************************************

TASK [Create Volume] **********************************************************************************************************************
changed: [localhost] => (item={'name': 'sfvol01', 'size': 100})
changed: [localhost] => (item={'name': 'sfvol02', 'size': 100})

TASK [Create Volume Access Group] *********************************************************************************************************
changed: [localhost] => (item={'name': 'sfvag01', 'ini': 'iqn.1994-05.com.redhat:fc7281d07007', 'volid': ['sfvol01', 'sfvol02']})

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

$
```

これでボリュームが作成され、登録したInitiatorからのアクセス許可を実施できました。

playbook内で、２つのtaskが実行されそれぞれ以下２つのモジュールが実行されています。
"na_elementsw_volume"モジュールで新規ボリュームを作成し、
"na_elementsw_access_group"モジュールでVAGにInitiatorとボリュームを関連づけ登録しています。


Solidfire側の準備が整ったので、サーバ側からiSCSIボリュームを検出でき、マウントして利用が可能な状態になっています。
今回は１台のサーバ用にInitiatorを１つだけ関連づけて登録しましたが、パラメータファイルのボリュームやVAGのリストを増やせば、複数のサーバ用に複数のInitiator用に一括してボリュームを作成・登録を行うことも可能です。


## まとめ
LinuxサーバでiSCSIボリュームをマウントするためのストレージ側で最低限必要な作業を自動化してみました。今回は、シンプルにAnsibleのモジュールを利用してみることを主眼にしていますので、実際にはRole化等も考慮して利用したほうが適切かと思います。

他にも色々モジュールが提供されていて、[AnsibleのCollections ページ](https://docs.ansible.com/ansible/latest/collections/netapp/elementsw/index.html#plugins-in-netapp-elementsw)に公開されているので、興味があれば是非試してみてください。