Настраиваемые ресурсы
Настраиваемый ресурс:
- Является простым расширением Chef Infra Client, которое добавляет собственные ресурсы
- Реализуется и поставляется как часть кулинарной книги
- Следует простым, повторяющимся синтаксическим шаблонам
- Эффективно использует ресурсы, встроенные в Chef Infra Client, и/или пользовательский код Ruby
- Используется повторно аналогично ресурсам, встроенным в Chef Infra Client
Например, Chef Infra Client включает встроенные ресурсы для управления файлами, пакетами, шаблонами и службами, но не включает ресурс для управления веб-сайтами.
Синтаксис
Настраиваемый ресурс определяется как файл Ruby и размещается в каталоге /resources кулинарной книги. Этот файл:
- Определяет свойства настраиваемого ресурса
- Загружает текущее состояние свойств, если ресурс уже существует
- Определяет каждый возможный action настраиваемого ресурса
Синтаксис настраиваемого ресурса. Например:
property :property_name, RubyType, default: 'value'
action :action_name do
# a mix of built-in Chef resources and Ruby
end
action :another_action_name do
# a mix of built-in Chef resources and Ruby
end
где первый action — это action по умолчанию.
Предупреждение
property :property_name в следующем недопустимом синтаксисе: property :name, String, default: 'thename'.Пример
Этот пример site использует встроенные ресурсы Chef file, service и package, и включает actions :create и :delete. Поскольку он использует встроенные ресурсы Chef Infra Client, помимо определения свойств и actions, код очень похож на код рецепта.
property :homepage, String, default: '<h1>Hello world!</h1>'
action :create do
package 'httpd'
service 'httpd' do
action [:enable, :start]
end
file '/var/www/html/index.html' do
content new_resource.homepage
end
end
action :delete do
package 'httpd' do
action :remove
end
end
где
-
homepage— это свойство, которое задает HTML по умолчанию для файлаindex.htmlсо значением по умолчанию'<h1>Hello world!</h1>' - блок
actionиспользует встроенный набор ресурсов, чтобы сообщить Chef Infra Client, как установить Apache, запустить службу, а затем создать содержимое файла по адресу/var/www/html/index.html -
action :create— это action по умолчанию, потому что он указан первым;action :deleteдолжен быть вызван явно (поскольку это не action по умолчанию)
После написания настраиваемый ресурс можно использовать в рецепте так же, как и любой из ресурсов, встроенных в Chef Infra Client. Название ресурса определяется именем кулинарной книги и именем файла в каталоге /resources, с разделителем подчёркиванием (_) между ними. Например, кулинарная книга с именем exampleco с настраиваемым ресурсом site.rb используется в рецепте следующим образом:
exampleco_site 'httpd' do
homepage '<h1>Welcome to the Example Co. website!</h1>'
end
а чтобы удалить веб-сайт exampleco, выполните следующее:
exampleco_site 'httpd' do
action :delete
end
Сценарий: ресурс веб-сайта
Создайте ресурс, который настраивает Apache httpd для Red Hat Enterprise Linux 7 и CentOS 7.
Этот сценарий охватывает следующее:
- Определение кулинарной книги с именем
website - Определение двух свойств
- Определение действия
- Для действия определение шагов настройки системы с использованием ресурсов, встроенных в Chef Infra
- Создание двух шаблонов, поддерживающих настраиваемый ресурс
- Добавление ресурса в рецепт
Создание кулинарной книги
В этом руководстве предполагается, что каталог кулинарной книги с именем website существует в chef-repo с (по крайней мере) следующими каталогами:
/website
/recipes
/resources
/templates
Вы можете использовать существующую кулинарную книгу или создать новую.
См. /ctl_chef.html для получения дополнительной информации о том, как использовать инструмент командной строки chef, который поставляется с Chef Workstation для построения chef-repo, а также связанных подкаталогов кулинарной книги.
Цели
Определите настраиваемый ресурс!
Настраиваемый ресурс обычно содержит:
- Список определённых пользовательских свойств (значения свойств указываются в рецептах)
- По крайней мере одно действие (действия сообщают Chef Infra Client, что делать)
- Для каждого действия используйте набор ресурсов, встроенных в Chef Infra Client, для определения шагов, необходимых для выполнения действия
Что нужно?
Этот настраиваемый ресурс требует:
- Два файла шаблона
- Два свойства
- Действие, которое определяет все шаги, необходимые для создания веб-сайта
Определение свойств
Пользовательские свойства определяются в ресурсе. Этот настраиваемый ресурс требует двух:
instance_nameport
Эти свойства определяются как переменные в файле httpd.conf.erb. Блок шаблона в рецептах сообщит Chef Infra Client, как применить эти переменные.
В настраиваемый ресурс добавьте следующие пользовательские свойства:
property :instance_name, String, name_property: true
property :port, Integer, required: true
где
-
StringиInteger— типы Ruby (все пользовательские свойства должны иметь назначенный тип Ruby) -
name_property: trueпозволяет значению этого свойства быть равным значению'name'блока ресурса
Свойство instance_name затем используется в настраиваемом ресурсе во многих местах, включая определение путей к конфигурационным файлам, службам и виртуальным хостам.
Определение действий
Каждый настраиваемый ресурс должен иметь по крайней мере одно действие, которое определено в блоке action:
action :create do
# the steps that define the action
end
где :create — значение, которое может быть присвоено свойству action при использовании этого ресурса в рецепте.
Например, action появляется как свойство при использовании этого настраиваемого ресурса в рецепте:
custom_resource 'name' do
# some properties
action :create
end
Определение ресурса
Используйте ресурсы package, template (дважды), directory и service для определения ресурса website. Помните: порядок важен!
package
Используйте ресурс package для установки httpd:
package 'httpd' do
action :install
end
template, httpd.service
Используйте ресурс template для создания httpd.service на узле на основе шаблона httpd.service.erb в кулинарной книге:
template "/lib/systemd/system/httpd-#{new_resource.instance_name}.service" do
source 'httpd.service.erb'
variables(
instance_name: new_resource.instance_name
)
action :create
end
где
-
sourceполучает шаблонhttpd.service.erbиз этой кулинарной книги -
variablesприсваивает свойствоinstance_nameпеременной в шаблоне
template, httpd.conf
Используйте ресурс template для настройки httpd на узле на основе шаблона httpd.conf.erb в кулинарной книге:
template "/etc/httpd/conf/httpd-#{new_resource.instance_name}.conf" do
source 'httpd.conf.erb'
variables(
instance_name: new_resource.instance_name,
port: new_resource.port
)
action :create
end
где
-
sourceполучает шаблонhttpd.conf.erbиз этой кулинарной книги -
variablesприсваивает свойстваinstance_nameиportпеременным в шаблоне
Примечание
cookbook 'website'
directory
Используйте ресурс directory для создания каталога /var/www/vhosts на узле:
directory "/var/www/vhosts/#{new_resource.instance_name}" do
recursive true
action :create
end
service
Используйте ресурс service для включения и запуска службы:
service "httpd-#{new_resource.instance_name}" do
action [:enable, :start]
end
Создание шаблонов
Каталог /templates должен содержать два шаблона:
-
httpd.conf.erbдля настройки Apache httpd -
httpd.service.erbдля указания systemd, как запускать и останавливать веб-сайт
httpd.conf.erb
httpd.conf.erb хранит информацию о веб-сайте и обычно находится в каталоге /etc/httpd:
ServerRoot "/etc/httpd"
Listen <%= @port %>
Include conf.modules.d/*.conf
User apache
Group apache
<Directory />
AllowOverride none
Require all denied
</Directory>
DocumentRoot "/var/www/vhosts/<%= @instance_name %>"
<IfModule mime_module>
TypesConfig /etc/mime.types
</IfModule>
Скопируйте его как показано, добавьте его в /templates, а затем назовите файл httpd.conf.erb.
Переменные шаблона
Шаблон httpd.conf.erb имеет две переменные:
<%= @instance_name %><%= @port %>
Они:
- Определяются как свойства настраиваемого ресурса
- Определяются как переменные в блоке ресурса шаблона в настраиваемом ресурсе
- Настраиваемые из рецепта при использовании
portиinstance_nameкак свойств в этом рецепте -
instance_nameпо умолчанию принимает значение'name'настраиваемого ресурса, если не указано как свойство
httpd.service.erb
httpd.service.erb сообщает systemd, как запускать и останавливать веб-сайт:
[Unit]
Description=The Apache HTTP Server - instance <%= @instance_name %>
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=notify
ExecStart=/usr/sbin/httpd -f /etc/httpd/conf/httpd-<%= @instance_name %>.conf -DFOREGROUND
ExecReload=/usr/sbin/httpd -f /etc/httpd/conf/httpd-<%= @instance_name %>.conf -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}
KillSignal=SIGCONT
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Скопируйте его как показано, добавьте его в /templates, а затем назовите его httpd.service.erb.
Окончательный ресурс
property :instance_name, String, name_property: true
property :port, Integer, required: true
action :create do
package 'httpd' do
action :install
end
template "/lib/systemd/system/httpd-#{new_resource.instance_name}.service" do
source 'httpd.service.erb'
variables(
instance_name: new_resource.instance_name
)
action :create
end
template "/etc/httpd/conf/httpd-#{new_resource.instance_name}.conf" do
source 'httpd.conf.erb'
variables(
instance_name: new_resource.instance_name,
port: new_resource.port
)
action :create
end
directory "/var/www/vhosts/#{new_resource.instance_name}" do
recursive true
action :create
end
service "httpd-#{new_resource.instance_name}" do
action [:enable, :start]
end
end
Окончательный каталог кулинарной книги
После добавления шаблонов и создания настраиваемого ресурса структура каталога кулинарной книги должна выглядеть так:
/website
metadata.rb
/recipes
default.rb
README.md
/resources
httpd.rb
/templates
httpd.conf.erb
httpd.service.erb
Рецепт
Имя настраиваемого ресурса выводится из имени кулинарной книги (website), имени файла ресурса (httpd) и разделителя подчёркиванием (_): website_httpd. Настраиваемый ресурс можно использовать в рецепте.
website_httpd 'httpd_site' do
port 81
action :create
end
что делает следующее:
- Устанавливает Apache httpd
- Присваивает имя экземпляра
httpd_site, использующее порт 81 - Настраивает httpd и systemd из шаблона
- Создаёт виртуальный хост для веб-сайта
- Запускает веб-сайт с помощью systemd
DSL настраиваемого ресурса
В следующих разделах описаны дополнительные методы DSL настраиваемого ресурса, которые не использовались в предыдущем сценарии:
action_class
Используйте блок action_class для предоставления методов действиям в пользовательском ресурсе. Модули с вспомогательными методами, созданными как файлы в каталоге библиотеки кулинарной книги, могут быть включены. Новые методы действий также могут быть определены непосредственно в блоке action_class. Код в блоке action_class имеет доступ к свойствам new_resource.
Предположим, что вспомогательный модуль был создан в файле кулинарной книги libraries/helper.rb.
module Sample
module Helper
def helper_method
# code
end
end
end
Методы могут быть доступны действиям пользовательского ресурса, используя блок action_class.
property file, String
action :delete do
helper_method
FileUtils.rm(new_resource.file) if file_exist
end
action_class do
def file_exist
::File.exist?(new_resource.file)
end
require 'fileutils'
include Sample::Helper
end
converge_if_changed
Используйте метод converge_if_changed внутри блока action в пользовательском ресурсе для сравнения желаемых значений свойств с текущими значениями свойств (загруженных методом load_current_value). Используйте метод converge_if_changed для обеспечения того, что обновления происходят только тогда, когда значения свойств в системе не соответствуют желаемым значениям свойств, и для предотвращения слияния ресурса в противном случае.
Чтобы использовать метод converge_if_changed, оберните им часть рецепта или пользовательского ресурса, которая должна быть слита только тогда, когда текущее состояние не соответствует желаемому состоянию:
action :some_action do
converge_if_changed do
# some property
end
end
Например, пользовательский ресурс определяет два свойства (content и path) и одно действие (:create). Используйте метод load_current_value для загрузки значения свойства для сравнения, а затем используйте метод converge_if_changed для указания Chef Infra Client, что делать, если это значение не соответствует желаемому значению:
property :content, String
property :path, String, name_property: true
load_current_value do
if ::File.exist?(path)
content IO.read(path)
end
end
action :create do
converge_if_changed do
IO.write(new_resource.path, new_resource.content)
end
end
Когда файл не существует, выполняется код IO.write(new_resource.path, new_resource.content), и вывод Chef Infra Client будет похожим на:
Recipe: recipe_name::block
* resource_name[blah] action create
- update my_file[blah]
- set content to "hola mundo" (was "hello world")
Несколько свойств
Метод converge_if_changed может использоваться несколько раз. Следующий пример показывает, как использовать метод converge_if_changed для сравнения нескольких желаемых значений свойств с текущими значениями свойств (загруженных методом load_current_value).
property :path, String
property :content, String
property :mode, String
load_current_value do |desired|
if ::File.exist?(desired.path)
content IO.read(desired.path)
mode ::File.stat(desired.path).mode
end
end
action :create do
converge_if_changed :content do
IO.write(new_resource.path, new_resource.content)
end
converge_if_changed :mode do
::File.chmod(new_resource.mode, new_resource.path)
end
end
где
-
load_current_valueзагружает значения свойств дляcontentиmode - Блок
converge_if_changedпроверяет толькоcontent - Блок
converge_if_changedпроверяет толькоmode
Chef Infra Client будет обновлять только значения свойств, которые требуют обновления, и не будет вносить изменений, когда значения свойств уже находятся в желаемом состоянии.
default_action
По умолчанию действие по умолчанию в пользовательском ресурсе — это первое действие в списке пользовательского ресурса. Например, действие aaaaa является ресурсом по умолчанию:
property :property_name, RubyType, default: 'value'
...
action :aaaaa do
# the first action listed in the custom resource
end
action :bbbbb do
# the second action listed in the custom resource
end
Метод default_action также может использоваться для указания действия по умолчанию. Например:
property :property_name, RubyType, default: 'value'
default_action :aaaaa
action :aaaaa do
# the first action listed in the custom resource
end
action :bbbbb do
# the second action listed in the custom resource
end
определяет действие aaaaa как действие по умолчанию. Если указан default_action :bbbbb, то действие bbbbb является действием по умолчанию. Используйте этот метод для ясности в пользовательских ресурсах, если нужно явно указать ресурс по умолчанию, или для указания действия по умолчанию, которое не указано первым в пользовательском ресурсе.
load_current_value
Используйте метод load_current_value для загрузки указанных значений свойств из узла и затем используйте эти значения при слиянии ресурса. Этот метод может принимать аргумент блока.
property :path, String
property :content, String
property :mode, String
load_current_value do |new_resource|
if ::File.exist?(new_resource.path)
content IO.read(new_resource.path)
mode ::File.stat(new_resource.path).mode
end
end
Используйте метод load_current_value для защиты от замены значений свойств. Например:
property :homepage, String
property :page_not_found, String
load_current_value do
if ::File.exist?('/var/www/html/index.html')
homepage IO.read('/var/www/html/index.html')
end
if ::File.exist?('/var/www/html/404.html')
page_not_found IO.read('/var/www/html/404.html')
end
end
Это гарантирует, что значения для homepage и page_not_found не будут изменены на значения по умолчанию при настройке узла Chef Infra Client.
new_resource.property
Пользовательские ресурсы предназначены для использования встроенных в Chef основных ресурсов. В некоторых случаях может потребоваться указать свойство в пользовательском ресурсе, которое совпадает со свойством основного ресурса, для переопределения этого свойства при использовании с пользовательским ресурсом. Например:
property :command, String, name_property: true
property :version, String
# Useful properties from the `execute` resource
property :cwd, String
property :environment, Hash, default: {}
property :user, [String, Integer]
property :sensitive, [true, false], default: false
prefix = '/opt/languages/node'
load_current_value do
current_value_does_not_exist! if node.run_state['nodejs'].nil?
version node.run_state['nodejs'][:version]
end
action :run do
execute 'execute-node' do
cwd cwd
environment environment
user user
sensitive sensitive
# gsub replaces 10+ spaces at the beginning of the line with nothing
command <<-CODE.gsub(/^ {10}/, '')
#{prefix}/#{new_resource.version}/#{command}
CODE
end
end
где property :cwd, property :environment, property :user, и property :sensitive идентичны свойствам ресурса execute, встроенным в действие action :run. Поскольку пользовательские свойства и свойства execute идентичны, это приведет к сообщению об ошибке, подобному:
ArgumentError
-------------
wrong number of arguments (0 for 1)
Чтобы предотвратить это поведение, используйте new_resource., чтобы указать Chef Infra Client обрабатывать свойства из основного ресурса вместо свойств в пользовательском ресурсе. Например:
property :command, String, name_property: true
property :version, String
# Useful properties from the `execute` resource
property :cwd, String
property :environment, Hash, default: {}
property :user, [String, Integer]
property :sensitive, [true, false], default: false
prefix = '/opt/languages/node'
load_current_value do
current_value_does_not_exist! if node.run_state['nodejs'].nil?
version node.run_state['nodejs'][:version]
end
action :run do
execute 'execute-node' do
cwd new_resource.cwd
environment new_resource.environment
user new_resource.user
sensitive new_resource.sensitive
# gsub replaces 10+ spaces at the beginning of the line with nothing
command <<-CODE.gsub(/^ {10}/, '')
#{prefix}/#{new_resource.version}/#{new_resource.command}
CODE
end
end
где cwd new_resource.cwd, environment new_resource.environment, user new_resource.user, и sensitive new_resource.sensitive правильно используют свойства ресурса execute, а не идентичные по имени переопределяющие свойства пользовательского ресурса.
свойство
Используйте метод property для определения свойств пользовательского ресурса. Синтаксис:
property :property_name, ruby_type, default: 'value', parameter: 'value'
где
-
:property_name— имя свойства -
ruby_type— необязательный тип Ruby или массив типов, например,String,Integer,true, илиfalse -
default: 'value'— необязательное значение по умолчанию, загружаемое в ресурс -
parameter: 'value'— необязательные параметры
Например, следующие свойства определяют свойства username и password без указанных значений по умолчанию:
property :username, String
property :password, String
ruby_type
Свойство ruby_type — это позиционный параметр. Используйте его для обеспечения того, что значение свойства является экземпляром определенного класса Ruby, например, true, false, nil, String, Array, Hash, Integer, Symbol Используйте массив классов Ruby, чтобы разрешить значение быть более чем одного типа. Например:
property :aaaa, String
property :bbbb, Integer
property :cccc, Hash
property :dddd, [true, false]
property :eeee, [String, nil]
property :ffff, [Class, String, Symbol]
property :gggg, [Array, Hash]
sensitive
Свойство может быть помечено как конфиденциальное, указав sensitive: true в свойстве. Это предотвращает экспорт содержимого свойства для сбора данных и отправки на сервер Automate.
Примечание: Эта функция была добавлена в Chef Client 12.14.
валидаторы
Параметр валидации используется для добавления нуля или более параметров валидации к свойству.
| Параметр | Описание |
|---|---|
|
Используйте для определения набора уникальных ключей и значений (ruby hash), где ключ — это сообщение об ошибке, а значение — лямбда-функция для валидации параметра. Например: |
|
Используйте для указания значения по умолчанию для свойства. Например: |
|
Используйте для сопоставления значения с |
|
Используйте для сопоставления значения с регулярным выражением. Например: |
|
Указывает, что свойство обязательно. Например: |
|
Используется для проверки наличия у значения заданного метода. Это может быть имя одного метода или массив имен методов. Например: |
Примеры комбинирования параметров валидации:
property :spool_name, String, regex: /$\w+/
property :enabled, equal_to: [true, false, 'true', 'false'], default: true
desired_state
Добавьте desired_state: для установки свойства желаемого состояния для ресурса. Это значение может быть true или false, и все свойства по умолчанию равны true.
- Когда
true, состояние свойства определяется состоянием системы - Когда
false, значение свойства влияет на то, как выполняется ресурс, но оно не определяется состоянием системы.
Например, если вы пишете ресурс для создания томов на поставщике облачных сервисов, вам потребуется определить такие свойства, как volume_name, volume_size, и volume_region. Состояние этих свойств определит, требуется ли вашему ресурсу слияние или нет. Для работы ресурса вам также потребуется определить такие свойства, как cloud_login и cloud_password. Эти свойства необходимы для взаимодействия с поставщиком облачных сервисов, но их состояние не влияет на решение о слиянии ресурса, поэтому вы установите desired_state в false для этих свойств.
property :volume_name, String
property :volume_size, Integer
property :volume_region, String
property :cloud_login, String, desired_state: false
property :cloud_password, String, desired_state: false
identity
Добавьте identity: для установки ресурса в определённый набор свойств. Это значение может быть true или false.
- Когда
true, данные для этого свойства возвращаются как часть набора данных ресурса и могут быть доступны внешним приложениям, например, отчётам - Когда
false, данные для этого свойства не возвращаются.
Если никакие свойства не помечены true, то свойство, которое по умолчанию принимает name ресурса, помечается true.
Например, следующие свойства определяют свойства username и password без указанных значений по умолчанию, но с identity , установленным в true для имени пользователя:
property :username, String, identity: true
property :password, String
Аргументы блока
Любые свойства, помеченные identity: true, desired_state: false, или name_property: true, будут напрямую доступны из load_current_value. Если требуется доступ к другим свойствам ресурса, используйте аргумент блока с load_current_value. Аргумент блока будет содержать значения запрошенного ресурса. Например:
// Property is directly available example
property :action, String, name_property: true
property :content, String
load_current_value do |desired|
puts "The user requested action = #{action} in the resource"
puts "The user typed content = #{desired.content} in the resource"
end
// Block argument example
property :action, String
property :content, String
load_current_value do |desired|
puts "The user requested action = #{desired.action} in the resource"
puts "The user typed content = #{desired.content} in the resource"
end
property_is_set?
Используйте метод property_is_set? для проверки, установлено ли значение для свойства. Синтаксис:
property_is_set?(:property_name)
Метод property_is_set? вернёт true, если свойство установлено.
Например, следующий пользовательский ресурс создаёт и/или обновляет свойства пользователя, но не их пароль. Метод property_is_set? проверяет, указал ли пользователь пароль, а затем сообщает Chef Infra Client, что делать, если пароль не идентичен:
action :create do
converge_if_changed do
shell_out!("rabbitmqctl create_or_update_user #{username} --prop1 #{prop1} ... ")
end
if property_is_set?(:password)
if shell_out("rabbitmqctl authenticate_user #{username}#{password}").error?
converge_by "Updating password for user #{username} ..." do
shell_out!("rabbitmqctl update_user #{username} --password #{password}")
end
end
end
end
provides
Используйте метод provides для ассоциации пользовательского ресурса с Recipe DSL на различных операционных системах. Когда несколько пользовательских ресурсов используют один и тот же DSL, применяются правила специфичности для определения приоритета, от высшего к низшему:
- provides :my_custom_resource, platform_version: ‘0.1.2’
- provides :my_custom_resource, platform: ‘platform_name’
- provides :my_custom_resource, platform_family: ‘platform_family’
- provides :my_custom_resource, os: ‘operating_system’
- provides :my_custom_resource
Например:
provides :my_custom_resource, platform: 'redhat' do |node|
node['platform_version'].to_i >= 7
end
provides :my_custom_resource, platform: 'redhat'
provides :my_custom_resource, platform_family: 'rhel'
provides :my_custom_resource, os: 'linux'
provides :my_custom_resource
Это позволяет использовать несколько файлов пользовательских ресурсов, предоставляющих один и тот же ресурс пользователю, но для разных операционных систем или версий операционных систем. С этим вы можете устранить необходимость в логике платформы или версии платформы в ваших ресурсах.
reset_property
Используйте метод reset_property для сброса значения свойства, как если бы оно никогда не было установлено, а затем используйте значение по умолчанию. Например, для сброса значения свойства с именем password.
reset_property(:password)
coerce
coerce используется для преобразования пользовательского ввода в каноническую форму. Значение передаётся, а преобразованное значение возвращается в качестве результата. Ленивые значения не будут переданы в этот метод до тех пор, пока они не будут оценены.
coerce выполняется в контексте экземпляра, что даёт ему доступ к другим свойствам.
property :mode, coerce: proc { |m| m.is_a?(String) ? m.to_s(8) : m }
© Chef Software, Inc.
Licensed under the Creative Commons Attribution 3.0 Unported License.
The Chef™ Mark and Chef Logo are either registered trademarks/service marks or trademarks/servicemarks of Chef, in the United States and other countries and are used with Chef Inc's permission.
We are not affiliated with, endorsed or sponsored by Chef Inc.
https://docs.chef.io/custom_resources/