Есть ли способ отложить разрешение атрибута ресурса до этапа "выполнить"?
У меня есть два LWRP. Первый касается создания тома диска, его форматирования и установки на виртуальной машине, мы будем называть этот ресурс cloud_volume
. Второй ресурс (не очень важно, что он делает) нуждается в UUID для вновь отформатированного тома, который является обязательным атрибутом, мы будем называть этот ресурс foobar
.
Ресурсы cloud_volume
и foobar
используются в рецепте примерно следующим образом.
volumes.each do |mount_point, volume|
cloud_volume "#{mount_point}" do
size volume['size']
label volume['label']
action [:create, :initialize]
end
foobar "#{mount_point}" do
disk_uuid node[:volumes][mount_point][:uuid] # This is set by cloud_volume
action [:do_stuff]
end
end
Итак, когда я выполняю работу шеф-повара, я получаю исключение Required argument disk_identifier is missing!
.
После некоторого рытья я обнаружил, что рецепты обрабатываются в две фазы, фазу компиляции и фазу выполнения. Похоже, что проблема во время компиляции, так как это момент времени, когда node[:volumes][mount_point][:uuid]
не установлен.
К сожалению, я не могу использовать трюк, который OpsCode имеет здесь, поскольку уведомления используются в LWRP cloud_volume (чтобы он попадал в анти-шаблон, показанный в документации)
Итак, в конце концов, мой вопрос в том, есть ли способ обойти требование о том, чтобы значение disk_uuid
было известно во время компиляции?
Ответы
Ответ 1
Более чистый способ - использовать Lazy Attribute Evaluation. Это будет оценивать node[:volumes][mount_point][:uuid]
во время выполнения, а не компилировать
foobar "#{mount_point}" do
disk_uuid lazy { node[:volumes][mount_point][:uuid] }
action [:do_stuff]
end
Ответ 2
Отказ от ответственности: это путь со старым шеф-поваром (< 11.6.0), прежде чем добавить ленивую оценку атрибутов.
Оберните свой ресурс foobar в ruby_block и определите foobar динамически. Таким образом, после этапа компиляции у вас будет код ruby в коллекции ресурсов, и он будет оцениваться на этапе выполнения.
ruby_block "mount #{mount_point} using foobar" do
block do
res = Chef::Resource::Foobar.new( mount_point, run_context )
res.disk_uuid node[:volumes][mount_point][:uuid]
res.run_action :do_stuff
end
end
Этот способ node[:volumes][mount_point][:uuid]
не будет известен во время компиляции, но во время компиляции он также не будет доступен. Доступ к нему будет доступен только на стадии запуска, когда он уже должен быть установлен.