LoginSignup
1
0

More than 5 years have passed since last update.

Chefでリソースのactionへの引数を、String(もしくはそのArray)から変換する

Last updated at Posted at 2018-07-05

問題

Chefでリソースのactionに渡す引数は、SymbolもしくはSymbolのArrayである必要がある。

レシピの例:

recipes/default.rb

service 'firewalld' do
  action [:stop, :disable]  # ここがSymbolもしくはSymbolのArray
end

Ruby DSLの場合の例:

その引数をChefのattributeに持たせる場合、Ruby DSLであれば、SymbolもしくはSymbolのArrayで保持できる。

attributes/default.rb
default['foo']['service']['firewalld']['action'] = [:stop, :disable]  # Ruby書式ならそのままSymbolもしくはSymbolのArrayで持てる

JSONの場合の例:

しかし、例えばchef-clientコマンドに-jオプションでJSONで渡す場合などでは、JSONにはSymbolが無い為、String(もしくはそのArray)などで記述する必要が生じる。

{
  "foo": {
    "service": {
      "firewalld": {
        "action": [
          "stop",
          "disable"
        ]
      }
    }
  }
}

:stopや:disableは使えない。

対応0 StringもしくはSymbolなら.to_symにより対応可能

recipes/default.rb

node['foo']['service'].each do |s_name, s_attr|
  service s_name do
    action s_attr['action'].to_sym
  end
end

Stringのto_symメソッドはSymbolに変換
Symbolのto_symメソッドはSymbolのまま何もしない
Arrayにはto_symメソッドは無い
したがって、Array(Chef::Node::ImmutableArray)の場合にはエラーとなる。

       NoMethodError
       -------------
       undefined method `to_sym' for ["stop", "disable"]:Chef::Node::ImmutableArray

対応1 Class別に処理を分ける

Stringであれば.to_symにてSymbol化が可能
Arrayであれば、.map { |e| e.to_sym }にてSymbolのArray化が可能
どちらか判らなければ、class毎に対応を変更する

recipes/default.rb

node['foo']['service'].each do |s_name, s_attr|
  service s_name do
    if s_attr['action'].class == Chef::Node::ImmutableArray
      action s_attr['action'].map { |e| e.to_sym }  # もしくは.map(&:to_sym)
    else
      action s_attr['action'].to_sym
    end
  end
end

もしくは三項演算子
しかし、いずれにせよ長く読みにくい

対応2 Classを拡張する

Array(正確にはChef::Node::ImmutableArray)の場合に個々の要素毎に.to_symをしてくれれば良いので

recipes/default.rb

class Chef::Node::ImmutableArray  # Chef::Node::ImmutableArrayクラスを拡張 (Rubyの柔軟性は凄い)
  def to_sym
    self.map{ |e| e.to_sym }
    # map(&:to_sym)               # cookstyle -a を通すと、上の行はこう変換される。&:については参照3
  end
end

node['foo']['service'].each do |s_name, s_attr|
  service s_name do
    action s_attr['action'].to_sym
  end
end

これで値がStringでもStringのArrayでも大丈夫
単純な関数likeなmethodを書いても良さそう。

参照

1
0
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
1
0