ChefDKに含まれるtest-kitchenによるリモートノードへのChef適用


リモート・ノードにChefレシピを適用するには、Chef Serverを使用する方法や、Knife-Zeroを使う方法などがある。

それらを使用しなくとも、ChefDKに含まれるtest-kitchenを用いる事で、リモート・ノードへのChef適用やInSpecテスト実行が可能である。
必要なものはChefDKに入っているのでとてもお手軽。

#前提
- ローカルマシンにChefDKが導入されている。(検証はMacで実施)
- ローカルマシンからリモートマシンにsshで接続が可能
- リモートマシンがインターネットに接続されていないならば、Chefクライアントが導入されている。


#設定
ほぼ.kitchen.ymlを編集するだけ。

ChefDK導入済みの状態から開始。
まず、クックブックの作成、レシピ、テストの用意、test-kitchenの設定を行う。

```bash:
$ chef generate cookbook manage_existing_servers
...
$ cd manage_existing_servers/
$ vi recipes/default.rb 
...
$ mkdir -p test/integration/default
$ vi test/integration/default/default_test.rb 
...
$ vi .kitchen.yml 
...
```
##Chefレシピ例
```ruby:recipes/default.rb
file '/tmp/test.txt' do
  content "hello world.\n"
end
```
##InSpecテスト例
```ruby:test/integration/default/default_test.rb
describe file('/tmp/test.txt') do
  its(:content) { should match %r(^hello world\.$) }
end
```
##test-kitchen設定例
```yaml:.kitchen.yml
---
provisioner:
  name: chef_zero
  always_update_cookbooks: true
  #require_chef_omnibus: false    # 古い書式
  product_name: chef              # 新しい書式
  install_strategy: skip          # 新しい書式
  sudo: false
  client_rb:                      # AIXの場合の問題対応
    'Chef::Config[:follow_client_key_symlink] =': true

verifier:
  name: inspec
  sudo: false
  inspec_tests:
    - test/integration/default

platforms:
  - name: aix
    run_list:
      - recipe[manage_existing_servers::default]

suites:
<% 
  %w(p8126a p8127a).each do |host| 
%>
  - name: <%= host %>
    driver:
      name: proxy
      host: <%= host %>
      ssh_key: ~/.ssh/id_rsa
      sudo: false
      reset_command: 'exit 0'
<% 
  end
%>
```
- .kitchen.ymlは、最初に、Chefのtemplateリソースでも使用しているERBとして処理されるので、Rubyによる値の設定が可能。ここでは、ループで回して2ノード分の構成としている。
- driver:の設定内容を相手毎に変えたいので、suites:の各要素下に移動。
- vagrantドライバーの代わりに稼働し続けるノード用のproxyドライバーを設定。(参照1,4,6)
- p8126a p8127aは、ssh接続可能なサーバー。この例では、これらのサーバーに対するssh接続情報は、~/.ssh/configにて設定しているので、.kitchen.ymlでは基本的にhost:のみ設定。
- ただし、ssh_key: ~/.ssh/id_rsa は、InSpecの為に必要であったので記載している。
- reset_command: 'exit 0'は、参照4より
- sudo: false は、対象サーバーにsudoが無くrootで接続する為。
- require_chef_omnibus: false は、対象サーバーがインターネット接続されていない為。なお、Chef Clientは事前に導入済み。=> product_name: chef, install_strategy: skip に置き換え。
- client.rbはAIXと特定のchef-clientの組み合わせ時の問題回避 (参照7)






#初期状態
```bash:
$ kitchen list 
Instance    Driver  Provisioner  Verifier  Transport  Last Action    Last Error
p8126a-aix  Proxy   ChefZero     Inspec    Ssh        <Not Created>  <None>
p8127a-aix  Proxy   ChefZero     Inspec    Ssh        <Not Created>  <None>
```

Last Actionの\<Not Created>に注目。
未作成状態。
ただし、実機は構成され稼働している。

#作成(ダミー)
```bash:
$ kitchen create 
-----> Starting Kitchen (v1.17.0)
-----> Creating <p8126a-aix>...
       Resetting instance state with command: exit 0
       Finished creating <p8126a-aix> (0m0.42s).
-----> Creating <p8127a-aix>...
       Resetting instance state with command: exit 0
       Finished creating <p8127a-aix> (0m0.40s).
-----> Kitchen is finished. (0m3.04s)
```

```bash:
$ kitchen list 
Instance    Driver  Provisioner  Verifier  Transport  Last Action  Last Error
p8126a-aix  Proxy   ChefZero     Inspec    Ssh        Created      <None>
p8127a-aix  Proxy   ChefZero     Inspec    Ssh        Created      <None>
```

createを行うと、作成したつもりになるが、実際には予め構成され稼働している。

#リモート・サーバーにChefレシピを反映
```bash:
$ kitchen converge
-----> Starting Kitchen (v1.17.0)
-----> Converging <p8126a-aix>...
$$$$$$ Running legacy converge for 'Proxy' Driver
       Preparing files for transfer
       Preparing dna.json
       Resolving cookbook dependencies with Berkshelf 6.3.1...
       Removing non-cookbook files before transfer
       Preparing validation.pem
       Preparing client.rb
       Transferring files to <p8126a-aix>
       Starting Chef Client, version 12.17.44
       Creating a new client identity for p8126a-aix using the validator key.
       resolving cookbooks for run list: ["manage_existing_servers::default"]
       Synchronizing Cookbooks:
         - manage_existing_servers (0.1.0)
       Installing Cookbook Gems:
       Compiling Cookbooks...
       Converging 1 resources
       Recipe: manage_existing_servers::default
         * file[/tmp/test.txt] action create
           - create new file /tmp/test.txt
           - update content in file /tmp/test.txt from none to d0083d
           --- /tmp/test.txt   2018-06-01 13:48:03.000000000 +0900
           +++ /tmp/.chef-test20180601-22479180-1dschzt.txt    2018-06-01 13:48:03.000000000 +0900
           @@ -1 +1,2 @@
           +hello world.
       
       Running handlers:
       Running handlers complete
       Chef Client finished, 1/1 resources updated in 06 seconds
       Finished converging <p8126a-aix> (0m14.74s).
-----> Converging <p8127a-aix>...
$$$$$$ Running legacy converge for 'Proxy' Driver
       Preparing files for transfer
       Preparing dna.json
       Resolving cookbook dependencies with Berkshelf 6.3.1...
       Removing non-cookbook files before transfer
       Preparing validation.pem
       Preparing client.rb
       Transferring files to <p8127a-aix>
       Starting Chef Client, version 12.17.44
       Creating a new client identity for p8127a-aix using the validator key.
       resolving cookbooks for run list: ["manage_existing_servers::default"]
       Synchronizing Cookbooks:
         - manage_existing_servers (0.1.0)
       Installing Cookbook Gems:
       Compiling Cookbooks...
       Converging 1 resources
       Recipe: manage_existing_servers::default
         * file[/tmp/test.txt] action create
           - create new file /tmp/test.txt
           - update content in file /tmp/test.txt from none to d0083d
           --- /tmp/test.txt   2018-06-01 13:48:17.000000000 +0900
           +++ /tmp/.chef-test20180601-17826238-1b9wet4.txt    2018-06-01 13:48:17.000000000 +0900
           @@ -1 +1,2 @@
           +hello world.
       
       Running handlers:
       Running handlers complete
       Chef Client finished, 1/1 resources updated in 06 seconds
       Finished converging <p8127a-aix> (0m14.20s).
-----> Kitchen is finished. (0m31.16s)
```


```bash:
$ kitchen list 
Instance    Driver  Provisioner  Verifier  Transport  Last Action  Last Error
p8126a-aix  Proxy   ChefZero     Inspec    Ssh        Converged    <None>
p8127a-aix  Proxy   ChefZero     Inspec    Ssh        Converged    <None>
```
リモート・サーバーにChefレシピの内容が反映される。
vagrantドライバーの場合と同様に、cookbookは/tmp/kitchen下に転送され実行される。

#リモート・サーバーにおいてInSpecによるテスト実行
```bash:
$ kitchen verify
-----> Starting Kitchen (v1.17.0)
-----> Setting up <p8126a-aix>...
$$$$$$ Running legacy setup for 'Proxy' Driver
       Finished setting up <p8126a-aix> (0m0.00s).
-----> Verifying <p8126a-aix>...
       Loaded tests from test/integration/default 

Profile: tests from test/integration/default
Version: (not specified)
Target:  ssh://root@p8126a:22


  File /tmp/test.txt
     ✔  content should match /^hello world\.$/

Test Summary: 1 successful, 0 failures, 0 skipped
       Finished verifying <p8126a-aix> (0m0.73s).
-----> Setting up <p8127a-aix>...
$$$$$$ Running legacy setup for 'Proxy' Driver
       Finished setting up <p8127a-aix> (0m0.00s).
-----> Verifying <p8127a-aix>...
       Loaded tests from test/integration/default 

Profile: tests from test/integration/default
Version: (not specified)
Target:  ssh://root@p8127a:22


  File /tmp/test.txt
     ✔  content should match /^hello world\.$/

Test Summary: 1 successful, 0 failures, 0 skipped
       Finished verifying <p8127a-aix> (0m0.52s).
-----> Kitchen is finished. (0m3.43s)
```
```bash:
$ kitchen list 
Instance    Driver  Provisioner  Verifier  Transport  Last Action  Last Error
p8126a-aix  Proxy   ChefZero     Inspec    Ssh        Verified     <None>
p8127a-aix  Proxy   ChefZero     Inspec    Ssh        Verified     <None>
```
リモート・サーバーでInSpecテストが実行された。

#kitchen loginも可能
```bash:
$ kitchen login p8126a
$$$$$$ Running legacy login for 'Proxy' Driver
Last unsuccessful login: Thu Apr 12 18:50:21 JST 2018 on ssh from p8127a
Last login: Fri Jun  1 13:48:41 JST 2018 on ssh from p8104a
*******************************************************************************
*                                                                             *
*                                                                             *
*  Welcome to AIX Version 7.2!                                                *
*                                                                             *
*                                                                             *
*  Please see the README file in /usr/lpp/bos for information pertinent to    *
*  this release of the AIX Operating System.                                  *
*                                                                             *
*                                                                             *
*******************************************************************************
p8126a:[/]# cat /tmp/test.txt       
hello world.
p8126a:[/]# exit
Connection to p8126a closed.
```
vagrantドライバー構成と同様の操作が可能。
なお、実際には稼働していても、未構成と認識されている状態では、kitchen loginはできない。

#削除(ダミー)

```bash:
$ kitchen destroy
-----> Starting Kitchen (v1.17.0)
-----> Destroying <p8126a-aix>...
       Resetting instance state with command: exit 0
       Finished destroying <p8126a-aix> (0m0.41s).
-----> Destroying <p8127a-aix>...
       Resetting instance state with command: exit 0
       Finished destroying <p8127a-aix> (0m0.55s).
-----> Kitchen is finished. (0m3.10s)
```
```bash:
$ kitchen list 
Instance    Driver  Provisioner  Verifier  Transport  Last Action    Last Error
p8126a-aix  Proxy   ChefZero     Inspec    Ssh        <Not Created>  <None>
p8127a-aix  Proxy   ChefZero     Inspec    Ssh        <Not Created>  <None>
```
削除を行っても、実機はそのまま稼働を続ける。

#作成、Chefレシピ反映、InSpecテスト、削除を通して実行

```bash:
$ kitchen test 
-----> Starting Kitchen (v1.17.0)
-----> Cleaning up any prior instances of <p8126a-aix>
-----> Destroying <p8126a-aix>...
       Finished destroying <p8126a-aix> (0m0.00s).
-----> Testing <p8126a-aix>
-----> Creating <p8126a-aix>...
       Resetting instance state with command: exit 0
       Finished creating <p8126a-aix> (0m0.46s).
-----> Converging <p8126a-aix>...
$$$$$$ Running legacy converge for 'Proxy' Driver
       Preparing files for transfer
       Preparing dna.json
       Resolving cookbook dependencies with Berkshelf 6.3.1...
       Removing non-cookbook files before transfer
       Preparing validation.pem
       Preparing client.rb
       Transferring files to <p8126a-aix>
       Starting Chef Client, version 12.17.44
       resolving cookbooks for run list: ["manage_existing_servers::default"]
       Synchronizing Cookbooks:
         - manage_existing_servers (0.1.0)
       Installing Cookbook Gems:
       Compiling Cookbooks...
       Converging 1 resources
       Recipe: manage_existing_servers::default
         * file[/tmp/test.txt] action create (up to date)
       
       Running handlers:
       Running handlers complete
       Chef Client finished, 0/1 resources updated in 06 seconds
       Finished converging <p8126a-aix> (0m15.57s).
-----> Setting up <p8126a-aix>...
$$$$$$ Running legacy setup for 'Proxy' Driver
       Finished setting up <p8126a-aix> (0m0.00s).
-----> Verifying <p8126a-aix>...
       Loaded tests from test/integration/default 

Profile: tests from test/integration/default
Version: (not specified)
Target:  ssh://root@p8126a:22


  File /tmp/test.txt
     ✔  content should match /^hello world\.$/

Test Summary: 1 successful, 0 failures, 0 skipped
       Finished verifying <p8126a-aix> (0m0.58s).
-----> Destroying <p8126a-aix>...
       Resetting instance state with command: exit 0
       Finished destroying <p8126a-aix> (0m0.44s).
       Finished testing <p8126a-aix> (0m17.07s).
-----> Cleaning up any prior instances of <p8127a-aix>
-----> Destroying <p8127a-aix>...
       Finished destroying <p8127a-aix> (0m0.00s).
-----> Testing <p8127a-aix>
-----> Creating <p8127a-aix>...
       Resetting instance state with command: exit 0
       Finished creating <p8127a-aix> (0m0.39s).
-----> Converging <p8127a-aix>...
$$$$$$ Running legacy converge for 'Proxy' Driver
       Preparing files for transfer
       Preparing dna.json
       Resolving cookbook dependencies with Berkshelf 6.3.1...
       Removing non-cookbook files before transfer
       Preparing validation.pem
       Preparing client.rb
       Transferring files to <p8127a-aix>
       Starting Chef Client, version 12.17.44
       resolving cookbooks for run list: ["manage_existing_servers::default"]
       Synchronizing Cookbooks:
         - manage_existing_servers (0.1.0)
       Installing Cookbook Gems:
       Compiling Cookbooks...
       Converging 1 resources
       Recipe: manage_existing_servers::default
         * file[/tmp/test.txt] action create (up to date)
       
       Running handlers:
       Running handlers complete
       Chef Client finished, 0/1 resources updated in 06 seconds
       Finished converging <p8127a-aix> (0m14.88s).
-----> Setting up <p8127a-aix>...
$$$$$$ Running legacy setup for 'Proxy' Driver
       Finished setting up <p8127a-aix> (0m0.00s).
-----> Verifying <p8127a-aix>...
       Loaded tests from test/integration/default 

Profile: tests from test/integration/default
Version: (not specified)
Target:  ssh://root@p8127a:22


  File /tmp/test.txt
     ✔  content should match /^hello world\.$/

Test Summary: 1 successful, 0 failures, 0 skipped
       Finished verifying <p8127a-aix> (0m0.64s).
-----> Destroying <p8127a-aix>...
       Resetting instance state with command: exit 0
       Finished destroying <p8127a-aix> (0m0.48s).
       Finished testing <p8127a-aix> (0m16.40s).
-----> Kitchen is finished. (0m35.81s)
```
```bash:
$ kitchen list 
Instance    Driver  Provisioner  Verifier  Transport  Last Action    Last Error
p8126a-aix  Proxy   ChefZero     Inspec    Ssh        <Not Created>  <None>
p8127a-aix  Proxy   ChefZero     Inspec    Ssh        <Not Created>  <None>
```
先にChefレシピを実行していた為、ファイル作成は * file[/tmp/test.txt] action create (up to date) としてスキップされている。
削除が実際には行われないことから、kitchen test -d neverの方を使うメリットはそれほど多くないと思える。

#参照
1. [Test Kitchenを稼働中のサーバに使う](https://aimless.jp/blog/archives/2017-04-27-use-testkitchen-against-existing-server/)
2.   [Shellで構築、Shellでテストする Test-Kitchen](https://qiita.com/sawanoboly/items/2874018f385dbe8562b1)
3. [Chef-Kitchen Do it simply..](http://blog.opstree.com/2016/04/chef-kitchen-do-it-simply.html)
4. [Using kitchen-ssh driver to run Inspec tests on remote node](https://discourse.chef.io/t/using-kitchen-ssh-driver-to-run-inspec-tests-on-remote-node/9035)
5.  [.kitchen.yml](https://docs.chef.io/config_yml_kitchen.html)
6.  [Class: Kitchen::Driver::Proxy](https://www.rubydoc.info/github/test-kitchen/test-kitchen/windows-guest-support/Kitchen/Driver/Proxy)
7.  [AIX V7 にて chef-client を使用する際の integer 137438954242 too big to convert to `int' エラー](https://qiita.com/hiroyuki_onodera/items/eb86972a72e58a533836)