Тестируем Chef cookbook. Часть 1

f074a586efd34a008187a0732bd7d2c8.pngПривет! Сегодня мы начинаем серию технических статей о Devops, Chef, infrastructure as code и всем таком. Эта статья — первая из трех о тестировании в Chef. Цикл статей будет полезен тем, кто уже знаком с Chef и хочет научиться тестировать свой код.

Концепция infrastructure as code позволяет нам применять к инфраструктуре решения из мира разработки. Отдельные компоненты инфраструктуры в проектах часто повторяются. При интеграции таких компонентов наиболее удобный вариант — общие кукбуки. Код кукбуков постоянно меняется, фиксятся баги, появляется новый функционал. С помощью тестирования мы отслеживаем регрессии, контролируем обратную совместимость и внедряем новые фичи быстрее.В этой статье мы познакомимся с инструментами для тестирования, напишем простой кукбук и тест к нему.

Что тестируемСначала нам надо определиться с тем, что мы будем тестировать.Ruby Style Guide. В Ruby мире нет style guide от разработчиков языка, но есть style guide от сообщества. Так как код кукбуков пишется на ruby, хорошо следовать практикам, которые уже есть в сообществе; Cookbook linter. За время существования chef накопилось большое количество паттернов и анти-паттернов, их необходимо учитывать при написании кукбука; Интеграционное тестирование. После внесения изменений необходимо проверить работоспособность кукбуков, пограничные условия и интеграцию с другими кукбуками. Ruby Style Guide Для проверки ruby на соответствие style guide используется утилита Rubocop.Утилита ставится командой gem install rubocop, проверить код можно командой 'rubocop .', большинство ошибок можно исправить автоматически, для этого надо воспользоваться опцией -a.Если нужно для некоторых файлов отключить некоторые проверки, то надо создать файл .rubocop.yml и указать в нем исключения.Пример. Для всех поддиректорий в директории test отключаем проверку на длину метода для файла spec_helper.rb:

MethodLength: Exclude:  — 'test/**/spec_helper.rb' Cookbook linter Стиль кукбуков и выявление известных ошибок осуществляется с помощью утилиты Foodcritic. Утилита ставится командой gem install foodcritic, запускается командой foodcritic <путь до кукбука>Пример работы: foodcritic . FC017: LWRP does not notify when updated: ./providers/default.rb:32 В случае, если Foodcritic нашел какие-то проблемы, на сайте проекта http://acrmp.github.io/foodcritic/ есть инструкции по их исправлению.Интеграционное тестирование Для интеграционного тестирования компания Chef выпустила утилиту Test Kitchen, http://kitchen.ci. Эта утилита подготавливает среду для тестирования и запускает ваши тесты. В простом случае Test Kitchen запускает виртуальную машину, в ней запускает chef-client и после прохождения chef-run запускает тесты.Виртуальные машины запускаются через Vagrant. В качестве гипервизора можно использовать всё, что поддерживает Vagrant. Помимо использования виртуальных машин Test Kitchen умеет работать с публичными и приватными облаками.Тесты можно писать с помощью различных фрейморков. Из коробки поддерживаются Bats, shUnit2, RSpec и Serverspec. Язык тестов Bash (Bats, shUnit2) или Ruby (RSpec, Serverspec). Одновременно один и тот же кукбук можно тестировать под разными операционными системами и с разными наборами тестов.Тестирование с помощью Test Kitchen Для того, чтобы писать тесты и вообще работать с chef кукбуками в современном мире используется Chef Development Kit. ChefDK устанавливает собственную инсталляцию языка ruby и всех гемов, которы нужны для работы chef. Таким образом инсталяция chef не будет зависеть от вашего системного руби, это позволит избежать множества проблем с кросс-зависимостями gem-ов и и тд.В поставку ChefDK входит сам chef и большинство нужных гемов. Если какого-то гема не хватает, то его можно установить командой: chef gem install <имя гема>.Скачать ChefDK под вашу платформу можно тут: https://downloads.chef.io/chef-dk/Тестируемый кукбук Для обучения тестированию напишем простой кукбук deploy-user который будет создавать пользователя deployer и домашнюю директорию /home/deployer. В реальной жизни для создания пользователей можно (и нужно) пользоваться уже готовыми кукбукам сообщества.Для генерации скелета кукбука воспользуемся командой: chef generate cookbook deploy-user. На выходе получим директорию deploy-user с кукбуком.чем генерировать скелет? Исторически пустой кукбук можно было создать командой knife cookbook create  — Эта команда создает кукбук в директории, которая прописана в настройках knife, не создает скелет тестов, не создает chefignore файл, не создает git репозиторий, зато создает много лишних директорий под все сущности chef. Хотя, в 2010-ом году и это было очень круто =) berks cookbook  — создает скелет при помощи утилиты berkshelf (это как bundler в ruby мире) chef generate cookbook  — создает скелет при помощи утилиты chef из ChefDK.berks cookbook и chef generate делают примерно одно и тоже. Разница в мелочах, которые мы не будем рассматривать в рамках этой статьи. В любом случае вы всегда можете добавить/удалить что вам нужно.В конечном итоге можно написать несложный Thor/Rack таск, который учтет все ваши пожелания. Создадим директорию attributes и файл default.rb в ней. В файле default.rb определим переменные с именем пользователя и его shell.attributes/default.rb: default['deploy-user']['username'] = 'deployer' default['deploy-user']['shell'] = '/bin/bash' В файле recipes/default.rb вызовем стандартный ресурс user и передадим ему наши параметрыrecipes/default.rb: user node['deploy-user']['username'] do shell node['deploy-user']['shell'] supports manage_home: true end Для нашего примера такого простого кукбука будет вполне достаточно.kitchen.yml Вся конфигурация Test Kitchen описывается одним файлом .kitchen.yml. Этот файл у нас уже есть, он был сгенерирован утилитой chef.Давайте пройдемся по содержимому .kitchen.yml.Конфиг разделен на секции, каждая секция отвечает за разные аспекты процесса тестирования.Дефолтный .kitchen.yml:

--- driver: name: vagrant

provisioner: name: chef_zero

platforms:  — name: ubuntu-12.04  — name: centos-6.5

suites:  — name: default run_list:  — recipe[deploy-user: default] attributes:

В секции driver описываются параметры драйвера работы с виртуальными машинами. В простом случае мы используем Vagrant.В секции provisioner мы указываем кто будет исполнять код тестируемого кукбука. В случае с Chef есть два варианта, chef-solo и chef-zero. В современном мире использовать chef-solo без особой необходимости не требуется. Также можно указать некоторые дополнительные опции, например, какую версию Chef ставить. Если ваш кукбук не работает с Chef 12, то можно явно указать версию require_chef_omnibus: 11.18.6.

Секция platforms описывает на каких ОС будет тестироваться наш кукбук. Например, добавить Ubuntu 14.04 можно так: ' — name: ubuntu-14.04'.

ВАЖНО для каждого драйвера и платформы существуют свои vagrant box-ы по умолчанию. Если вам нужно поменять настройки по умолчанию, то драйверу надо передать соответствующую команду.

Пример: гипервизор Parallels Desktop и custom box.

platforms:  — name: ubuntu-14.04 driver: provider: parallels box: express42/ubuntu-14.04 При такой записи (company/image) образ берется с сервиса https://atlas.hashicorp.com, вы можете указать просто url box-а через опцию box_url.Наконец, секция suites описывает набор рецептов, который необходимо выполнить перед запуском тестов. У нас один suite с именем default. В нем описан run-list с одним рецептом deploy-user: default. Это тот рецепт, в котом мы описывали создание пользователя.

Работа с Test Kitchen Теперь посмотрим, что мы можем сделать с нашей кухней.Посмотреть список машин и их состояние можно командой kitchen list. Заметьте, у нас описан только один suite, поэтому будут созданы только две машины: default-ubuntu-1404 и default-centos-70. Если бы мы описали еще один suite, то количество машин бы удвоилось. Конечное количество машин равно: количество suites умножить на количество platforms

Командой kitchen converge мы запустим создание виртуальных машин и запуск всех suites для всех платформ. Запустить один suite на одной платформе можно так: kitchen converge default-ubuntu-1404. Чтобы удалить все машины и вернуть всё как было существует команда kitchen destroy.

как выключить виртуальную машину Забавный факт, средствами Test Kitchen нельзя выключить машины не удаляя их. На Github об этом есть эпичная сага в нескольких действиях issue https://github.com/test-kitchen/test-kitchen/issues/350 После выполнения kitchen converge мы получим запущенные виртуальные машины с выполненным рецептом default.rb из нашего кукбука deploy-user.Если в коде кукбука есть ошибки, chef-run прервется и будет показано место в коде, которое вызвало ошибку. Считаем, что chef-run прошел успешно =). Далее давайте проверим, действительно-ли suite отработал правильно и сделал, что мы от него ждали. С помощью команды kitchen login default-ubuntu-1404 войдем на одну из машин.

Выполним команду getent passwd deployer:

deployer: x:1001:1001::/home/deployer:/bin/bash И правда, пользователь deployer создан, используется верная home директория и используется нужным нам shell.Теперь проверим, что для пользователя создана home директория и у нее верный владелец, группа и права доступа: ls -lah /home/deployer/.

drwxr-xr-x 2 deployer deployer 4096 Mar 15 23:12 . drwxr-xr-x 4 root root 4096 Mar 15 23:12 … -rw-r--r-- 1 deployer deployer 220 Apr 8 2014 .bash_logout -rw-r--r-- 1 deployer deployer 3637 Apr 8 2014 .bashrc -rw-r--r-- 1 deployer deployer 675 Apr 8 2014 .profile Действительно, домашняя директория существует и имеет верного владельца, группу и права доступа.Ура, теперь вы умеете тестировать кукбуки!

Шутка =)

Тестирование Для запуска тестов есть две команды kitchen verify и kitchen test.kitchen verify ставит фреймворк для тестирования внутрь vm и запускает ваши тесты. Вы можете править ваши тесты и повторно запустить verify.

kitchen test запускает полный цикл тестирования. В первую очередь выполняется kitchen destroy, если до этого машина была создана, затем выполняются suites, прогоняются тесты и в конце иногда выполняется destroy. По умолчанию destroy производится, если тесты прошли успешно. Такое поведение можно переопределить через опции команды kitchen test.

В наши дни кукбуки принято тестировать фреймворком Serverspec, http://serverspec.org. Serverspec это расширение RSpec, которое предоставляет удобные примитивы для тестирования серверов. С выходом serverspec люди перестали писать тесты на чистом RSpec (как и на bash).

Если сейчас запустить kitchen verify, то мы увидим, что за нас написали пустой тест:

deploy-user: default does something (PENDING: Replace this with meaningful tests)

Pending: (Failures listed here are expected and do not affect your suite’s status)

1) deploy-user: default does something # Replace this with meaningful tests # /tmp/busser/suites/serverspec/default_spec.rb:8

Finished in 0.00185 seconds (files took 0.3851 seconds to load) 1 example, 0 failures, 1 pending

Finished verifying (0m36.87s). Откроем файл test/integration/default/serverspec/default_spec.rb и напишем тест на наш кукбук:

require 'spec_helper'

describe 'deploy-user: default' do

describe user ('deployer') do it { should exist } it { should have_home_directory '/home/deployer' } it { should have_login_shell '/bin/bash' } end

describe file ('/home/deployer') do it { should be_directory } it { should be_mode 755 } it { should be_owned_by 'deployer' } it { should be_grouped_into 'deployer' } end

end В коде описаны действия, которые мы делали на машине вручную.Пользователь deployer должен существовать, иметь home директорию /home/deployer, и иметь shell /bin/bash./home/deployer должно быть директорией, иметь права доступа 755, владельца deployer и группу deployer.

В случае если мы нигде не ошиблись, то результат kitchen verify будет таким:

deploy-user: default User «deployer» should exist should have home directory »/home/deployer» should have login shell »/bin/bash» File »/home/deployer» should be directory should be mode 755 should be owned by «deployer» should be grouped into «deployer»

Finished in 0.10972 seconds (files took 0.306 seconds to load) 7 examples, 0 failures

Finished verifying (0m1.92s). Ура, теперь вы умеете тестировать кукбуки!

Бонус. Unit тестирование В мире Сhef также существует unit тестирование. Для него используется инструмент chefspec, http://sethvargo.github.io/chefspec/. Основное отличие от тестирования через Test Kitchen заключается в том, что создания виртуальных машин и запуска chef-run не происходит. Вместо этого проверяется вызов ресурса с нужными параметрами. Это может быть полезно, когда какие-то ресурсы нельзя протестировать обычным способом. Например, если выполнение ресурса зависит от внешней системы или требует специфического оборудования. Ну и такие тесты можно прогонять в любой CI системе. Из минусов стоит отметить, что таким способом сложно тестировать LWRP.Пример такого теста можно посмотреть ниже.

spec/unit/recipes/default_spec.rb

require 'spec_helper'

describe 'deploy-user: default' do

let (: chef_run) do runner = ChefSpec: ServerRunner.new runner.converge (described_recipe) end

it 'converges successfully' do chef_run # This should not raise an error end

it 'creates a user deployer with home »/home/deployer» and shell »/bin/bash»' do expect (chef_run).to create_user ('deployer').with ( home: '/home/deployer', shell: '/bin/bash') end

end Если в файл spec/spec_helper.rb дописать строчку at_exit { ChefSpec: Coverage.report! }, то после окончания тестов будет выводиться процент покрытия.

Запустить эти тесты можно командой chef exec rspec -c

Finished in 0.51553 seconds (files took 3.34 seconds to load) 2 examples, 0 failures

ChefSpec Coverage report generated…

Total Resources: 1 Touched Resources: 1 Touch Coverage: 100.0%

You are awesome and so is your test coverage! Have a fantastic day! Конец Первая часть статьи закончена. Во второй части статьи мы будем выполнять несколько suite, тестировать lwrp и писать сложные тесты.Полезная документация

© Habrahabr.ru