LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

配列のなかに入れ子な複数のハッシュのdata_bagsのjsonをchefで扱うレシピ

Last updated at Posted at 2015-10-06

なんか上手くいったので忘れないように自分のための備忘録を。

fluentのsecure_forwardの設定をchefでばらまく時のはなし。
前提環境としてはAWSの複数アカウント間転送でVPCpeeringしてないのでsslで送りたいからSecure_forwardプラグインつかうがELB介すのはセッションぶちぶち切れて無理そげなのでEIPで制限して直に送ることにしてみてなんとかできそう。あとはそれをレシピにしようとしてました。

サーバ側(受け取る側)とクライアント側(送る側)で共通な設定が多い割に、
送る側ではユーザのデータは一人分しか要らないけどどうやってとりだしたらええねんとなって初心者なりに試行錯誤しました。

こんなかんじのjson。このユーザのデータを受け取る側では全て設定していなければならないが送る側は一人分で良い。

$ knife solo data bag create fluentd secure_forward
{
  "id": "secure_forward",
  "fluentusers": [
    {
      "username": "hoge",
      "password": "hoge********"
    },
    {
      "username": "fuga",
      "password": "fuga********"
    }
  ],
  "shared_key": "piyopiyo",
  "servers": [
    {
      "server": "log-ext1.mng.piyo.net"
    },
    {
      "server": "log-ext2.mng.piyo.net"
    }
  ]
}

ググりまくったりrubyのhash関連のマニュアルをガン見してトライアンドエラーした結果、以下のようなレシピに。

#~略~本体インストールとかアカウント判別データのロード

# load secure_forward data
ssl_data = Chef::EncryptedDataBagItem.load("fluentd", "secure_forward")
fluentusers = ssl_data['fluentusers']
servers = ssl_data['servers']
shared_key = ssl_data['shared_key']
ssl_conf = node['fluentd']['server_ssl_conf']

#~略~(このへんで証明書関連のデータをロード

## piyo のみ elasticsearchに送る、secure_forwardの受け取り側.
if "#{account}" == 'piyo'
  ## set cert files.
  file "#{sslkeydir}/#{sslkeyfile}" do
    notifies :restart, 'service[td-agent]'
    content sslkeydata
  end
  file "#{sslkeydir}/#{sslcrtfile}" do
    notifies :restart, 'service[td-agent]'
    content sslcrtdata 
  end
  file "#{sslkeydir}/#{sslcacrtfile}" do
    notifies :restart, 'service[td-agent]'
    content sslcacrtdata
  end
  ## set elasticsearch configs.
  template "/etc/td-agent/extra/td-agent-el-tag4" do
    action :create
    source "td-agent.conf.server-el-tag4.erb"
    notifies :restart, 'service[td-agent]'
    variables ({
        :elasticsearch => elasticsearch
    })
  end
  template "/etc/td-agent/extra/td-agent-el-tag3" do
    action :create
    source "td-agent.conf.server-el-tag3.erb"
    notifies :restart, 'service[td-agent]'
    variables ({
        :elasticsearch => elasticsearch
    })
  end
  include_el_tag4 = '@include /etc/td-agent/extra/td-agent-el-tag4'
  include_el_tag3 = '@include /etc/td-agent/extra/td-agent-el-tag3'

  ## set server template for secure_forward.
  template "/etc/td-agent/extra/td-agent-#{ssl_conf}.conf" do
    action :create
    source "td-agent.conf.server-#{ssl_conf}.erb"
    notifies :restart, 'service[td-agent]'
    variables ({
        :shared_key => shared_key,
        :sslcacrt => sslcacrtfile,
        :sslcrt => sslcrtfile,
        :sslkey => sslkeyfile,
        :fluentusers => fluentusers
    })
  end
  ## set variables for include confs(switch distination).
  variables = {}
  variables.merge!({
    :include_el_tag4 => include_el_tag4,
    :include_el_tag3 => include_el_tag3,
  })

## piyo(アカウント名)以外の場合、elasticsearchには送付しない、secure_forward送信側.
else
  ## set cacert file.
  file "#{sslkeydir}/#{sslcacrtfile}" do
    notifies :restart, 'service[td-agent]'
    content sslcacrtdata
  end
  ## set client variables for secure_forward.
  sfvariables = {}
  fluentusers.each do |fluentuser|
    if fluentuser.has_value?("#{account}")
      fluentuser.values_at(:username, :password)
      sfvariables = fluentuser
    end
  end
  sfvariables.merge! ({
        :shared_key => shared_key,
        :sslcacrt => sslcacrtfile,
        :servers => servers,
  })
  ## set client template for secure_forward.
  template "/etc/td-agent/extra/td-agent-#{ssl_conf}" do
    action :create
    source "td-agent.conf.server-#{ssl_conf}.erb"
    notifies :restart, 'service[td-agent]'
    variables sfvariables
  end
  include_sslsend = '@include /etc/td-agent/extra/td-agent-ssl-send'
#ここにelに送らずpiyoにsecure_worwardで送るのをincludeさせるための変数をset.
  ## set variables for include confs(switch distination).
  variables = {}
  variables.merge!({ 
    :include_sslsend => include_sslsend,
  })
end

#~略~(他に必要なtemplateの配置など)

やりたかったのはここいらへんで使ってるeachとhas_value?とvalus_atとmerge!とかでなんとかなりました。

  ## set client variables for secure_forward.
  sfvariables = {}
  fluentusers.each do |fluentuser|
    if fluentuser.has_value?("#{account}")
      fluentuser.values_at(:username, :password)
      sfvariables = fluentuser
    end
  end
  sfvariables.merge! ({
        :shared_key => shared_key,
        :sslcacrt => sslcacrtfile,
        :servers => servers,
  })

eachで配列の中身をループで処理、has_value?でアカウント名の文字列が含まれる配列だけピックアップして、
values_atでkey名に含まれるやつをピックアップして(これ要らなかったかも?)別名でhashを保存して、
merge!でほかに必要なhashと結合、という具合でございますです。

template側で送るとこ切り替えるのはtype copy<store>~</store>を分離したやつをincludeさせて切り替えました。

~略~
</store>
<% if @include_el_tag4 %>
<%= @include_el_tag4 %>
<% elsif @include_sslsend %>
<%= @include_sslsend %>
<% end %>
<store>
~略~

あと、ひとつのアカウントだけelasticsearchに送るけど他のアカウントはその一つのアカウントに送るみたいなことになってて
そのtemplateでの送る先の切替を読み込むincludeの文字列をifで切替えするみたいなこともやってみたりなど。

secure_forward的には送る側のtemplateがこんな↓かんじ。

  <store>
  type secure_forward
  self_hostname <%= node['hostname'] %>
  shared_key    <%= @shared_key %>
  secure yes
  ca_cert_path /etc/td-agent/<%= @sslcacrt %>
#  enable_strict_verification yes
<% for server in @servers %>
  <server>
    host <%= server["server"] %>  # or IP
#    port 24284
    username <%= @username %>
    password <%= @password %>
  </server>
<% end %>
  </store>

secure_forward的な受け取る側のtemplateはこんな↓かんじです。

<source>
  type secure_forward
  shared_key <%= @shared_key %>
  self_hostname <%= node['hostname'] %>
#  cert_auto_generate yes
  secure yes
  ca_cert_path        /etc/td-agent/<%= @sslcacrt %>
  cert_path        /etc/td-agent/<%= @sslcrt %>
  private_key_path /etc/td-agent/<%= @sslkey %>
  private_key_passphrase 
  authentication     yes # Deny clients without valid username/password
<% for fluentuser in @fluentusers %>
  <user>  
    username <%= fluentuser["username"] %> 
    password <%= fluentuser["password"] %>
  </user> 
<% end %>
</source>

某アニキによると、private_key_passphraseは空でもかかないとだめっぽかったとのことでした。
で、実際適用されたあとの設定ファイルが、、
受け取る側はこんなかんじで、

<source>
  type secure_forward
  shared_key piyopiyo
  self_hostname log2-mng****
#  cert_auto_generate yes
  secure yes
  ca_cert_path        /etc/td-agent/exsample.cacrt
  cert_path        /etc/td-agent/exsample.crt
  private_key_path /etc/td-agent/exsample.key
  private_key_passphrase 
  authentication     yes # Deny clients without valid username/password
  <user>  
    username hoge 
    password hoge********
  </user> 
  <user>  
    username fuga 
    password fuga********
  </user> 
</source>

送る側はこんなかんじに。

  <store>
  type secure_forward
  self_hostname log-fuga-mng-****
  shared_key    piyopiyo
  secure yes
  ca_cert_path /etc/td-agent/exsample.cacrt
#  enable_strict_verification yes
  <server>
    host log-ext1.mng.piyo.net  # or IP
#    port 24284
    username fuga
    password fuga********
  </server>
  <server>
    host log-ext2.mng.piyo.net  # or IP
#    port 24284
    username fuga
    password fuga********
  </server>
  </store>

参考:
・キレ者の人が書いたと思われるレシピとtemplate、
・rubyのhash関連のマニュアル
http://ref.xaio.jp/ruby/classes/hash
・data_bagsに関して試してる記事など
http://inokara.hateblo.jp/entry/2013/05/05/084251
・chefのtemplateのマニュアル
https://docs.chef.io/resource_template.html
「Chef活用ガイド」P595~のtemplateのマニュアル

感想:
いつもあんまり使ってない脳みそを結構使った感じでちょっと楽しかったです。
(うまくいかないとつらいですけれども)
初心者なのでまず取り出したいデータが配列の中の複数hashっぽいのを理解するまでがアレでした。
そこからはhashのマニュアルみて悩みつつ目的に合いそうなメソッドを単体テストしまくりました。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up