[CentOS6][Chef] ChefでLAMP構成をつくる10 - 任意のユーザでスクリプト実行


Create: 2013/08/13
LastUpdate: 2013/08/13
[メニューに戻る]

ここでは、Chef11を使用して、段階的にLAMP環境を構築していきます。

今回は、前回の「 [CentOS6][Chef] ChefでLAMP構成をつくる9 - OSアカウントの作成」に引き続き、任意のユーザでスクリプトを実行するレシピを追加します。

Chef11のテスト環境の詳細については、「メニュー」を参照してください。

  [テスト環境]
  • 管理サーバ
    192.168.1.67(chetos6g) ・・・ Chefサーバ + ワークステーション
  • 管理対象
    192.168.1.68(centos6h) ・・・ ノード

前回同様、テスト駆動開発のように、まずテストケースを作成してからレシピを作成し、実際にノードで実行する前に Cookbook が期待する動作を行うかテストすることにします。

Chefのレシピの書き方や、Chefspecのテストケースの書き方は、以下を参考にしました。

今回使用する管理対象のノードは、前回までのレシピを実行した状態になっています。
今回作成する新しいレシピでは、app01ユーザで、テスト用のbashスクリプトを実行することにします。

1.Cookbook 作成


以下、管理サーバに chefユーザでログインして、Chefのワークステーションで作業します。

1.1.ひな形の作成


今回、"sandbox" という名称で新しくcookbookを作成するので、ひな形を用意します。
$ cd ~/chef-repo/cookbooks
$ knife cookbook create sandbox
$ knife cookbook create_specs sandbox

1.2.Chefspec のテストケース追加


以下のファイルにChefspecのテストケースを作成します。
  • ~/chef-repo/cookbooks/sandbox/spec/default_spec.rb 
内容は以下のとおり。
require 'chefspec'

describe 'sandbox::default' do
  let (:chef_run) { ChefSpec::ChefRunner.new.converge 'sandbox::default' }

  it 'should create bashrc' do
    expect(chef_run).to create_cookbook_file '/home/app01/.bashrc'
    file = chef_run.cookbook_file('/home/app01/.bashrc')
    expect(file.mode).to eq "0644"
    expect(file).to be_owned_by('app01', 'appgrp')
  end

  it 'should create example.sh' do
    expect(chef_run).to create_cookbook_file '/home/app01/example.sh'
    file = chef_run.cookbook_file('/home/app01/example.sh')
    expect(file.mode).to eq "0744"
    expect(file).to be_owned_by('app01', 'appgrp')
  end

  it 'should exec shell' do
    expect(chef_run).to execute_bash_script 'execute_shell'
  end

end
app01ユーザのホームディレクトリに ".bashrc" と、テスト用スクリプトの "example.sh" を作成し、このテスト用スクリプトを実行しているかチェックします。

1.3.レシピ修正


以下のファイルにレシピを作成します。
  • ~/chef-repo/cookbooks/sandbox/recipes/default.rb
内容は以下のとおり。
"example.sh" は、1回しか実行できないようにするため、ログファイル(example.log)が存在したら実行しないようにします。
#
# Cookbook Name:: sandbox
# Recipe:: default
#
# Copyright 2013, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#

cookbook_file "/home/app01/.bashrc" do
  source  "bashrc"
  owner   "app01"
  group   "appgrp"
  mode    "0644"
end

cookbook_file "/home/app01/example.sh" do
  source  "example.sh"
  owner   "app01"
  group   "appgrp"
  mode    "0744"
end

bash "execute_shell" do
  user "app01"
  code <<-EOH
    /home/app01/example.sh
  EOH
  not_if "test -f /home/app01/example.log"
end
Chefspecのテストケースを実行してレシピをチェックします。
結果が、以下のように "0 failures" であればOKです。
$ cd ~/chef-repo/cookbooks
$ rspec -fd --color sandbox

sandbox::default
  should create bashrc
  should create example.sh
  should exec shell

Finished in 0.28809 seconds
3 examples, 0 failures 

2.4.cookbook_file の作成


以下のCookbook に同梱するファイルを作成します。
  • ~/chef-repo/cookbooks/sandbox/files/default/bashrc
  • ~/chef-repo/cookbooks/sandbox/files/default/example.sh
"bashrc" の内容は、以下の通り。
# .bashrc

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

# User specific aliases and functions
export TEST_WORD="xxxxxxxxxxxxxxxx"
"example.sh" の内容は、以下のとおり。
#!/bin/bash

exec > /home/app01/example.log

echo "***************** START"

echo "----------------- pwd"
pwd

echo "----------------- whoami"
whoami

echo "----------------- id"
id

echo "----------------- env"
env

echo "***************** END"

exit 0

2.5.metadata の変更


以下のファイルを修正して Cookbookの metadata 変更します。
  • ~/chef-repo/cookbooks/users/metadata.rb
赤字部分を修正します。
name             'sandbox'
maintainer       'blue21'
maintainer_email 'canopus@blue21.ddo.jp'
license          'All rights reserved'
description      'Installs/Configures sandbox'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version          '0.1.0'
Foodcritic で Cookbookの全体的なチェック(文法、矛盾など)をします。
以下のように何も表示されなければOKです。
$ cd ~/chef-repo/cookbooks
$ foodcritic ./sandbox
 

2.6.CookbookをChefサーバに登録


作成した Cookbook をChefサーバにアップロードします。
$ cd ~/chef-repo/cookbooks
$ knife cookbook upload sandbox
Uploading sandbox         [0.1.0]
Uploaded 1 cookbook.

3.ノードの Run List にレシピを追加


今回も、WebUIは使わずに、knifeコマンドを使用します。
管理サーバのワークステーションで以下のように実行します。
$ knife node run_list add centos6h 'recipe[sandbox]'
centos6h:
  run_list:
    role[LAMP]
    recipe[mysql::database]
    recipe[users]
    recipe[sandbox]
"centos6h" はノード名、"recipe[sandbox]" はレシピ名です。

4.ノードでレシピの実行


管理対象のノードに、root ユーザでログインして作業します。
以下のようにコマンドを実行して、レシピを実行します。
# /opt/chef/bin/chef-client
Starting Chef Client, version 11.4.4
resolving cookbooks for run list: ["apache", "php", "mysql", "mysql::database", "users", "sandbox"]
Synchronizing Cookbooks:
  - sandbox
  - users
  - mysql
  - apache
  - php
Compiling Cookbooks...
Recipe: mysql::database
  * chef_gem[ruby-mysql] action install (up to date)
Converging 22 resources
Recipe: apache::default
  * package[httpd] action install (up to date)
  * template[/etc/httpd/conf/httpd.conf] action create (up to date)
  * service[httpd] action enable (up to date)
  * service[httpd] action start (up to date)
Recipe: php::default
  * package[php] action install (up to date)
  * package[php-mysql] action install (up to date)
  * package[php-mbstring] action install (up to date)
  * package[php-gd] action install (up to date)
  * template[/etc/php.ini] action create (up to date)
Recipe: mysql::default
  * package[mysql] action install (up to date)
  * package[mysql-server] action install (up to date)
  * template[/etc/my.cnf] action create (up to date)
  * service[mysqld] action enable (up to date)
  * service[mysqld] action start (up to date)
Recipe: mysql::database
  * link[/tmp/mysql.sock] action create (up to date)
  * chef_gem[ruby-mysql] action install (up to date)
  * mysql_database[appdb] action create (up to date)
  * mysql_database_user[app_user] action create (up to date)
  * mysql_database_user[app_user] action grant

Recipe: users::default
  * group[appgrp] action create (up to date)
  * user[app01] action create (up to date)
  * user[app02] action remove (up to date)
Recipe: sandbox::default
  * cookbook_file[/home/app01/.bashrc] action create
    - create a new cookbook_file /home/app01/.bashrc
        --- /home/app01/.bashrc 2013-08-13 14:13:33.328900857 +0900
        +++ /var/chef/cache/cookbooks/sandbox/files/default/bashrc      2013-08-13 14:10:29.829900537 +0900
        @@ -6,3 +6,4 @@
         fi

         # User specific aliases and functions
        +export TEST_WORD="xxxxxxxxxxxxxxxx"

  * cookbook_file[/home/app01/example.sh] action create
    - create a new cookbook_file /home/app01/example.sh
        --- /tmp/chef-tempfile20130813-21151-1ivfnlf    2013-08-13 14:15:54.576900543 +0900
        +++ /var/chef/cache/cookbooks/sandbox/files/default/example.sh  2013-08-13 14:15:54.575900543 +0900
        @@ -0,0 +1,21 @@
        +#!/bin/bash
        +
        +exec > /home/app01/example.log
        +
        +echo "***************** START"
        +
        +echo "----------------- pwd"
        +pwd
        +
        +echo "----------------- whoami"
        +whoami
        +
        +echo "----------------- id"
        +id
        +
        +echo "----------------- env"
        +env
        +
        +echo "***************** END"
        +
        +exit 0

  * bash[execute_shell] action run
    - execute "bash"  "/tmp/chef-script20130813-21151-1lv5qme"

Chef Client finished, 4 resources updated
適用済みのレシピは、何も行われていません。(up to date)
/home/app01に ".bashrc" と "example.sh" が作成され、"example.sh" が実行されたことが確認できます。
"example.sh" の実行結果は、以下のとおり。
# cat /home/app01/example.log
***************** START
----------------- pwd
/
----------------- whoami
app01
----------------- id
uid=10001(app01) gid=0(root) groups=10001(appgrp),0(root)
----------------- env
HOSTNAME=centos6h
SHELL=/bin/bash
TERM=xterm
HISTSIZE=1000
SSH_CLIENT=192.168.1.2 64697 22
SSH_TTY=/dev/pts/0
LC_ALL=C
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/opt/chef/embedded/bin:/opt/chef/embedded/bin
MAIL=/var/spool/mail/root
PWD=/
LANG=ja_JP.UTF-8
HISTCONTROL=ignoredups
HOME=/root
SHLVL=4
LOGNAME=root
SSH_CONNECTION=192.168.1.2 64697 192.168.1.68 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
***************** END
この結果を見ると、実行時の uid は app01ユーザ ですが、環境変数やグループは rootユーザのものです。ディレクトリも、app01 ユーザのホームディレクトリには移動していません。
app01 ユーザでログインして実行しているわけではないようです。(このページ参照
app01 ユーザでログインして実行させるには、rootユーザで "su" コマンドを使用したほうが良さそうです。
レシピのスクリプト実行箇所を以下のように修正して、アップロードします。
bash "execute_shell" do
  code <<-EOH
    su - app01 -c /home/app01/example.sh
  EOH
  not_if "test -f /home/app01/example.log"
end 
"example.log" を削除して、再度、レシピを実行すると以下のとおり。
# rm ./example.log
# /opt/chef/bin/chef-client
Starting Chef Client, version 11.4.4
resolving cookbooks for run list: ["apache", "php", "mysql", "mysql::database", "users", "sandbox"]
Synchronizing Cookbooks:
  - sandbox
  - users
  - mysql
  - apache
  - php
Compiling Cookbooks...
Recipe: mysql::database
  * chef_gem[ruby-mysql] action install (up to date)
Converging 22 resources
Recipe: apache::default
  * package[httpd] action install (up to date)
  * template[/etc/httpd/conf/httpd.conf] action create (up to date)
  * service[httpd] action enable (up to date)
  * service[httpd] action start (up to date)
Recipe: php::default
  * package[php] action install (up to date)
  * package[php-mysql] action install (up to date)
  * package[php-mbstring] action install (up to date)
  * package[php-gd] action install (up to date)
  * template[/etc/php.ini] action create (up to date)
Recipe: mysql::default
  * package[mysql] action install (up to date)
  * package[mysql-server] action install (up to date)
  * template[/etc/my.cnf] action create (up to date)
  * service[mysqld] action enable (up to date)
  * service[mysqld] action start (up to date)
Recipe: mysql::database
  * link[/tmp/mysql.sock] action create (up to date)
  * chef_gem[ruby-mysql] action install (up to date)
  * mysql_database[appdb] action create (up to date)
  * mysql_database_user[app_user] action create (up to date)
  * mysql_database_user[app_user] action grant

Recipe: users::default
  * group[appgrp] action create (up to date)
  * user[app01] action create (up to date)
  * user[app02] action remove (up to date)
Recipe: sandbox::default
  * cookbook_file[/home/app01/.bashrc] action create (up to date)
  * cookbook_file[/home/app01/example.sh] action create (up to date)
  * bash[execute_shell] action run
    - execute "bash"  "/tmp/chef-script20130813-22412-1yke2mf"

Chef Client finished, 2 resources updated
"example.sh" だけ実行されました。
"example.sh" の実行結果は、以下のとおり。 "~/.bashrc" も読み込まれたようです。(赤字部分で確認)
# cat example.log
***************** START
----------------- pwd
/home/app01
----------------- whoami
app01
----------------- id
uid=10001(app01) gid=10001(appgrp) 所属グループ=10001(appgrp)
----------------- env
HOSTNAME=centos6h
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
USER=app01
TEST_WORD=xxxxxxxxxxxxxxxx
PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/app01/bin
MAIL=/var/spool/mail/app01
PWD=/home/app01
LANG=ja_JP.UTF-8
HISTCONTROL=ignoredups
HOME=/home/app01
SHLVL=2
LOGNAME=app01
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
***************** END


■ 補足
以下のようにすると、レシピで環境変数を設定したり、初期ディレクトリを指定することもできます。
bash "execute_shell" do
  user "app01"
  group "appgrp"
  cwd "/home/app01"
  environment 'HOME' => '/home/app01', 'USER' => 'app01'
  code <<-EOH
    . /home/app01/.bashrc
    /home/app01/example.sh
  EOH
  not_if "test -f /home/app01/example.log"
end