itamae 入門

Fukagawa.rbの準備用の投稿です。
まだドキュメントが十分じゃないようなので、中途半端にソースコードから解読したため、間違っているものがあるかも？
バージョンは1.1.4(2015/2/3時点)

*　注意事項
 - まだ未検証のものがあるけども、とりあえず投稿


## itamaeとは？
https://github.com/itamae-kitchen/itamae

* chefにインスパイアされて作った構成管理ツール。
* 以前はlightchefという名前で、chefを簡単にしたものを目指しているらしい。
* 内部で[specinfra](http://test.com)を利用している。(リソースの実行はspecinfraを呼び出している)



## 概要
### 事前準備
1.rubygemsでインストールしましょう。
`sudo gem install itamae`

2.`/tmp`の実行権限が必要(普通は必要ない)
`sudo chmod 777 /tmp`


### 作成するファイル
下記の２つのみ（ただし、ノードアトリビュートはオプション）  
* レシピ(rubyファイル) 
  - 「XXをインストールする」など実行するレシピを記述する。  
* ノードアトリビュート（json/yamlファイル）
  - レシピから参照する設定値を記述。
  - 例えば、ホスト名のように状況によって変わる変数を記述する。
  - node["test"]のようにnodeにハッシュが格納される。



## 実行方法
２つの方法があるらしい。ローカルとsshと。sshの中にはvagrant用の引数も用意されている。
下記コマンドの引数はアトリビュートファイルのnode.jsonと、レシピファイルのrecipe.rb。


### ローカルでの実行方法例
```例
sudo itamae local -j node.json recipe.rb
```

```凡例
sudo itamae local 引数 レシピ
```

#### 引数
引数に[]がある場合は任意パラメータ。

| 引数 [パラメータ] | 説明 |
|:--------|:--------|
| [-j  node_json]　|ノードアトリビュート(json)
| [-y node_yaml] |ノードアトリビュート(yaml)
| [--dry-run] | 実際には変更を加えないで変更される内容をみる
| [--ohai] | ohaiの値を取得可能にする。ただし、対象サーバにohaiが入っていない場合には自動的にインストールされる。



### ssh経由の実1行方法

```例
itamae ssh -j example/node.json -h 192.168.10.10 -p 22 -u user -i /path/to/private_key recipe.rb
```


```凡例
itamae ssh 引数　レシピ
```




|引数 [パラメタ]|説明|
|:--|:--|:--|
| [-j  node_json]　|ノードアトリビュート(json)
| [-y node_yaml] |ノードアトリビュート(yaml)
| [--dry-run] | 実際には変更を加えないで変更される内容をみる
| -h target_host | 対象のホスト(192.168.1.2等、vagrantであればdefault等）
| [-u user_name] | 対象のホストで実行するユーザ(指定がない場合はitamaeを実行しているユーザ(Etc.getlogin)
| [-i key] | sshキー？※未確認
| [-p port] | sshサーバポート
| [--ohai] | ohaiの利用(入っていない場合は自動インストール)
| [--vagrant]  |  vagrantを利用している場合に指定。`vagrant ssh-config`を実行した結果を利用する。
| [--ask_password true] | sshのパスワードの入力の要求をする。trueにせずにパスワードが必要となった場合、HighLine or Termiosが入っていないとパスワードを平文で入力させられる。
| [--sudo false] | sudoを実行しない場合に記載する。いくつかのレシピで/tmp/itamae_tmpのchmodをやろうとするため、ほとんど使う必要はない。

jsonとyamlが両方指定されている場合、jsonのアトリビュート設定のあとにyamlで上書きされる。Hash#merge!によって上書きされている。

## dry-runについて
実際には実行せずに、動作を確認する方法。


## レシピ記載方法
実行する内容をリソース単位で記載する。リソースはパラメータをブロック式内に記載できる。
また、ノードアトリビュートの変数をnode["a"]["b"]のように指定して利用できる。
リソースは「XXXのパッケージをインストールする」「XXXのファイルをリモートサーバにコピーする」「リモートサーバでXXXのコマンドを実行する」など設定の１アクション。


### リソース
標準で準備されているリソースについて記載する。
因みにパラメータがすべて任意の場合、ブロックを書く必要はない。

```slをインストールするレシピ
package "sl"
```

#### directory
ディレクトリを作る、あるいは既存のディレクトリの権限等を変更する。(action_create以外のactionメソッドがないため、deleteなどは準備されていない)
パラメータは作成するディレクトリパスのpath、アクセス権のmode、所有者のowner、所有グループのgroup
pathはdirectoryブロック引数として記載できる(ブロック内にpathを書くか、ブロック引数にpathを書くか、どっちが可読性が高い？)


```
directory "/path/to/directory" do
  action :create # デフォルトのため記載不要だが書いたほうが可読性が高い
  path "/path/to/directory" #任意指定。ここにパスを書くとブロック引数より優先される
  mode "777" # 任意指定
  owner "rasenn" # 任意指定
  group "rasenn" # 任意指定
end
```




#### execute
コマンドを実行する。
パラメータは実行コマンドのcommandと、実行ディレクトリのcwdのみ。
ブロック内にcommandを記述しない場合、ブロック引数が実行コマンドとなるが、可読性が悪いと思われる（ブロック使わないならいいかも）


```
execute "create an empty file" do
  command "touch /path/to/file" #　ここにコマンドを書かない場合、ブロック引数が実行されるため注意
  cwd "/path/to/command/execute" # 任意指定。コマンドを実行するディレクトリ
end
```

### file
ファイルを作成あるいは削除する。
パラメータは作成するファイルパスのpath、作成するファイルの中身のcontent、コピーするするファイルのcontent_file、アクセス権限のmode、所有者のowner、所有グループのgroup。
actionはデフォルトがcreateのためactionを指定しない場合はファイル作成になる。



```ファイル作成
file  "/path/to/file" do 
  path "/path/to/file" # 任意指定。ここに記載するとブロック引数より優先される。
  content_file "ファイル名" # 任意指定。指定したファイルをコピーする場合。
  content "ここにファイルの中身を書きます" # 任意指定。content_fileの指定がない場合に利用される。content_file,contentの両方がない場合は空ファイルが作成される
  mode "777" # 任意指定
  owner "rasenn" # 任意指定
  group "rasenn" # 任意指定
end
```

```ファイル削除
file "/path/to/file" do 
  path "/path/to/file" #任意指定。ここに記載するとブロック引数より優先される。
  action :delete
end
```


#### git

gitからfetchかcloneする。
パラメータはclone先ディレクトリのdestination、リポジトリURLのrepository、リビジョンのrevision(指定がない場合、`git ls-remote origin HEAD | cut -f1`の実行結果が利用される）

```
package "git"
git "/path/to/clone/directory" do 
  destination "/path/to/clone/directory" #　任意指定。指定がない場合、ブロック引数が利用される。
  repository "git repository url" # 必須 
  revision "HEAD" # 任意。指定がなければHEADのリビジョン
end
```


#### group
グループを作成する。(削除は準備されていない）
パラメータはグループ名のgroupname、グループIDのgid。


```
group "group name" do 
  groupname "グループ名" # 任意指定。指定がない場合ブロック引数が利用される。 
  gid 137892 # 任意指定
end
```


#### link
シンボリックリンクを作成する。
パラメータはリンクファイルのlink、リンク対象ファイルのto。

```
link "/link/from" do 
  link "リンク対象のファイル" #　必須指定。
  to "作成するシンボリックリンク" # 任意指定
end

```

#### package
パッケージをインストールする。(削除はない）

```
package "sl" do 
  name "パッケージ名" # 任意指定。指定がない場合はブロック引数が利用される。
  version "1.0" # 任意指定。
  options "" # 任意指定。インストール時のオプション。--force-yesとかか。
end
```

#### remote_directory
指定したディレクトリ配下のファイル・ディレクトリをまるごとコピーする。（再帰コピー。指定ディレクトリ自体はコピーされない）
chefと違って空ディレクトリもコピーされる。(chefってコピーされなかったよね？）
パラメータは作成・削除を指定するaction、コピー先のフォルダpath、コピー元ディレクトリのsource、アクセス権のmode、所有者のowner、所有グループのgroup。
コピー先のpathはすでにDirectoryが存在する必要があるので、最初にdirectoryリソースを記載したほうが良さげ。


```作成
directory "コピー先のパス"
remote_directory "/remote/copy/to/path" do
  action :create
  path "コピー先のパス" # 任意指定。指定がない場合はブロック引数が利用される。
  source "コピー元のパス" # 必須指定。再帰的にコピーされる
  mode "777" # アクセス権の指定
  owner "rasenn" # 所有者
  owner "rasenn" # 所有グループ
end
```


#####（要確認！）
あと、なぜか出来る削除機能。。。directoryリソースじゃないのか。。`rm -rf`なのかな？

```削除
remote_directory "/remote/delete/path" do
  action :delete
  path "削除するパス" # 任意指定。指定がない場合はブロック引数が利用される。
  source "？？？"
end
``` 

#### remote_file
リモート先のファイルを作成あるいは削除する（リソース`file`の拡張）
パラメータはコピー元ファイルのsource、リモートのコピー先のpath、アクセス権限のmode、所有者のowner、所有グループのgroup。
pathはファイル名も含めたパスを指定する(mvの第二引数と同じ)。指定しない場合、変なファイル名(1423232788.583672等)になる。
また、sourceにディレクトリは指定できない。

```ファイル作成
remote_file  "/path/to/file" do 
  path "リモートのコピー先パス" # 任意指定。ここに記載するとブロック引数より優先される。
  source "コピー元のファイルパス"  # 必須指定
  mode :777 # 任意指定
  owner :rasenn # 任意指定
  group :rasenn # 任意指定
end
```

fileを継承したがゆえに残ってしまっている感のあるファイル削除。
実際にはfileのaction_deleteを使うだろう。

```ファイル削除
remote_file "/path/to/file" do 
  action :delete
  path "/path/to/file" #任意指定。ここに記載するとブロック引数より優先される。
  source "何かしらのファイル"  # 必須指定
end
```



#### service

サービスの起動・停止・再起動・リロード・有効化・無効化を行う。
actionはstart,restart,stop,enable,disable。
パラメータはパッケージ名のnameのみ。

```
service "nginx" do 
  action :restart   
  name "nginx" # 任意指定。ここに記載するとブロック引数より優先される。
end
```


#### template
erbファイルからファイルを作成する。fileの拡張。
パラメータはテンプレート元erbファイルのsource、変数を格納するハッシュのvariables。後はfileにある作成するファイルパスのpath、アクセス権限のmode、所有者のowner、所有グループのgroup。（path以外未確認)


```
template "コピー先のパス＋ファイル名" do 
 path "/path/to/file" # 任意指定。ここに記載するとブロック引数より優先される。
 source "test.erb" #　必須指定。
 variables({"param1" => "value1"}) # 任意指定。
end
```

```test.erb
<%= @param1 %>
```




####  user
ユーザを作成する。
パラメータはユーザ名のusername、グループIDのgid、ホームディレクトリのhome、パスワードのpassword、システムユーザか否かのsystem_user、ユーザidのuid

```
user "rasenn" do
  action :create
  username "rasenn" # 任意指定。ここに記載するとブロック引数より優先される。
  gid "rasenn" # 任意指定
  home "/home/rasenn" # 任意指定。ホームが作成されるわけではない。
  password "password".crypt # 任意指定。
  system_user false # [TrueClass,FalseClass]任意指定
  uid 123798 # 任意指定
end
```


#### base
すべてのリソースの親クラス。下記ののパラメータがすべてのリソースで利用可能。
パラメータはリソースが更新された場合に実行するnotify、
他のリソースが更新された際に実行するsubscribes、
コマンドが成功した時だけ実行するonly_if条件、コマンドが失敗した時だけ実行するnot_if条件、実行ユーザのuser。

```例１
file "only if" do
  path "create/file/path"
  only_if "test -e /tmp/test.txt" # コマンドの実行結果が成功(0以外)の時
end
```

```例2
file "not if" do
  not_if "test -e /tmp/test2.txt" # コマンドの実行結果が失敗(0)の時
end
```


```例3
service "nginx"

template "/etc/nginx/conf.d/site" do 
  source "nginx/site.erb"
  notifies :reload, "service[nginx]"
end
```


```例4
service "nginx" do 
  subscribes :reload, "template[/etc/nginx/conf.d/site]"
end

template "/etc/nginx/conf.d/site" do
  source "nginx/site.erb"
end
```


### 別レシピを呼び出す。
複数のレシピファイルを組み合わせて１つのレシピにする方法。例えば、下記の３ファイルを作成しweb_server_recipe.rbをレシピにすれば、nginxとslがインストールされる。
chefのようにロールはないが、下記のように似たようなものが実現できる。

```nginx_recipe.rb
package "nginx"
```

```sl_recipe.rb
package "sl"
```



```web_server_recipe.rb
include_recipe "nginx_recipe.rb"
include_recipe "sl_recipe.rb"
```


### 備考
書きかけでは大分間違っていた。remote_directoryとか全然違うじゃん。。。

## 参考
https://speakerdeck.com/ryotarai/itamae-infra-as-code-xian-zhuang-que-ren-hui

https://github.com/itamae-kitchen/itamae

http://qiita.com/tbpgr/items/9a796c9ee92037d332ca