Как я могу использовать ресурс Chef в библиотечном модуле? (Или я должен)?

Я пытаюсь лучше организовать некоторые рецепты Chef, собирая общую логику Ruby во вспомогательной библиотеке. Я видел примеры, объявляющие класс в библиотеке (например, класс Chef::Recipe::MyHelper) с несколькими повторно используемыми методами внутри. Я также видел примеры использования модуля аналогичным образом. В моем случае я хотел использовать ресурс внутри нескольких из этих методов.

Например, предположим, что я хочу предоставить вспомогательный метод, который принимает массив имен служб и в цикле останавливает каждое из них, используя ресурс службы. Я хочу максимально очистить файлы рецептов и сохранить часть этой логики, просто вызвав метод «stopServices (serviceList)».

Если я определяю вспомогательную библиотеку, например:

class Chef::Recipe::MyHelper
  def self.stopServices(serviceList)
    serviceList.each do |svc|
      service "#{svc}" do
        action :stop
      end
    end
  end
end

Тогда в моем рецепте я использую:

MyHelper.stopServices(serviceList)

Я получаю сообщение об ошибке: «служба неопределенного метода для Chef::Recipe::MyHelper:Class».

Есть ли простой способ использовать ресурсы в такой библиотеке? (Содержит ли библиотека MyHelper как класс или модуль)? Это просто плохая практика, которую я нарушаю? Я много искал и не могу найти никого, кто спрашивал бы что-то подобное, что заставляет меня поверить, что я, вероятно, делаю что-то, чего не должен, поэтому любые альтернативные предложения также будут высоко оценены.


person user3525074    schedule 11.04.2014    source источник


Ответы (1)


Библиотеки — это способ абстрагировать сложный код Ruby от кулинарной книги.

Чтобы сгруппировать ресурсы (код Chef DSL), вы должны использовать либо

  • Определения (самый простой вариант), которые вы можете использовать как обычный ресурс Chef в своих рецептах; или
  • LWRP, более сложные, но поддерживающие другие действия (подумайте, service ресурсы, которые вы можете :start, :stop , :restart и т. д. или package ресурсов, которые можно :install, :upgrade, :remove и т. д.).

Обновить

Определение, которое решит вашу примерную проблему:

# cookbooks/common/definitions/common_stop_services.rb
define :common_stop_services, :services => [] do
  params[:services].each do |svc|
    service svc do
      action :stop
    end
  end
end

затем используйте его следующим образом:

# my_cookbook/recipes/my_recipe.rb
common_stop_services "my_recipe_services" do
  services [ 'svc1', 'svc2' ]
end

Наблюдения: возможно, стоит спросить себя, действительно ли вы хотите объединить несколько остановок службы в общий метод. Обычно действие службы уведомляется другим ресурсом (классическим примером является изменение файла конфигурации, уведомляющее перенастроенную службу о перезапуске, но применимы и другие шаблоны).

Obs2: CamelCase используется только для Classes и Modules в коде Ruby. Я рекомендую прочитать руководство по стилю.

Obs3: даже если вы будете реализовывать этот код в библиотеке, вы, вероятно, не захотите использовать файл Class. Вы никогда не будете создавать экземпляр MyHelper, поэтому вместо этого вам нужен Module.

person cassianoleal    schedule 12.04.2014
comment
Спасибо за ответ, я думаю, что LWRPs - это путь для меня в долгосрочной перспективе. В краткосрочной перспективе мне все еще интересно, возможно ли то, что я пытаюсь сделать. Чтобы очистить рецепты, я переместил многие из этих методов в файл библиотеки в общей поваренной книге и сделал другие поваренные книги, которые в них нуждались, зависимыми от этой поваренной книги. Я не удосужился обернуть методы в класс или модуль, и он отлично работает, написанный точно так же, как указано выше, только без строки класса (и self.), но по-прежнему вызывает ресурс из метода в библиотеке. - person user3525074; 13.04.2014
comment
Я хотел обернуть его в класс в качестве лучшей практики, чтобы избежать загрязнения пространства имен по умолчанию и сделать более очевидным, откуда берется метод в других рецептах, используя MyHelper.stopServices вместо просто stopServices. Кажется, единственная проблема заключается в том, что когда я оборачиваю его в класс, он предполагает, что сервисный ресурс является частью этого класса. Так что это похоже на простую проблему с пространством имен, но ничто из того, что я пробовал, не исправляет это. Есть ли способ, которым я могу полностью указать имя ресурса или иным образом указать, что это такое, чтобы использовать его таким образом? - person user3525074; 13.04.2014
comment
Опять же, вы подрываете использование библиотек для выполнения вызовов Chef DSL. Вы также не делаете это более ясным, объявляя класс, имя которого не дает вам подсказки о том, откуда он взялся (возможно, Common было бы лучшим именем, поскольку оно соответствовало бы его поваренной книге?). Я отредактировал свой ответ, чтобы продемонстрировать, как вы можете реализовать определение своей проблемы. Я также добавил несколько наблюдений, которые могут помочь вам в долгосрочной перспективе. - person cassianoleal; 13.04.2014
comment
Спасибо, я ценю пример. Очевидно, мне нужно многому научиться, но это определение помогает. Я рассмотрю возможность более эффективного использования LWRP и уведомлю сервисные ресурсы, которые необходимо остановить/запустить. - person user3525074; 13.04.2014