#目的
Push-Jobsを利用すると、ワークステーション環境から、事前定義したコマンドの実行をnodeに指示できます。
Push-Jobsの基本的な説明は以下をご参照ください。
https://docs.chef.io/push_jobs.html
Push-Jobsを利用したところ、個人的に以下2点が課題になりました。
・ジョブの事前定義が必要で、任意のコマンドを実行できない
・nodeでジョブ実行した際の出力を確認できない
("output"オプションで出力を取得できる仕様ですが、現時点ではSJISの2バイト文字が含まれると取得できなかったり、取得できる出力のサイズ上限が固定であったりします。)
そこで、カスタマイズを行い課題を解消します。
#構成
Chef Server 12.17.15
Push Jobs Server 2.2.8
Chef Client 13.4.24
Push Jobs Client 2.5.6
node Platform : AIX7, RHEL7, Windows2016
#手順
1. Chef Server nginxのconfファイルを追加
/var/opt/opscode/nginx/etc/nginx.d/export.conf
server {
listen 60080;
root /tmp/push-jobs;
location = /log {
client_max_body_size 1m;
client_body_buffer_size 1m;
content_by_lua_block {
ngx.req.read_body() -- explicitly read the req body
local data = ngx.req.get_body_data()
if (not data) then
ngx.say("no body in request.")
return
end
local file = string.match(data, 'filename="(.+)"')
if (not file) then
ngx.say("no filename in request body.")
return
end
local logdir = "/tmp/push-jobs/log"
local status, err = pcall(os.execute, "mkdir -p "..logdir)
local filepath = logdir.."/"..file
local f, err = io.open(filepath, "w")
if err then
ngx.say("can not open file on chef server: ", filepath)
return
end
f:write(data)
f:close()
ngx.say("output data to file on chef server: ", filepath)
}
}
}
nginxを再起動
chef-server-ctl restart nginx
2. nodeのwhiteにコマンドを登録
AIX,Linux
"script-exec-simple": "chmod 755 ${CHEF_PUSH_JOB_FILE} && ${CHEF_PUSH_JOB_FILE} ${CHEF_PUSH_JOB_ID} ${CHEF_PUSH_NODE_NAME}",
Windows
"script-exec-simple": "powershell -Command \"mv %CHEF_PUSH_JOB_FILE% %CHEF_PUSH_JOB_FILE%.PS1; %CHEF_PUSH_JOB_FILE%.PS1 %CHEF_PUSH_JOB_ID% %CHEF_PUSH_NODE_NAME% \"",
3. Chefサーバに以下のディレクトリ・ファイルを作成
ディレクトリ作成
/tmp/push-jobs/log/
/tmp/push-jobs/script/
ファイル作成
/tmp/push-jobs/script/tmplate-lin
jobId=$1
nodeName=$2
logfile=/tmp/${jobId}-${nodeName}.log
cd /tmp
curl -O -k http://ChefServer:60080/script/tmpCommand
curl -O -k http://ChefServer:60080/script/http_file_upload.rb
chmod 755 tmpCommand http_file_upload.rb
LANG=C echo "#logfile head" > $logfile
LANG=C /tmp/tmpCommand >> $logfile 2>&1
RC=$?
LANG=C echo '#logfile end' >> $logfile
echo RC=${RC} >> $logfile
ruby /tmp/http_file_upload.rb $logfile
/tmp/push-jobs/script/tmplate-win
Param( $jobId, $nodeName )
$logfile="C:/tmp/${jobId}-${nodeName}.log"
$httpUploadRb="C:/tmp/http_file_upload.rb"
Set-Location "C:/tmp/"
Invoke-WebRequest http://ChefServer:60080/script/tmpCommand -OutFile tmpCommand.ps1
Invoke-WebRequest http://ChefServer:60080/script/http_file_upload.rb -OutFile http_file_upload.rb
echo "#logfile head" | Out-File ${logfile} -Encoding UTF8
.tmpCommand.ps1 2>&1 | Out-File ${logfile} -Encoding UTF8 -Append
${RC}=$LastExitCode
echo '#logfile end' | Out-File ${logfile} -Encoding UTF8 -Append
echo "RC=${RC}" | Out-File ${logfile} -Encoding UTF8 -Append
C:/opscode/chef/embedded/bin/ruby C:/tmp/http_file_upload.rb ${logfile}
/tmp/push-jobs/script/http_file_upload.rb
require 'net/http'
require 'uri'
require 'base64'
uri = URI.parse('http://ChefServer:60080/log')
sendString = Base64.urlsafe_encode64(open(ARGV[0]).read)
sendFileName = File.basename(ARGV[0])
data = [[ "upfile", sendString, { filename: sendFileName, content_type: "application/octet-stream" } ]]
http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Post.new(uri.path)
req.set_form(data, "multipart/form-data")
res = http.request(req)
puts res.code
puts res.msg
puts res.body
/tmp/push-jobs/script/file_decode.rb
require 'base64'
puts Base64.urlsafe_decode64(open(ARGV[0]).read)
以上で準備完了です。
4. 実行してみます。
まず、実行したいコマンドを以下のファイルに記載します。
/tmp/push-jobs/script/tmpCommand
以下のようにジョブを実行します。
knife job start script-exec-simple <node name> --file /tmp/push-jobs/script/tmplate-lin
ジョブ終了後、以下のファイルがChefサーバに作成されているはずです。
/tmp/push-jobs/log/<jobId>-<nodeName>.log
取得したファイルから必要な個所を抜き出し、base64でデコードすれば、出力を確認できます。
grep "I2xvZ2ZpbGUgaGVhZA" /tmp/push-jobs/log/<jobId>-<nodeName>.log | sed -z 's/\r\n//g' > /tmp/push-jobs/log/<jobId>-<nodeName>.log
ruby /tmp/push-jobs/script/file_decode.rb /tmp/push-jobs/log/<jobId>-<nodeName>.log
※I2xvZ2ZpbGUgaGVhZAは"#logfile head"をencodeした文字列です。
#感想
こんなことするなら、シンプルにSSH/winrm 使いますよね。。。