Руководство по Ruby
Ruby — простой язык программирования:
- Chef использует Ruby в качестве языка-справочника для определения шаблонов, встречающихся в ресурсах, рецептах и кулинариях
- Используйте эти шаблоны для настройки, развертывания и управления узлами по всей сети
Ruby также является мощным и полным языком программирования:
- Используйте язык программирования Ruby для принятия решений о том, что должно произойти с определёнными ресурсами и рецептами
- Расширяйте Chef любым способом, который необходим вашей организации
Чтобы узнать больше о Ruby, посетите:
Начиная с Chef Infra Client 15.x, в Chef Infra Client поставляется Ruby 2.6.
Основы Ruby
Этот раздел описывает основы Ruby.
Проверка синтаксиса
Многие люди, которые только начинают изучать Ruby, быстро осваивают основы. Например, полезно знать, как проверить синтаксис файла Ruby, например, содержимое кулинарии с именем my_cookbook.rb.
ruby -c my_cookbook_file.rb
для возврата:
Syntax OK
Комментарии
Используйте комментарий, чтобы объяснить код, который существует в кулинарии или рецепте. Всё после # является комментарием.
# This is a comment.
Локальные переменные
Присвойте локальную переменную:
x = 1
Математика
Выполните некоторые основные арифметические операции:
1 + 2 # => 3
2 * 7 # => 14
5 / 2 # => 2 (because both arguments are whole numbers)
5 / 2.0 # => 2.5 (because one of the numbers had a decimal place)
1 + (2 * 3) # => 7 (you can use parentheses to group expressions)
Строки
Работайте со строками:
'single quoted' # => "single quoted"
"double quoted" # => "double quoted"
'It\'s alive!' # => "It's alive!" (the \ is an escape character)
'1 + 2 = 5' # => "1 + 2 = 5" (numbers surrounded by quotes behave like strings)
Преобразуйте строку в верхний или нижний регистр. Например, имя хоста «Foo»:
node['hostname'].downcase # => "foo"
node['hostname'].upcase # => "FOO"
Ruby в строках
Встраивание Ruby в строку:
x = 'Bob'
"Hi, #{x}" # => "Hi, Bob"
'Hello, #{x}' # => "Hello, \#{x}" Notice that single quotes don't work with #{}
Символ экранирования
Используйте обратную косую черту (\) в качестве символа экранирования, когда кавычки должны появляться внутри строк. Однако, вам не нужно экранировать одинарные кавычки внутри двойных кавычек. Например:
'It\'s alive!' # => "It's alive!"
"Won\'t you read Grant\'s book?" # => "Won't you read Grant's book?"
Интерполяция
Когда в строках есть кавычки внутри кавычек, используйте двойные кавычки (" ") для внешних кавычек, а одинарные кавычки (' ') для внутренних. Например:
Chef::Log.info("Loaded from aws[#{aws['id']}]")
"node['mysql']['secretpath']"
"#{ENV['HOME']}/chef.txt"
antarctica_hint = hint?('antarctica')
if antarctica_hint['snow']
"There are #{antarctica_hint['penguins']} penguins here."
else
'There is no snow here, and penguins like snow.'
end
Истинные значения
Работайте с базовыми истинными значениями:
true # => true
false # => false
nil # => nil
0 # => true ( the only false values in Ruby are false
# and nil; in other words: if it exists in Ruby,
# even if it exists as zero, then it is true.)
1 == 1 # => true ( == tests for equality )
1 == true # => false ( == tests for equality )
Ложные значения
Работайте с базовыми ложными значениями (! означает "не"):
!true # => false
!false # => true
!nil # => true
1 != 2 # => true (1 is not equal to 2)
1 != 1 # => false (1 is not equal to itself)
Преобразование истинных значений
Преобразуйте что-либо в true или false (!! означает "не не"):
!!true # => true
!!false # => false
!!nil # => false (when pressed, nil is false)
!!0 # => true (zero is NOT false).
Массивы
Создавайте списки с помощью массивов:
x = ['a', 'b', 'c'] # => ["a", "b", "c"]
x[0] # => "a" (zero is the first index)
x.first # => "a" (see?)
x.last # => "c"
x + ['d'] # => ["a", "b", "c", "d"]
x # => ["a", "b", "c"] ( x is unchanged)
x = x + ['d'] # => ["a", "b", "c", "d"]
x # => ["a", "b", "c", "d"]
Массивы со пробелами
Синтаксис %w — это сокращение Ruby для создания массива без необходимости кавычек и запятых вокруг элементов.
Например:
if %w(debian ubuntu).include?(node['platform'])
# do debian/ubuntu things with the Ruby array %w() shortcut
end
Когда синтаксис %w использует переменную, такую как |foo|, должны использоваться строки в двойных кавычках.
Верно:
%w(openssl.cnf pkitool vars Rakefile).each do |foo|
template "/etc/openvpn/easy-rsa/#{foo}" do
source "#{foo}.erb"
...
end
end
Неверно:
%w(openssl.cnf pkitool vars Rakefile).each do |foo|
template '/etc/openvpn/easy-rsa/#{foo}' do
source '#{foo}.erb'
...
end
end
Пример
WiX включает несколько инструментов — например, candle (предварительно обрабатывает и компилирует исходные файлы в объектные файлы), light (связывает и связывает объектные файлы с базой данных установщика) и heat (собирает файлы из различных форматов входных данных). Следующий пример использует массив со пробелами и ресурс аудита Chef InSpec file, чтобы проверить, присутствуют ли эти три инструмента:
%w(
candle.exe
heat.exe
light.exe
).each do |utility|
describe file("C:/wix/#{utility}") do
it { should be_file }
end
end
Словари
Словарь — это список с ключами и значениями. Иногда порядок словарей не определён:
h = {
'first_name' => 'Bob',
'last_name' => 'Jones',
}
А иногда он есть. Например, имя, затем фамилия:
h.keys # => ["first_name", "last_name"]
h['first_name'] # => "Bob"
h['last_name'] # => "Jones"
h['age'] = 23
h.keys # => ["first_name", "age", "last_name"]
h.values # => ["Jones", "Bob", 23]
Регулярные выражения
Используйте регулярные выражения в стиле Perl:
'I believe' =~ /I/ # => 0 (matches at the first character)
'I believe' =~ /lie/ # => 4 (matches at the 5th character)
'I am human' =~ /bacon/ # => nil (no match - bacon comes from pigs)
'I am human' !~ /bacon/ # => true (correct, no bacon here)
/give me a ([0-9]+)/ =~ 'give me a 7' # => 0 (matched)
Операторы
Используйте условия! Например, оператор if
if false
# this won't happen
elsif nil
# this won't either
else
# code here will run though
end
или оператор case
x = 'dog'
case x
when 'fish'
# this won't happen
when 'dog', 'cat', 'monkey'
# this will run
else
# the else is an optional catch-all
end
if
Оператор if может использоваться для указания части рецепта, которая будет использоваться, когда будут выполнены определенные условия. Операторы else и elsif могут использоваться для обработки ситуаций, когда начальное условие не выполняется или когда могут быть выполнены другие возможные условия. Поскольку это поведение на 100% Ruby, делайте это в рецепте так же, как и в любом другом месте.
Например, использование оператора if с атрибутом узла platform
if node['platform'] == 'ubuntu'
# do ubuntu things
end
case
Оператор case может использоваться для обработки ситуации, когда есть много условий. Используйте оператор when для каждого условия, сколько требуется.
Например, использование оператора case с атрибутом узла platform
case node['platform']
when 'debian', 'ubuntu'
# do debian/ubuntu things
when 'redhat', 'centos', 'fedora'
# do redhat/centos/fedora things
end
Например, использование оператора case с атрибутом узла platform_family
case node['platform_family']
when 'debian'
# do things on debian-ish platforms (debian, ubuntu, linuxmint)
when 'rhel'
# do things on RHEL platforms (redhat, centos, scientific, etc)
end
Вызов метода
Вызов метода на чём-либо с .method_name()
x = 'My String'
x.split(' ') # => ["My", "String"]
x.split(' ').join(', ') # => "My, String"
Определение метода
Определение метода (или функции, если хотите):
def do_something_useless(first_argument, second_argument)
puts "You gave me #{first_argument} and #{second_argument}"
end
do_something_useless('apple', 'banana')
# => "You gave me apple and banana"
do_something_useless 1, 2
# => "You gave me 1 and 2"
# see how the parentheses are optional if there's no confusion about what to do
Класс Ruby
Используйте класс Ruby File в рецепте. Так как Chef имеет ресурс file, используйте File для использования класса Ruby File. Например:
execute 'apt-get-update' do
command 'apt-get update'
ignore_failure true
not_if { ::File.exist?('/var/lib/apt/periodic/update-success-stamp') }
end
Включение класса
Используйте :include для включения другого класса Ruby. Например:
::Chef::DSL::Recipe.include MyCookbook::Helpers
В не-Chef Ruby синтаксис include (без префикса :), но без префикса : Chef Infra Client попытается найти провайдер под именем include. Использование префикса : указывает Chef Infra Client искать указанный класс, который следует за ним.
Включение параметра
Метод include? может использоваться для обеспечения включения определенного параметра перед выполнением действия. Например, использование метода include? для поиска определенного параметра:
if %w(debian ubuntu).include?(node['platform'])
# do debian/ubuntu things
end
или:
if %w(rhel).include?(node['platform_family'])
# do RHEL things
end
Рекомендации по шаблонам
Этот раздел описывает лучшие практики для создания кулинарий и рецептов.
Этика Git
Хотя это не строго правило стиля Chef, убедитесь, что ваши user.name и user.email правильно настроены в файле .gitconfig.
-
user.nameдолжно быть вашим именем (например, «Иванов Иван») -
user.emailдолжен быть действительным рабочим адресом электронной почты
Это предотвратит записи в журнале коммитов, подобные "guestuser <login@Bobs-Macbook-Pro.local>", которые бесполезны.
Использование тире
Имена кулинарий и пользовательских ресурсов должны содержать только буквенно-цифровые символы. Тире (-) — допустимый символ и может использоваться в именах кулинарий и пользовательских ресурсов, но это не рекомендуется. Chef Infra Client вернет ошибку, если тире не будет преобразовано в подчеркивание (_) при ссылке в рецепте на имя пользовательского ресурса, в котором находится тире.
Именование кулинарий
Используйте короткий организационный префикс для кулинарий приложений, которые являются частью вашей организации. Например, если ваша организация называется SecondMarket, используйте sm в качестве префикса: sm_postgresql или sm_httpd.
Версионирование кулинарий
- Используйте семантическое версионирование при нумерации кулинарий.
- Загружайте только стабильные кулинарии из ветки master.
- Загружайте только нестабильные кулинарии из ветки dev. Объедините с master и увеличьте версию, когда она станет стабильной.
- Всегда обновляйте CHANGELOG.md со всеми изменениями, с билетом JIRA и кратким описанием.
Именование
Называйте вещи единообразно для их системы и компонента. Например:
- атрибуты:
node['foo']['bar'] - рецепт:
foo::bar - роль:
foo-bar - каталоги:
foo/bar(если специфично для компонента),foo(если нет). Например:/var/log/foo/bar.
Называйте атрибуты по имени рецепта, в котором они в основном используются. Например, node['postgresql']['server'].
Порядок параметров
Следуйте этому порядку для информации в каждом объявлении ресурса:
- Источник
- Кулинария
- Владение ресурсом
- Разрешения
- Уведомления
- Действие
Например:
template '/tmp/foobar.txt' do
source 'foobar.txt.erb'
owner 'someuser'
group 'somegroup'
mode '0644'
variables(
foo: 'bar'
)
notifies :reload, 'service[whatever]'
action :create
end
Режимы файлов
Всегда указывайте режим файла с помощью цитируемой строки из 3-5 символов, которая определяет восьмеричный режим:
mode '755'
mode '0755'
Неверно:
mode 755
Указать действие ресурса?
Объявление ресурса не требует указания действия, потому что Chef Infra Client автоматически применяет действие по умолчанию для ресурса, если оно не указано в блоке ресурса. Например:
package 'monit'
установит пакет monit, потому что действие :install является действием по умолчанию для ресурса package.
Однако, если желательна удобочитаемость кода, например, для того, чтобы читатель понимал, какое действие по умолчанию выполняется для пользовательского ресурса, или указывая действие для ресурса, чьё значение по умолчанию может быть не очевидным для читателя, рекомендуется указать действие по умолчанию:
ohai 'apache_modules' do
action :reload
end
Символы или строки?
Предпочитайте строки символам, поскольку они легче читаются, и вам не нужно объяснять не-программистам на Ruby, что такое символ. Пожалуйста, модернизируйте старые кулинарные книги по мере их обнаружения.
Верно:
default['foo']['bar'] = 'baz'
Неверно:
default[:foo][:bar] = 'baz'
Кавычки для строк
Используйте одинарные кавычки во всех ситуациях, где строка не требует интерполяции.
Массивы пробелов
Когда синтаксис %w использует переменную, такую как |foo|, следует использовать строки в двойных кавычках.
Верно:
%w(openssl.cnf pkitool vars Rakefile).each do |foo|
template "/etc/openvpn/easy-rsa/#{foo}" do
source "#{foo}.erb"
...
end
end
Неверно:
%w(openssl.cnf pkitool vars Rakefile).each do |foo|
template '/etc/openvpn/easy-rsa/#{foo}' do
source '#{foo}.erb'
...
end
end
Рецепты
Рецепт должен быть чистым и содержать подробные комментарии. Например:
###########
# variables
###########
connection_info = {
host: '127.0.0.1',
port: '3306',
username: 'root',
password: 'm3y3sqlr00t',
}
#################
# Mysql resources
#################
mysql_service 'default' do
port '3306'
initial_root_password 'm3y3sqlr00t'
action [:create, :start]
end
mysql_database 'wordpress_demo' do
connection connection_info
action :create
end
mysql_database_user 'wordpress_user' do
connection connection_info
database_name 'wordpress_demo'
password 'w0rdpr3ssdem0'
privileges [:create, :delete, :select, :update, :insert]
action :grant
end
##################
# Apache resources
##################
httpd_service 'default' do
listen_ports %w(80)
mpm 'prefork'
action [:create, :start]
end
httpd_module 'php' do
notifies :restart, 'httpd_service[default]'
action :create
end
###############
# Php resources
###############
package 'php-gd' do
action :install
end
package 'php-mysql' do
action :install
end
directory '/etc/php.d' do
action :create
end
template '/etc/php.d/mysql.ini' do
source 'mysql.ini.erb'
action :create
end
httpd_config 'php' do
source 'php.conf.erb'
notifies :restart, 'httpd_service[default]'
action :create
end
#####################
# wordpress resources
#####################
directory '/srv/wordpress_demo' do
user 'apache'
recursive true
action :create
end
tar_extract 'https://wordpress.org/wordpress-4.1.tar.gz' do
target_dir '/srv/wordpress_demo'
tar_flags ['--strip-components 1']
user 'apache'
creates '/srv/wordpress_demo/index.php'
action :extract
end
directory '/srv/wordpress_demo/wp-content' do
user 'apache'
action :create
end
httpd_config 'wordpress' do
source 'wordpress.conf.erb'
variables(
servername: 'wordpress',
server_aliases: %w(computers.biz www.computers.biz),
document_root: '/srv/wordpress_demo'
)
notifies :restart, 'httpd_service[default]'
action :create
end
template '/srv/wordpress_demo/wp-config.php' do
source 'wp-config.php.erb'
owner 'apache'
variables(
db_name: 'wordpress_demo',
db_user: 'wordpress_user',
db_password: 'w0rdpr3ssdem0',
db_host: '127.0.0.1',
db_prefix: 'wp_',
db_charset: 'utf8',
auth_key: 'You should probably use randomly',
secure_auth_key: 'generated strings. These can be hard',
logged_in_key: 'coded, pulled from encrypted databags,',
nonce_key: 'or a ruby function that accessed an',
auth_salt: 'arbitrary data source, such as a password',
secure_auth_salt: 'vault. Node attributes could work',
logged_in_salt: 'as well, but you take special care',
nonce_salt: 'so they are not saved to your chef-server.',
allow_multisite: 'false'
)
action :create
end
Проверка стиля Cookstyle
Chef Workstation включает Cookstyle для проверки стиля Ruby-специфической и Chef-специфической части кода вашего кулинарного руководства. Все кулинарные руководства должны соответствовать правилам Cookstyle перед загрузкой.
cookstyle your-cookbook
должно вернуть no offenses detected
© 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/ruby/