Ansible2.xのexpectを使ってAnacondaをインストールする


# 背景

[Anacondaの本家](https://www.continuum.io/)で提供されているLinux向けのインストーラーはBashで実行し対話式でインストール先を指定したり、パスの設定をしたりという動きになっています。

このAnacondaをAnsibleを使って複数サーバにインストールする時に、対話式であることがネックになります。以前はexpectを使って自力でなんとかしていたのですが、2.x系では[expectのmodule](http://docs.ansible.com/ansible/expect_module.html)が追加されたそうなので、その動作確認も兼ねてAnsible2.x系を使ってAnacondaのインストールをしてみることにしました。


# やりたいこと
- SSHで接続できる対象サーバにAnacondaをインストールする
- 全部Ansibleで完結させる


# 動作確認環境
- ansibleを実行するサーバ
	- hostname:ansible-server
	- OS:Ubuntu14.04
- 対象サーバ
	- hostname:test-server
	- OS:Ubuntu14.04

この2つのサーバを[Vagrant](http://qiita.com/awakia/items/895b3d61311b19737237)で用意して動作確認しました。



# 大雑把な流れ
1. Ansibleの実行環境構築
2. AnacondaのInstall時の挙動を確認
3. 2の内容を踏まえてansible-playbookを作成
4. ansible実行後の動作確認


## 1. Ansibleの実行環境構築

Ansibleはapt-getでインストールできますが、OSやバージョンによって2.x系をインストールする手順が少し異なります。
Ubuntu14.04の場合は以下のコマンドでインストールできます。

```Bash:Ansibleインストールコマンド
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible
```

Ubuntu意外のOSでの導入方法は[AnsibleのInstallationページ](docs.ansible.com/ansible/intro_installation.html)を参照してください。

インストールが完了したら、以下のコマンドでバージョンを確認します。バージョンが返ってきたらインストール成功です。

```Bash:Ansibleバージョン確認コマンド
$ ansible --version
ansible 2.1.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
```


## 2. AnacondaのInstall時の挙動を確認

Anacondaのインストーラーを実際に実行して、どのようにそれぞれの質問に対応すべきか確認します。今回の動作確認では「Anaconda3-4.1.1-Linux-x86_64.sh」を利用しています。

```Bash:Anacondaインストールコマンド
bash Anaconda3-4.1.1-Linux-x86_64.sh
```

実行すると、以下の部分で入力を求められます。

```DOS:Anacondaインストール時の標準出力1

Welcome to Anaconda3 4.1.1 (by Continuum Analytics, Inc.)

In order to continue the installation process, please review the license
agreement.
Please, press ENTER to continue
>>>
```

expectのmoduleで挙動を定義するために、途中で入力を求められる部分が重要になります。
**1つめの「>>>」は単にENTER**すれば良いのでそれを覚えておきます。
処理をすすめるにENTERします。次に以下のところで入力を求められます。

```DOS:Anacondaインストール時の標準出力2
(略)
Anaconda contains open source software packages from third parties. These
--More--
```

この部分はスペースでページ送りすれば良い部分です。
ただ、この部分もちゃんとexpectのmoduleに書いてあげる必要があります。
標準出力には「--More--」と表示されていますが、実はこれは「:」を置き換えられている(※)ので
**「:」ときはスペース**として覚えておきます。
※：Macで試すと「:」が表示されるんです。Ubuntuだと気を利かせて置き換えてくれてる？

更にすすめると、以下のように同意するか求められます。

```DOS:Anacondaインストール時の標準出力3
(略)
Do you approve the license terms? [yes|no]
>>>
```

ここではもちろん「yes」なので、 **2つめの「>>>」はyes**とおぼえておきます。
次にインストールパスの確認が来ます。

```DOS:Anacondaインストール時の標準出力4
(略)
Anaconda3 will now be installed into this location:
/home/vagrant/anaconda3

  - Press ENTER to confirm the location
  - Press CTRL-C to abort the installation
  - Or specify a different location below

[/home/vagrant/anaconda3] >>>
```

デフォルトでよければENTERで良いので **3つめの「>>>」はENTER**と覚えておきます。
ENTERするとパッケージのインストールがスタートします。
パッケージのインストールが終わると、最後にパスを.bashrcに追加するか確認されます。

```DOS:Anacondaインストール時の標準出力5
(略)
installation finished.
Do you wish the installer to prepend the Anaconda3 install location
to PATH in your /home/vagrant/.bashrc ? [yes|no]
[no] >>>
```

個人的には.bashrcに追加してほしいので **4つめの「>>>」はyes**と覚えておきます。
これでインストールまでの挙動の確認は完了です。


## 3. 2の内容を踏まえてansible-playbookを作成

2で確認した挙動をもとにAnsibleのexpectのmoduleを記述します。
ansible-playbook全体は[github](https://github.com/nyk0401/ansible2_expect)にアップしているので、他の部分も確認したい場合はそちらを参照してください。

先程挙動を確認した結果をresponsesの下に書きます。

```Python:roles/anaconda/tasks/main.ymlの抜粋
- name: install anaconda3
  expect:
    chdir: "/home/{{ target_user }}"
    command: "bash {{ anaconda_script }}"
    timeout: 360
    responses:
      '>>>': '\n'
      ':': ' '
      '>>>': 'yes'
      '>>>': '\n'
      '>>>': 'yes'
  become: true
  become_method: su
  become_user: "{{ target_user }}"
  
```

Anacondaはgroup_vars/allで指定したtarget_userの権限でインストールしたいので以下のように記述しています。

```Python:roles/anaconda/tasks/main.ymlの抜粋
  become: true
  become_method: su
  become_user: "{{ target_user }}"
```

expectのmoduleを使うためにpexpectをpipでインストールしないといけないので
expectのmoduleよりも前に以下のような記述も必要です。

```Python:roles/anaconda/tasks/main.ymlの抜粋
- name: install pexpect by anaconda pip
  pip: name=pexpect
```



## 4. ansible実行後の動作確認

無事すべてのansible-playbookが流れると以下のように出力されます。

```DOS:Ansibleの実行結果
(略)
PLAY RECAP *********************************************************************
test-server                : ok=5    changed=4    unreachable=0    failed=0
```

最後に動作確認として、test-serverにログインしてAnacondaがインストールされたかを確認します。

```Bash:pythonコマンドの実行結果
vagrant@test-server:~$ python
Python 3.5.2 |Anaconda 4.1.1 (64-bit)| (default, Jul  2 2016, 17:53:06)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
```

パスがしっかり通っていれば対象のユーザで```python```コマンドを打つと↑のような形になり、先程インストールしたAnaconda4.1.1のPythonが利用されていることが確認できます。


# まとめ

今回はAnacondaのインストールのやり方をベースに説明しましたが、他にもAnacondaと同じようにBashで対話式にインストールするタイプのものは、同様の方法で対応することが可能だと思います。
もし、そういうものをAnsibleで入れる必要が出てきたら参考にしてみてください。

質問やコメントがあれば気軽にお願いします。