Chef in 21 days. Part two. Creating and using a cookbook

  • Tutorial
Hi-hello, habrayuzer! Still with us? CHEF - it's interesting! We continue our voyage to the skill of an automation warrior, which began in the first part of this article. This article will focus on the first experience of writing a cookbook , recipes , attributes and templates .

Before moving on, a small digression about the infrastructure. In the future, we need a couple of computers or virtual machines. Of course, there is VirtualBox, there is Vagrant, but I strongly recommend using Amazon Web Services (AWS). The main reason is that AWS is widely used by different companies, and getting to know it is an added bonus to you. There are free images on it that anyone can use. There are many different services and tools that Amazon offers. Some of them are extremely relevant. I believe that this experience is a must-have experience.

Step 5. Welcome to the kitchen, baby

Welcome to the kitchen! In our hands is the most important and indispensable tool - knife !
What will we cook? Of course, our first recipe, and so as not to forget it and use it in the future, we will write it in our cookbook . This is exactly what knife will help us with, which knows how to create cookbooks. Of course, you can recreate the cookbook structure manually, but why? It is better to get acquainted with the correct structure of a standard cookbook.
In the creation, the knife cookbook create directive will help us . It will be created in the / cookbooks directory (you can specify its location in the configuration file knife.rb) folder with our first cookbook. Let's get acquainted with the main contents of this folder.

  • The / attributes directory contains files with a description of cookbook attributes that can be used on the node to overwrite the values ​​of certain default values ​​of the node. It can be variables that contain paths to working directories, network port numbers for services, any specific labels for this node (for example, its role in the working environment). The most important thing when using attributes is understanding how to apply them through a recipe. How does CHEF get the values ​​of standard attributes? He has a tool called ohai- collector of system attributes used for CHEF. These attributes are not system variables, you are unlikely to see such attribute names in your OS - these are variables with logical names such as node [“platform”] , which stores the name of the host OS, or node [“fqdn”] - storing Host FQDN If you want to make changes to the current configuration of a service / software, you need to use exactly the names of the attributes that ohai provides. An equally important attribute property is the identification of the node - the purpose of the mentioned “labels”. I will give an example from practice.
    It was necessary to create a group of virtual machines (chef-clients), connect them to the Chef-server and give them cookbooks in accordance with their role in this group (master or slave). At the stage of registering nodes on the Chef server, it is not known which node is master and which is slave . What to do, do not assign hands to everyone? Everything was decided simply to impossibility. Each node received, depending on its purpose, the attribute env_role = master or slave, which was available to the Chef server. The server, in turn, on all nodes registered on it, searched for this attribute and, depending on the value, handed out cookbooks (by means of roles, which we will talk about later).
  • The / files directory - contains a set of files that will be used for distribution to nodes. In other words, if you need to generate a file with static content on the node (it is understood that the contents of the file do not change during the use of it) - this is the directory where you put the files. Further, in the recipe, the cookbook_file resource initializes the use of your file. It is worth noting that the name of this resource indicates the absolute path of the file location on the node, so be careful when specifying the name. In order to specify the source file, a resource property called source is used., which indicates the name of the source file located in the / files directory. You can also optionally specify access rights to files on nodes, the user and a group of users who "own" these files.
    Another interesting property is the file name . There are templates for it , according to which a specific file can be transferred to a specific node (using FQDN), used on a specific platform with a specific current version. Example - a file named ubuntu-12.04 will be transferred only to nodes with Ubuntu OS version 12.04.
  • The / recipies directory is the fundamental directory of our cookbook, the directory with recipes. These are our recipes . It is here that determines what and how we will configure. The recipe file is a Ruby file, which obviously uses the syntax of the Ruby language (cap here!) Depending on the complexity of the task, it may contain a description of the functionality and collection of resources (for simple tasks) or the collection of resources and calls of providers ( we will talk about them below). In the recipe, you can call other recipes, build dependencies on other recipes, place script blocks for end nodes (for example, bash or powershellcommands) and use many other features available to the Ruby language. It is worth remembering that the code is executed in the order specified in the recipe. As a result, we have quite massive opportunities in our hands, limited by our knowledge of the Ruby language and its capabilities.
  • Directory / templates - contains resource templates that can be used in the recipe. Templates are described in Embedded Ruby format , have the extension .erb and describe dynamic content that is generated based on variables, logic, or plain text. Next, the resource template is declared in the resource. The minimum version of the ad is as follows:

    template “/path/to/file/on/our/node.cmd” do
         source “node.erb”

    Also, it is possible to set, for example, access rights, owner and group of owners of this file. In this specific case, the cmd file with the specified absolute path will be created on the node, the template of which is the node.erb file . This template can be a set of commands that must be run on the node through the command line. And it may also contain some variables and logic. Variables in the template can be, for example, attributes of your cookbook, giving the template the mentioned dynamism. It looks like this:
    <%= node['sql_server']['product_key'] %>,
    and a declaration of an attribute (SQL server's public key), present in the cookbook-e. Also, it is worth noting that, like the file names in the / files directory, template names have the same name property, namely, they describe the correspondence of a template to a specific OS and version, or to the FQDN of a node.
  • The / providers and / resources directories are the two directories that in terms of Chef organize LWRP ( light-weight resource providers ). I could compare this with the concept of a class in OOP, however, such a comparison may not be very correct (brothers programmers will forgive the administrator). In the provider, you can describe the functionality , in resources - attributes / variables and available actions (possible actions for providers that can be called from recipes). Resources are identified and associated with the provider, forming a semblance of a “class”.
    Interactions between parts of LWRP are provided using Resource DSL.- a language containing several methods for describing attributes and actions. And given that this is a variant of Ruby DSL, the Ruby code can also be part of the definition of resources and providers. In order not to go into theory for a long time, here is an example of LWRP, which sends out letters (for example, when an event occurs in the system).


    def mailing  
      puts "\n Sending your email..."
      r = chef_gem "mail" do
      	action :install
      require 'mail'
      options = { 
      			:address              => new_resource.server,
                :port                 => new_resource.port,
                :mailto				  => new_resource.mailto,
                :user_name            => new_resource.user_name,
                :password             => new_resource.password,
                :authentication       => 'plain',
                :enable_starttls_auto => true  
        Mail.defaults do
              delivery_method :smtp, options
        mail = Mail.deliver do
            from options[:user_name]
            to options[:mailto]
            subject 'Hello'
            body new_resource.msg

    actions :create
    default_action :create
    attribute :app_name, :kind_of => String
    attribute :user_name, :kind_of => String, :default => ""
    attribute :password, :kind_of => String, :default => ""
    attribute :server, :kind_of => String, :default => ""
    attribute :port, :kind_of => Integer, :default => 465
    attribute :mailto, :kind_of => [String, NilClass], :default => ""
    attribute :from, :kind_of => [String, NilClass], :default => ""
    attribute :msg, :kind_of => String, :default => "Hi there"
    def initialize(*args)
       @ action = :create

    I think it’s obvious enough, even for those who have not encountered the Ruby syntax that is described in this file. This is an email function. In the next part, we will get acquainted with a cookbook that uses LWRP to send messages about changes in the system.

Step 6. Tasting time

Well, let's imagine that our cookbook is ready (I will provide an example of it and describe the use in the next part).
What to do next? How to upload it to the server and send it for execution by nodes? Knife will do it for us. In order to successfully carry out further operations, we need the Chef admin to have a properly configured knife (file knife.rb) and an administrator certificate (for example, admin.pem). Next, you need to go to the / chef-repo directory (where our starter kit is located, for example) and, being in it, execute commands.
The first step is to make sure that the nodes are registered on the server knife node list. As a result, you should get the names of the active nodes.
Next, upload ourcookbook to the server. It should be located in the directory specified in the cookbook_path of the knife.rb file .
We execute - knife cookbook upload name-of-cookbook. As a result - a message about a successful download and the presence of our cookbook in the list received by the team knife cookbook list.
The next step is to assign a run-list node. Here you can go in 2 ways - simple or right .
Simple - immediately add a recipe to the run-list - knife node edit name-of-nodeand make text changes to the run-list section, adding the line “recipe [name-of-recipe]” there . But what if there are a dozen such recipes? Not very comfortable.

The right way is to add a role. The role file is a description of the run-list attributes . Including - and recipes. Accordingly, one role can be assigned to multiple nodes. The role file is located at / chef-repo / roles :

name "mailer"
description "Role for host that will notify us on changes"
run_list "recipe[name-of-recipe]"

In order to upload the role to the server, the command is used knife role from file name-of-role-file. After loading - the role can be assigned in the run-list of the node, which we will do.

This simple process is over, we are ready to run the client on the site. After that, we get a node with ( conditionally ) implemented cookbook on it .

With this, I will finish the second part and will announce the third - a more technical-oriented (with a lot of code), which will tell about the example of using AWS and Chef .

Also popular now: