Как правильно проверить наличие вложенного атрибута в Chef?

Существует несколько способов проверить наличие вложенного атрибута в шеф-поваре, и я не уверен, какой из них правильный/лучший, и если какой-либо из них приведет к хранению пустых атрибутов на узле:

node[:parent] and node[:parent][:child]

node.attribute?(:parent) and node[:parent].attribute?(:child))

node[:parent].nil? and node[:parent][:child].nil?

Было бы гораздо предпочтительнее иметь возможность одновременно проверять родительский и дочерний элементы, но я не знаю, возможно ли это. Я использую Chef 10, а не Chef 11, хотя ответы с пояснениями приветствуются.


person borntyping    schedule 24.09.2013    source источник


Ответы (5)


Правильный современный способ сделать это — использовать помощник exist?():

if node.exist?('foo', 'bar', 'baz')
  # do stuff with node['foo']['bar']['baz']
end

Это заменяет старый механизм шеф-сахара deep_fetch и уже очень давно встроено в шеф-клиент.

Существует также помощник read() для получения значения, который вернет nil, если какой-либо промежуточный ключ не существует:

fizz = node.read('foo', 'bar', 'baz')

Он идентичен методу Hash#dig, который позже был добавлен в ruby, который также поддерживается как псевдоним:

fizz = node.dig('foo', 'bar', 'baz')
person lamont    schedule 21.08.2020

Объект атрибута узла — HashMap. Вы можете использовать нативный API ruby ​​для поиска вложенных атрибутов.

Chef Node Object предоставляет ряд вспомогательных методов, таких как:

node.attribute?()
node[:foo].attribute?(:bar)
node[:foo].member?(:bar)

Кроме того, в Chef 11 есть новый метод node.debug_value(), помогающий отлаживать атрибуты узлов, что тоже полезно:

node.debug_value(:foo, :bar)

Подробности можно найти в статье Chef 11 In-Depth: Изменения атрибутов

person shawnzhu    schedule 25.09.2013

Способ, которым я решил это совсем недавно, заключался в том, чтобы всегда устанавливать значения по умолчанию для атрибутов, используемых в поваренной книге, где это возможно.

Например, cookbook/attributes/default.rb будет содержать:

default[:parent][:child] = nil

А в рецепте любую проверку значения атрибутов можно свести к:

node[:parent][:child].nil?

Конечно, обычно гораздо полезнее иметь пригодное для использования значение по умолчанию и вообще не проверять его.

person borntyping    schedule 09.07.2014

Ознакомьтесь с расширением deep_fetch шеф-сахара, которое позволяет безопасно ссылаться на глубокие атрибуты.

person Jason Martin    schedule 08.07.2014

Я нашел действительно элегантное решение здесь который использует rescue NoMethodError в конце условного предложения if.

if node['foo']['bar']['baz']
   do the stuff I want
end rescue NoMethodError
person Cory Ringdahl    schedule 02.07.2020
comment
Это также избавит от любого NoMethodError, вызванного любым другим предложением, добавленным к условному (поэтому при расширении до if node['foo']['bar']['baz'] && shoulddoit? будут поглощаться любые программные ошибки в def shoulddoit?, которые вызывают NoMethodError). И это также спасет любой NoMethodError, вызванный блоком do the stuff I Want. Для абсолютно тривиального случая это работает, но как только тривиальный случай усложняется, это сильно затрудняет отладку чего-либо. Этот раствор не следует использовать. - person lamont; 27.03.2021
comment
На этой связанной веб-странице, если автор сделал опечатку include_recipie "ganglia::default" (дополнительный i в рецепте, что является достаточно распространенной опечаткой), то спасательная служба проглатывает ошибку об опечатке. - person lamont; 27.03.2021