📜 ⬆️ ⬇️

Test Chef cookbook



The concept of infrastructure as code allows us to apply to the infrastructure solutions from the world of development. Individual infrastructure components in projects are often repeated. When integrating such components, the most convenient option is general kukbuki. Code kukbukov constantly changing, fix bugs, there is a new functionality. With the help of testing, we monitor regressions, control backward compatibility and implement new features faster.
In this article we will get acquainted with the tools for testing, we will write a simple kukbook and a test for it.


')

What we test


First we need to decide on what we will test.

  1. Ruby Style Guide . In the Ruby world, there is no style guide from the language developers, but there is a style guide from the community . Since the code of the cookbooks is written in ruby, it is good to follow the practices that are already in the community;
  2. Cookbook linter. During the existence of the chef, a large number of patterns and anti-patterns have accumulated, they must be considered when writing the book;
  3. Integration testing . After making changes, it is necessary to check the performance of the kukbuk, boundary conditions and integration with other kukbuk.

Ruby Style Guide


To check ruby ​​for compliance with the style guide, use the Rubocop utility.
The utility is installed by the gem install rubocop command , you can check the code with the ' rubocop ' command. ', most errors can be fixed automatically, for this you need to use the -a option.
If you need to disable some checks for some files, you need to create a .rubocop.yml file and specify exceptions in it.

Example. For all subdirectories in the test directory, disable the method length check for the spec_helper.rb file :
MethodLength: Exclude: - 'test/**/spec_helper.rb' 

Cookbook linter


Kukbuk style and identification of known errors is carried out using the utility Foodcritic . The utility is installed by the gem install foodcritic command , run by the foodcritic command <path to the cookbook>
Work example:
 foodcritic . FC017: LWRP does not notify when updated: ./providers/default.rb:32 

In case Foodcritic has found some problems, there are instructions for correcting them on the project site http://acrmp.imtqy.com/foodcritic/ .

Integration testing


For integration testing, Chef has released the Test Kitchen utility, http://kitchen.ci . This utility prepares the test environment and runs your tests. In the simple case, Test Kitchen starts the virtual machine, starts the chef-client in it, and after passing the chef-run runs the tests.
Virtual machines are started via Vagrant. Anything that supports Vagrant can be used as a hypervisor. In addition to using virtual machines, Test Kitchen can work with public and private clouds.
Tests can be written using various frameworks. Out of the box, Bats, shUnit2, RSpec and Serverspec are supported. Test language Bash (Bats, shUnit2) or Ruby (RSpec, Serverspec). At the same time, the same kukbook can be tested under different operating systems and with different sets of tests.

Testing with Test Kitchen


In order to write tests and generally work with chef cookbooks in the modern world, the Chef Development Kit is used . ChefDK installs its own installation of the ruby ​​language and all the gems that are needed to work chef. Thus, the installation of chef will not depend on your system cuts, this will avoid many problems with cross-dependencies of gems and so on.
ChefDK itself includes chef and most of the necessary gems. If there is not enough of a heme, then it can be installed with the command:
chef gem install <heme name> .
Download ChefDK for your platform here: https://downloads.chef.io/chef-dk/

Test Kukbook


To teach testing, we will write a simple deploy-user kukbook that will create a user deployer and a home directory / home / deployer. In real life, to create users, you can (and should) use the already prepared community kukbuks.
To generate the Kukbook skeleton, use the following command: chef generate cookbook deploy-user . At the output we will get the deploy-user directory with a kukbook.
how to generate a skeleton?
Historically, an empty kukbook could be created by a team.
  knife cookbook create <name> 
- This command creates a cookie in the directory that is specified in the settings of the knife, does not create a skeleton of tests, does not create a chefignore file, does not create a git repository, but creates many extra directories for all chef entities. Although, in the 2010th year, and it was very cool =)
  berks cookbook <name> 
- creates a skeleton using the berkshelf utility (this is like a bundler in the ruby ​​world)
  chef generate cookbook <name> 
- creates a skeleton using the chef utility from ChefDK.
berks cookbook and chef generate do about the same thing. The difference in the details that we will not consider in this article. In any case, you can always add / remove what you need.
In the end, you can write a simple Thor / Rack task, which will take into account all your wishes.

Create the attributes directory and the default.rb file in it. In the file default.rb, we define variables with the name of the user and his shell.
attributes / default.rb :
 default['deploy-user']['username'] = 'deployer' default['deploy-user']['shell'] = '/bin/bash' 

In the recipes / default.rb file, let's call the standard user resource and pass it our parameters.
recipes / default.rb :
 user node['deploy-user']['username'] do shell node['deploy-user']['shell'] supports manage_home: true end 

For our example of such a simple kukbuk will be quite enough.

kitchen.yml


The entire configuration of Test Kitchen is described by a single .kitchen.yml file. We already have this file, it was generated by the chef utility.
Let's go over the contents of .kitchen.yml.
The config is divided into sections, each section is responsible for different aspects of the testing process.

Default .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: 

The driver section describes the parameters of the virtual machine driver. In the simple case, we use Vagrant.

In the provisioner section, we specify who will execute the code for the test book. In the case of Chef, there are two options, chef-solo and chef-zero. In the modern world, using chef-solo without much need is not required. You can also specify some additional options, for example, which version of Chef to install. If your Kukbook does not work with Chef 12, then you can explicitly specify the version of require_chef_omnibus: 11.18.6 .

The platforms section describes on which OS our kookbook will be tested. For example, you can add Ubuntu 14.04 as follows: ' - name: ubuntu-14.04 '.

IMPORTANT for each driver and platform, there are different default vagrant boxes. If you need to change the default settings, then the driver must pass the appropriate command.

Example: Parallels Desktop hypervisor and custom box.
 platforms: - name: ubuntu-14.04 driver: provider: parallels box: express42/ubuntu-14.04 

With such a record ( company / image ), the image is taken from https://atlas.hashicorp.com , you can simply specify the url of the box via the box_url option.

Finally, the suites section describes a set of recipes that must be completed before running the tests. We have one suite named default. It describes the run-list with one recipe deploy-user :: default . This is the recipe in which we described the creation of a user.

Work with Test Kitchen


Now let's see what we can do with our kitchen.

You can view the list of machines and their status using the kitchen list command. Note that we have described only one suite, so only two machines will be created: default-ubuntu-1404 and default-centos-70. If we described another suite, the number of cars would double. The final number of machines is equal to: the number of suites multiplied by the number of platforms

With the kitchen converge command, we will start creating virtual machines and launching all suites for all platforms. You can run one suite on one platform like this: kitchen converge default-ubuntu-1404 . To remove all the machines and return everything as there was a kitchen destroy command.
how to turn off the virtual machine
The funny thing is, you cannot turn off the machines by means of Test Kitchen without removing them. On Github about it there is an epic saga in several actions issue https://github.com/test-kitchen/test-kitchen/issues/350

After running kitchen converge, we’ll get running virtual machines with the default.rb recipe from our deploy-user kukbook.

If there are errors in the codebook code, the chef-run will be interrupted and the place in the code that caused the error will be shown. We believe that the chef-run was successful =). Next, let's check if the suite really worked properly and did what we expected from it. Use the kitchen login default-ubuntu-1404 command to log in to one of the machines.

Run the command getent passwd deployer :
 deployer:x:1001:1001::/home/deployer:/bin/bash 

Indeed, user deployer is created, the correct home directory is used and the shell we need is used.

Now we’ll check that the user has created the home directory and has the correct owner, group and access rights: 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 

Indeed, the home directory exists and has the right owner, group and access rights.

Hooray, now you can test kukbuki!

Joke =)

Testing


To run the tests, there are two commands kitchen verify and kitchen test .

kitchen verify puts the framework for testing inside vm and runs your tests. You can edit your tests and re-run verify .

kitchen test starts a full test cycle. First , the kitchen destroy is executed , if the machine was previously created, then the suites are executed, tests are run and at the end sometimes the destroy is executed. By default, destroy is made if tests are successful. This behavior can be overridden using the kitchen test command options.

Nowadays, kukbuki is usually tested by the Serverspec framework, http://serverspec.org . Serverspec is an RSpec extension that provides convenient primitives for server testing. With the release of serverspec, people stopped writing tests on pure RSpec (as on bash).

If we start the kitchen verify now , we will see that an empty test was written for us:

  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 <default-ubuntu-1404> (0m36.87s). 


Open the file test / integration / default / serverspec / default_spec.rb and write a test on our kukbook:
 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 


The code describes the actions that we did on the machine manually.
The user deployer must exist, have the home directory / home / deployer , and have shell / bin / bash .
/ home / deployer must be a directory, have 755 access rights, the owner of the deployer, and the deployer group.

If we are not mistaken anywhere, the result of kitchen verify will be as follows:
 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 <default-ubuntu-1404> (0m1.92s). 


Hooray, now you can test kukbuki!

Bonus Unit testing


In the world of ches, unit testing also exists. It uses the chefspec tool, http://sethvargo.imtqy.com/chefspec/ . The main difference from testing through Test Kitchen is that the creation of virtual machines and the launch of the chef-run does not occur. Instead, a call to the resource with the required parameters is checked. This can be useful when some resources cannot be tested in the usual way. For example, if the performance of the resource depends on the external system or requires specific equipment. Well, such tests can be run in any CI system. Of the minuses worth noting that in this way is difficult to test LWRP.

An example of such a test can be found below.

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 


If in the file spec / spec_helper.rb add the line at_exit {ChefSpec :: Coverage.report! } , after the end of the tests, the percentage of coverage will be displayed.

You can run these tests with the chef exec rspec -c command
 .. 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! 

Useful documentation


Source: https://habr.com/ru/post/253139/


All Articles