自分用メモ：rbenvとruby_buildをインストールしてrubyをインストールする手順でハマった話

ハマった話シリーズ。

#やりたいこと
・特定のユーザにのみrubyをインストールさせたい
・rubyのインストールにはrbenvとruby_buildを用いたい
・インターネットアクセスせず完全ローカル上で完結させたい
・すべてansible playbookで自動化すること

#ディレクトリ構成
```
├── roles
│   └──middle
│      └── ruby
│          └── files
│          │   └── opt
│          │       └── node1
│          │       │   └── .bash_profile
│          │       │   └── .rbenv # rbenvとruby_buildのzipパッケージはここに配置する
│          │       │       └── plugins # 必要なrpmはすべてここに格納
│          │       └── node2
│          │           └──以下node1と同一構成
│          └── tasks
│              └── main.yml
└── vars
    └── middle_var.yml
    └── usr_var.yml
```
※rubyに関係する箇所以外のnode情報は他で記述しているためここでは割愛


#参考
https://qiita.com/inouet/items/478f4228dbbcd442bfe8

#その他情報
・OSはCentOS7.4
・rubyはデフォルトでは2.0.0がインストールされている


##手順概要
1.グループ作成
2.ユーザーアカウント作成
3.ソースディレクトリ作成
4.ruby依存パッケージを事前にインストール
5.rbenvインストール
6.ruby_buildインストール
7..bash_profile配布と編集
8.シェルとソースのリフレッシュ
9.rubyインストール
10.rubyバージョン切り替え


##手順詳細
※ここではnode1とnode1_usrのみ記述するが、node2_usrも同様にymlに記述すること

1.グループ作成
usr_var.ymlでよしなに記述してある前提で書くので変数の個所は割愛

```
- name: ■ アカウント一覧 - Group
  group: 
    name: "{{ item.group }}"
    gid: "{{ item.gid }}"
  with_items:
    - "{{ node1_usr }}"
```
node2_usrも同様に記述する。

2.ユーザーアカウント作成

```
- name: ■ アカウント一覧 - ユーザ
  user:
    #state: absent #ユーザを削除するときはコメントを外す
    name: "{{ item.name }}"
    uid : "{{ item.uid }}"
    password: "{{ item.password | password_hash('sha512') }}"    #変数からパスワード情報を取得し、ハッシュ化してパスワードを設定
    group:  "{{ item.group }}"
    home :  "{{ item.home }}"
    shell: /bin/bash
    update_password: on_create    #ユーザ作成時パスワード設定
  with_items:
    - "{{ node1_usr }}"
  no_log: True #パスワード、マスク
  when: node1_usr #postgres_user
```


3.ソースディレクトリ作成

```
- name: ■ ソース用ディレクトリ作成
  file: path={{ item.path }} owner={{ item.owner }} group={{ item.group }} mode={{ item.mode }} state=directory
  with_items:
    - { path: "/opt/node1_usr/"          , owner: node1_usr , group: node1_usr , mode: "755" }
    - { path: "/opt/node1_usr/.rbenv/"         , owner: node1_usr , group: node1_usr , mode: "755" }
    - { path: "/opt/node1_usr/.rbenv/plugins/" , owner: node1_usr , group: node1_usr , mode: "755" }
```

4.ruby依存パッケージを事前にインストール
対象rpmは以下の通り
-bison.rpm
-bzip2.rpm"
-m4.rpm
-ncurses-devel.rpm
-readline-devel.rpm

バージョンは割愛。
後ほどインストールするrubyファイルもここで配布しておく。
-ruby.tar.bz2 [ruby公式からダウンロード](https://www.ruby-lang.org/ja/downloads/)

上記ファイルはまとめてrpmのフォルダに入れておく。

```
- name: ■ ruby RPM Copy
  copy:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
  with_items:
    - "{{ node1_rpm_cp }}"
  ignore_errors: "{{ ansible_check_mode }}"

- name: ■ ruby RPM Install
  yum:
    name: "{{ node1_rpm_install }}"
    state: present
  ignore_errors: "{{ ansible_check_mode }}"
```

node1_rpm_cpは配置したファイルをローカルに引っ張ってくる。
node1_rpm_installはruby依存rpmのみ先にインストールする。


5.rbenvインストール
インストールといってもzipファイルを解凍するだけ。
-rbenvmaster.zip [githubからダウンロード](https://github.com/sstephenson/rbenv/archive/master.zip)
→適当なフォルダに配置

```
- name: ■ rbenv Source File Copy
  copy:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
  with_items:
    - "{{ rbenv_source_cp }}"
  ignore_errors: "{{ ansible_check_mode }}"

- name: ■ rbenv Source Unzip node1_usr
  command: chdir=/opt/node1_usr/.rbenv/ unzip -o rbenv-master.zip
  ignore_errors: "{{ ansible_check_mode }}"
```
ここは変数を入れ込むとバグるらしい、、、原因不明、、、

6.ruby_buildインストール
5同様4で配置したzipファイルを解凍するだけ。
-ruby-build-master.zip [githubからダウンロード](https://github.com/rbenv/ruby-build/archive/master.zip)
→適当なフォルダに配置

```
- name: ■ ruby_build Source File Copy
  copy:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
  with_items:
    - "{{ ruby_build_source_cp }}"
  ignore_errors: "{{ ansible_check_mode }}"

- name: ■ ruby_build Source Unzip node1_usr
  command: chdir=/opt/node1_usr/.rbenv/plugins/ unzip -o ruby-builder-master.zip
  ignore_errors: "{{ ansible_check_mode }}"
```

7.rubyに必要なファイルの配布
.bash_profile を/opt/node1_usr/に配布する。
以下の通り編集する。最後の2行が大事。

```
# User specific environment and startup programs

PATH=$PATH:$HOME/bin
export PATH



export PATH="/opt/node1_usr/.rbenv/rbenv-master/bin:$PATH"
eval "$(rbenv init -)"
```

8.シェルとソースのリフレッシュ

```
- name: ■ Shell Refresh node1_usr
  become: yes
  become_user: node1_usr
  shell: exec $SHELL -l
  ignore_errors: "{{ ansible_check_mode }}"

- name: ■ .bash_profile Check Action node1_usr
  become: yes
  become_user: node1_usr
  shell: source ~/.bash_profile
  ignore_errors: "{{ ansible_check_mode }}"
```



9.rubyインストール
必要なバージョンがインストールされているかをまず確認する。
インストールされている場合はスキップする処理、されていない場合はインストールを続行する処理とする。

```
- name:  ■ Ruby Version Check Before Install node1_usr
  become: yes
  become_user: node1_usr
  stat: path=/opt/node1_usr/.rbenv/versions/n.n.n
  register: result

- name: ■ Ruby Install node1_usr
  become: yes
  become_user: node1_usr
  shell: bash -lc "RUBY_BUILD_CACHE_PATH=/opt/node1_usr/.rbenv/plugins/ rbenv install n.n.n"
  when: not result.stat.exists
```

10.rubyバージョン切り替え

```
- name: ■ Ruby Version Change node1_usr
  become: yes
  become_user: node1_usr
  shell: bash -lc "rbenv global n.n.n"
  ignore_errors: "{{ ansible_check_mode }}"
```

以上のコードはroles/middle/ruby/tasks/main.ymlに記述すること。

#ハマった箇所と理由
5.rbenvインストール
コマンドを実行する箇所に変数を指定するとそんなファイル・パスはないと言われてしまう。
詳細は不明だが、絶対パスで書くのが無難。

6.ruby_buildインストール
5同様の注意事項。
ファイル名が似ているため、middle_var.ymlに書くときは注意。
ずっとruby_buildのインストールにrbenv-master.zipを指定していたことに気が付くのに時間がかかったのは自分だけでいい。

7.rubyに必要なファイルの配布
予め/opt/node1_usr/内に作っておくのが無難。
改行コードが問題になることがあるので、LFで統一すること。
CRLFで何時間もハマった。

8.シェルとソースのリフレッシュ
そこまで大ハマりしたわけではないが、シェルとソースのリフレッシュはansibleを実行するユーザではなくrubyをインストールするユーザを指定すべき。
これを避けるためにはbecome変数を使用し、bash -lcでコマンドを実行すること。

9.rubyインストール
インストール済みの場合スキップ、未インストールの場合のみインストールという処理を考えるとき、条件に悩んだ。
ruby -vでバージョンを出してもよかったが、バージョンの数値のみ取得するのが骨が折れそうだった。
rubyのインストールディレクトリ配下のversionというディレクトリの配下にバージョン名でディレクトリができることを利用し、
このディレクトリをインストールしたいバージョンの番号の有無と判定することにした。registerとwhen変数がそれである。
また、rbenv install n.n.n(バージョン名)でrubyをインストールする場合、何も指定しないとWeb上のファイルを取得しに行ってしまう。
予めダウンロード・配置しておいたファイルを使用してインストールする場合には、RUBY_BUILD_CACHE_PATH で配置先のディレクトリを指定してやる必要があった。


以上の工程に3人日使ってしまい非常にもったいないことをしたので備忘録としておく。