[chef] chefサーバのバックアップ

一通りchefの構築を済ませたので、この辺でchefサーバのバックアップを仕掛けることにしました。
chefも構築を始めるとノウハウの塊になってきて消失するとかなり痛いです。

node,role,data bagのバックアップ

node,role,data bagのバックアップはドキュメントに書いてあるchef_server_backup.rbを使うことにしました。

これを使えば、node,role,data bagは$cwd/.chef/chef_server_backupというディレクトリにそれぞれのオブジェクトがjson形式でバックアップされます。

chef_server_backup.rbの使い方

使い方ってほどでもないのですが、水増しのため解説します。

まずはchef_server_backup.rbを入手します。

cd /path/to/working_dir
curl -O https://raw.github.com/jtimberman/knife-scripts/master/chef_server_backup.rb

そして、knife execchef_server_backup.rbを実行します。
もちろんknifeが正常に動くことが大前提です。

knife exec /path/to/chef_server_backup.rb

以上!

でも、これではせっかく時間をかけて作ったCookbookがバックアップされません。
Cookbookはこれとは別にバックアップを取る必要があります。

Cookbookのバックアップは自作した

いろしろ探したのですが、Cookbookのバックアップツールは見つかりませんでした。
chef_server_backup.rbと同じような感じでできるのが一番かっこいいのですが、残念ながらそれをするためのRuby言語のスキルが僕には圧倒的に不足しています。

ということで、いろいろ悩んだ結果pythonでknifeを使って、cookbookのリストを取得し、それをknifeコマンドでdownloadするベタな方法にしました。
何で悩んだかというとcookbookのバージョンです。
ご存知の通りCookbookは複数のバージョンを保持することができます。それを全てバックアップを取ろうとするとどうやっても僕のスキルではbashで実装できなかったので、pythonで作りました。

恥をしのんでそのスクリプトを晒します。

#!/usr/bin/python
# -*- coding:utf-8 -*-
import subprocess,sys,os,os.path,shutil
import datetime,locale

import smtplib
from email.MIMEText import MIMEText
from email.Utils import formatdate

backup_dir = '/data/chef-repo/.chef/cookbook'
subject = 'Cookbook Backup ERROR'
mail_from = 'from@domain'
mail_to = 'to@domain'

# 現在時刻を取得する関数
def getnow():
  return datetime.datetime.today().strftime("%Y/%m/%d %H:%M:%S")

# メール構築
def create_message(f,to,subject,body):
  message = MIMEText(body)
  message['Subject'] = subject
  message['From'] = f
  message['To'] = to
  message['Date'] = formatdate()
  return message

# メール送信
def sendMail(f, to, message):
  s = smtplib.SMTP()
  s.connect()
  s.sendmail(f, [to], message.as_string())
  s.close()
 
# 処理開始
print '---START {0} ----'.format(getnow())

# 作業用ディレクトリを消す
if os.path.isdir(backup_dir):
  print "Remove {0}".format(backup_dir)
  try:
    shutil.rmtree(backup_dir)
  except OSError:
    error_message = "ERROR: {0} can not delete.".format(backup_dir)
    print error_message
    sendMail(mail_from,mail_to,create_message(mail_from,mail_to,subject,error_message))
    sys.exit(1)

# 作業用ディレクトリの作成
try:
  os.mkdir(backup_dir)
except OSError:
  error_message = "ERROR: {0} can not create.".format(backup_dir)
  print error_message
  sendMail(mail_from,mail_to,create_message(mail_from,mail_to,subject,error_message))
  sys.exit(1)

# cookbookリストを取得する
cmdline = ['/usr/bin/knife', 'cookbook', 'list', '-a']
subproc_args = {
  'stdin':subprocess.PIPE,
  'stdout':subprocess.PIPE,
  'stderr':subprocess.STDOUT,
  'close_fds':True,
}

try:
  p = subprocess.Popen(cmdline, **subproc_args)
except OSError:
  error_message = "Failed to execute command. : {0}".format(cmdline.__str__())
  print error_message
  sendMail(mail_from,mail_to,create_message(mail_from,mail_to,subject,error_message))
  sys.exit(1)

cmd_args = {
  'stdin':subprocess.PIPE,
  'stdout':subprocess.PIPE,
  'stderr':subprocess.STDOUT,
  'close_fds':True,
}

# Cookbookごとにdownload
while True:
  line = p.stdout.readline().split()
  if not line:
    break
  cookbook_name = line.pop(0)
  print cookbook_name
  pp = ""

  # 複数バージョンがある場合はそれらをdownload
  for version in line:
    cmdline = "/usr/bin/knife cookbook download {0} {1} -d {2}".format(cookbook_name, version, backup_dir)
    print "Downloading {0} {1}: ".format(cookbook_name, version),
    try:
      ret = os.system(cmdline)
    except OSError:
      print "ERROR"
      error_message = "Failed to execute command.: {0}".format(cmdline.__str__())
      print error_message
      sendMail(mail_from,mail_to,create_message(mail_from,mail_to,subject,error_message))
      sys.exit(1)

    print "SUCSESS"
    
print '---END {0} ----'.format(getnow())

このスクリプトで/path/to/.chef/cookbookに全てのcookbookをダウンロードして、chef_server_backup.rbで取得したオブジェクトのjsonをまとめてtarで固めてバックアップを取ることにしました。

おしまい。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です