VMwareモジュールのvmware_guest_file_operationでファイルのやり取りするよ（おまけもあるよ）

こちらは [Ansible Blogger 2018 （sponsored by Red Hat） Advent Calendar 2018](https://qiita.com/advent-calendar/2018/ansibleblogger) の9日目の記事です。

ここでは、VMwareモジュールの一つの `vmware_guest_file_operation` をメインに紹介したいと思います。

# 1. vmware_guest_file_operationドキュメント

[vmware_guest_file_operation](https://docs.ansible.com/ansible/latest/modules/vmware_guest_file_operation_module.html#vmware-guest-file-operation-module)

# 2. vmware_guest_file_operationの説明

<font color="#FC0107">vmware_guest_file_operationは、一言でいうとVMwareのVMにネットワーク経由ではなくAPI経由でファイルの送受信やディレクトリ作成などができるモジュールです。
そのため、Ansibleホストとファイルを送受信したいVMのネットワークが繋がっていなくてもやりとりができます。</font>
ただし、VM内でVMwaretoolsが動作していることが前提となります。
余談ですが、結構前に [vmware-guest-file-operation](https://github.com/sky-joker/vmware-guest-file-operation) というツールを個人的に作っていました。
このツールはpythonで出来ており、同じようにAPI経由でファイルの送受信ができます。
このツールを作っていた時は、まだAnsibleのバージョンが2.3位だった時でVMwareのモジュールも少なく、作っていたツールをお勉強がてらAnsibleのモジュールに移行してみようかなと思っていたら2.5で偶然同じような名前で出て来たのでラッキーだと思いました :)

# 3. モジュールが使える対象

vCenterまたはESXiに対して使えます。

# 4. モジュール使い方例

## 4-1. 環境

|   項目  | バージョン |
|---------|------------|
| OS      | CentOS7.5  |
| Ansible | 2.7.4      |
| Python  | 3.6.6      |

![環境図.png](https://qiita-image-store.s3.amazonaws.com/0/180118/a479bbda-10e3-6ba2-6f4d-d0ad1eee5201.png)

ここでは、vCenter配下で管理しているVMであるtest01からtest02に対してファイルの送受信をしてみます。

## 4-2. 準備

モジュールを動作させるために必要なモジュールをインストールします。

```
pip3 install pyvmomi
```

## 4-3. ファイル送信例Playbook

`example.txt` というファイルを `test02` の `/opt/example.txt` へAPI経由でアップロードしてみたいと思います。

```yaml:main.yml
---
- name: example file upload.
  hosts: localhost
  gather_facts: no
  tasks:
    - vmware_guest_file_operation:
        hostname: 192.168.0.111
        username: administrator@vsphere.local
        password: password
        validate_certs: no
        datacenter: DC
        vm_id: test02
        vm_username: root
        vm_password: password
        copy:
          src: example.txt
          dest: /opt/example.txt
          overwrite: yes
```

**パラメーター説明**

|  パラメーター  |                        説明                        |
|----------------|----------------------------------------------------|
| hostname       | vCenter or ESXiのIP or ホスト名                    |
| username       | vCenter or ESXiへログインするユーザー名            |
| password       | vCneter or ESXiへログ新するユーザーのパスワード    |
| validate_certs | サーバ証明書の検証                                 |
| datacenter     | 対象VMが存在するデータセンター名、ESXiの場合は不要 |
| vm_id          | 対象VM名                                           |
| vm_username    | 対象VMのゲストOSユーザー名                         |
| vm_password    | 対象VMのゲストOSユーザー名のパスワード             |
| copy           | ファイルを送る                                     |
| copy/src       | 送るファイル                                       |
| copy/dest      | 対象VM内に保存するファイルの送り先                 |
| overwrite      | ファイルの上書き許可                               |


これをtest01で実行してみます。

```shell-session
[root@test01 example]# ls
example.txt  main.yml
[root@test01 example]# ansible-playbook main.yml
 [WARNING]: Unable to parse /etc/ansible/hosts as an inventory source

 [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 [example file upload.] **********************************************************************************

TASK [vmware_guest_file_operation] ***************************************************************************
changed: [localhost]

PLAY RECAP ***************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0
```

test02にファイルが送られたか確認します。

```shell-session
[root@test02 ~]# ls /opt/
example.txt
[root@test02 ~]# cat /opt/example.txt
This is Test Message.
```

ファイルが送られていることが確認できました。

## 4-4. ファイル受信例Playbook

ファイルを受信する場合は以下のようにします。

```yaml:main.yml
---
- name: example file download.
  hosts: localhost
  gather_facts: no
  tasks:
    - vmware_guest_file_operation:
        hostname: 192.168.0.111
        username: administrator@vsphere.local
        password: password
        validate_certs: no
        datacenter: DC
        vm_id: test02
        vm_username: root
        vm_password: password
        fetch:
          src: /opt/example.txt
          dest: example.txt
```

**パラメーター説明**

| パラメーター |                                 説明                                 |
|--------------|----------------------------------------------------------------------|
| fetch/src    | ダウンロード元のファイル                                             |
| fetch/dest   | 保存するファル名とパス(パスを指定しない場合はカレントに保存されます) |

<font color="#FC0107">fetchの場合はoverwriteは使えません</font>

## 4-5. 注意点

あくまでもAPI経由でファイルのやりとりをするためネットワークとやる場合とはスループットがそれなりに落ちます。
また、サイズの大きなファイル(数GBなど)をやりとりしようと思うと負荷がかかったり、かなり遅いのでオススメはしません。

## 4-6. まとめ

`vmware_guest_file_operation` を使うことで直接ネットワークが繋がっていなくてもファイルのやりとりができることがわかりました。
今までは踏み台を経由してファイルをやりとりしたり、別ネットワーク経由でやっていたことがAnsibleモジュールを使うことで簡単にできるようになりました。
今回はLinuxを例にしましたが、対象がWindowsでも問題なくやりとりができます。

# 5. おまけ

さて、ここからはおまけです。
ただ、ファイルのやりとりをするだけだと面白くないと思って以下のことを考えてみました。

<font color="#FC0107">test02にansibleを入れてtest01からplaybookを送り込んで実行すればネットワーク経由じゃなくてもansibleで操作できるのでは？</font>

と、言うのでやってみました。
追加で使うモジュールは [vmware_vm_shell](vmware_vm_shell) です。

## 5-1. vmware_vm_shellについて

`vmware_vm_shell` はVMのゲストOSでコマンドを実行するモジュールです。
前までは、ゲストOS内でコマンドを実行したらバックグラウンドで実行して処理が完了されたことになってしまい処理待ちをしなかったので [vmware_vm_shell_wait](https://github.com/sky-joker/ore-ore-ansible/blob/master/modules/cloud/vmware/vmware_vm_shell_wait.py) と言うツールを作っていたのですが、2.7からは処理待ちをするオプションが追加されてました。
本来は自分で作った `vmware_vm_shell_wait` を使ってみようと思った（だからおまけだった）のですが、オプションが追加されちゃっていたのでそっちを使ってみます :)

<font color="#FC0107">本当は、vmware_vm_shell_wait作って処理待ちが出来るようになったぜ「ﾄﾞﾔｧ」をしたかったw</font>


## 5-2. ApacheをインストールするPlaybok(送り込むやつ)

以下は、test02へアップロードするApacheのインストール及び起動をするPlaybookです。

```yaml:apache_install.yml
---
- name: install apache playbook.
  hosts: localhost
  gather_facts: no
  tasks:
    - name: install apache.
      shell: yum -y install httpd

    - name: start apache.
      systemd:
        state: started
        enabled: yes
        name: httpd
```

## 5-3. main playbook

以下は、test01で実行してAPI経由からtest02へApacheをインストールするPlaybookを送り込んで実行して結果をファイルに出力してダウンロードするためのPlaybookです。

```yaml:main.yml
---
- name: Install apache on test02.
  hosts: localhost
  gather_facts: no
  tasks:
    - name: install ansible.
      vmware_vm_shell:
        hostname: 192.168.0.111
        username: administrator@vsphere.local
        password: password
        validate_certs: no
        datacenter: DC
        vm_id: test02
        vm_username: root
        vm_password: password
        vm_shell: /usr/bin/yum
        vm_shell_args: -y install ansible
        wait_for_process: yes

    - name: upload apache install playbook to test02.
      vmware_guest_file_operation:
        hostname: 192.168.0.111
        username: administrator@vsphere.local
        password: password
        validate_certs: no
        datacenter: DC
        vm_id: test02
        vm_username: root
        vm_password: password
        copy:
          src: apache_install.yml
          dest: /opt/apache_install.yml
          overwrite: yes

    - name: execute apache install playbook.
      vmware_vm_shell:
        hostname: 192.168.0.111
        username: administrator@vsphere.local
        password: password
        validate_certs: no
        datacenter: DC
        vm_id: test02
        vm_username: root
        vm_password: password
        vm_shell: /usr/bin/ansible-playbook
        vm_shell_args: apache_install.yml | /usr/bin/tee apache_install_result.txt
        vm_shell_cwd: /opt
        wait_for_process: yes

    - name: download apache install playbook result from test02.
      vmware_guest_file_operation:
        hostname: 192.168.0.111
        username: administrator@vsphere.local
        password: password
        validate_certs: no
        datacenter: DC
        vm_id: test02
        vm_username: root
        vm_password: password
        fetch:
          src: /opt/apache_install_result.txt
          dest: apache_install_result.txt
```

**パラメーター説明**

`vmware_vm_shell` の一部パラメーター説明です。

|   パラメーター   |                         説明                         |
|------------------|------------------------------------------------------|
| vm_shell         | ゲストOS内で実行するコマンド                         |
| vm_shell_args    | ゲストOS内で実行するコマンドの引数                   |
| vm_shell_cwd     | コマンドを実行する時に移動するディレクトリ           |
| wait_for_process | ゲストOS内で実行したコマンドの処理待ちをするかどうか |


## 5-4. 実行

上記のPlaybookをtest01で実行した結果が以下になります。

[![asciicast](https://asciinema.org/a/knGmJFxuT2zAMUm7H43LkVI4G.svg)](https://asciinema.org/a/knGmJFxuT2zAMUm7H43LkVI4G)

test02で実行したansibleの実行結果を見る限りapacheは問題なくインストールされて実行されていますね :)

## 5-5. まとめ

`vmware_guest_file_operation` と `vmware_vm_shell` を組み合わせることでAnsibleホストとネットワークで繋がっていなくてもAnsibleで操作ができることができました :)
他の使い方でも便利さが発揮できそうですね！

# 6. 最後に

今まで足りなかった機能を自作モジュールなどで作っていましたが、どんどんとその機能が取り込まれていったり前より沢山のVMwareモジュールが増えて嬉しいです :)
ただ、いくつかまだ欲しい機能があるが機能としては実装されていないので自分でもお勉強用としていくつか作っていきたいと思います。