{"id":4292,"date":"2013-04-19T01:00:50","date_gmt":"2013-04-18T22:00:50","guid":{"rendered":"http:\/\/railsware.com\/blog\/?p=4292"},"modified":"2021-08-15T15:11:09","modified_gmt":"2021-08-15T12:11:09","slug":"getting-started-with-chef-server-part-1","status":"publish","type":"post","link":"https:\/\/railsware.com\/blog\/getting-started-with-chef-server-part-1\/","title":{"rendered":"Getting Started with Chef Server"},"content":{"rendered":"\n<p>Hello my dear friends. Today we will talk about a Chef Server. In this article we will learn what is the Chef Server and how to setup it up. Before reading this article, it&#8217;s better to read my articles about <a href=\"http:\/\/leopard.in.ua\/2013\/01\/04\/chef-solo-getting-started-part-1\/\">Chef Solo<\/a>. Here I&#8217;ll explain only those things that hasn&#8217;t already been covered in those Chef Solo series of articles.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is the Chef Server?<\/h2>\n\n\n\n<p>Chef is a Ruby-based configuration management engine.<\/p>\n\n\n\n<p>The Chef Server acts as a hub, ensuring that the right cookbooks are used, that the right policies are applied, that all of the node objects are up-to-date, and that all of the nodes that will be maintained are registered and known to the Chef Server. The Chef Server distributes configuration details (such as recipes, templates, and file distributions) to every node within the organization. Chef then does as much of the configuration work as possible on the nodes themselves (and not on the Chef Server). This scalable approach distributes the configuration effort throughout the organization.<\/p>\n\n\n\n<p>There are three types of Chef Servers:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Hosted Chef is a version of a Chef Server that is hosted by Opscode. Hosted Chef is cloud-based, scalable, and available (24&#215;7\/365), with resource-based access control. Hosted Chef has all of the automation capabilities of Chef, but without requiring it to be set up and managed from behind the firewall.<\/li><li>Private Chef is a version of a Chef Server that is designed to provide all of the infrastructure automation capabilities of Chef, set up and managed from within the organization.<\/li><li>Open Source Chef is an open source version of the Chef Server that contains much of the same functionality as Hosted Chef, but requires that each instance be configured and managed locally, including performing data migrations, applying updates to the Open Source Chef server, and ensuring that the Open Source Chef server scales as the local infrastructure it is supporting grows. Open Source Chef includes support from the Chef community but does not include support directly from Opscode.<\/li><\/ul>\n\n\n\n<p>In the series of articles we will work with Open Source Chef.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is the difference between Chef Solo and Chef Server?<\/h2>\n\n\n\n<p>Chef Solo does not provide:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Node data storage or search indexes.<\/li><li>Centralized cookbook distribution.<\/li><li>Environments, for setting policy of cookbook versions.<\/li><li>A central API to interact with and use to integrate infrastructure components.<\/li><li>Bulk operations with nodes.<\/li><\/ul>\n\n\n\n<p>As you can see, Chef Solo is useful for small infrastructure (several servers), but if you have a huge amount of server &#8211; you must use Chef Server.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Environments<\/h2>\n\n\n\n<p>As you remember, Chef Solo has nodes, roles and data bags. Chef Server have additional policy: environments. An environment is a way to map an organization&#8217;s real-life workflow to what can be configured and managed when using Chef Server. Every Chef organization begins with a single environment called the &#8220;_default&#8221; environment, which cannot be modified (or deleted). Additional environments can be created, such as production, staging, testing, and development. Generally, an environment is also associated with one (or more) cookbook versions. An environment attribute can only be set to be a default attribute or an override attribute.<\/p>\n\n\n\n<p>Attributes for recipes can be redefined in this way (except &#8220;override attributes&#8221;):<\/p>\n\n\n\n<p>Defaults (lowest precedence) -&gt; Environments -&gt; Roles -&gt; Nodes (highest precedence)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Chef version<\/h2>\n\n\n\n<p>In this series of articles we will work with Chef 11. You can read about changes in this Chef version by <a href=\"http:\/\/docs.opscode.com\/breaking_changes_chef_11.html\">this link<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Initialize Chef Server project<\/h2>\n\n\n\n<p>To setup and configure Chef Server we will use Chef Solo (really? :). This is because this component of the system also should be quickly deployed to the new server, if something happened with Chef Server something happens (crash file system of server, etc.). Do not forget to make a backups of Chef Server (because compared with Chef Solo, Chef Server will be the point of failure in your configuration management system).<\/p>\n\n\n\n<p>Let&#8217;s create our folder, which will contain all our Chef kitchen:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ mkdir chef-server-example\n$ cd chef-server-example\n<\/pre>\n\n\n\n<p>Next I will use <a href=\"http:\/\/gembundler.com\/\">bundler<\/a> to get some useful gems:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ cat Gemfile\n  source :rubygems\n  # \n  # gem 'chef', \"~> 11.4.0\"\n  # need version 11.4.0, but problem with net-ssh versions conflict\n  # install it manual by \"gem install\" command\n  # \n  gem 'knife-solo'\n  gem 'berkshelf', github: \"RiotGames\/berkshelf\", branch: \"fix-for-chef-11\"\n  gem 'ffi', '~> 1.2.0'\n  gem 'vagrant'\n  gem 'oj'\n  gem 'multi_json'\n\n$ bundle\n<\/pre>\n\n\n\n<p>And create a kitchen for the Chef:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife solo init .\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Berkshelf<\/h2>\n\n\n\n<p>As you remember, we used librarian gem to manage cookbooks for Chef Solo we used librarian gem. For this tutorial, I selected another good gem to manage a cookbooks dependencies &#8211; <a href=\"http:\/\/berkshelf.com\/\">berkshelf<\/a>. You can use anyone you like, but compared to the &#8220;librarian&#8221; the &#8220;berkshelf&#8221; has several pros:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>By default, berkshelf stores every version of a cookbook that you have ever installed in one folder on your local machine (the same workflow as for rubybems)<\/li><li>Flexible configuring<\/li><li>Build-in integration with <a href=\"http:\/\/www.vagrantup.com\/\">Vagrant<\/a> and <a href=\"https:\/\/github.com\/wycats\/thor\">Thor<\/a><\/li><li>Adding sources of cookbooks to groups (like have bundler)<\/li><\/ul>\n\n\n\n<p>Let&#8217;s create the Berksfile file and add the \u201cchef-server\u201d cookbook <a href=\"https:\/\/github.com\/opscode-cookbooks\/chef-server\">&#8220;chef-server&#8221; cookbook<\/a> (this cookbook supported by Opscode):<\/p>\n\n\n\n<p>Let\u2019s create the Berksfile file and add the \u201cchef-server\u201d cookbook to it (this cookbook supported by Opscode):<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ cat Berksfile\n#!\/usr\/bin\/env ruby\n#^syntax detection\n\nsite :opscode\n\ncookbook 'chef-server',\n  git: 'git:\/\/github.com\/opscode-cookbooks\/chef-server.git'\n\n$ berks install\n<\/pre>\n\n\n\n<p>After launch of command &#8220;berks install&#8221; your cookbooks directory will be clear, because by default &#8220;berkshelf&#8221; install cookbooks into &#8220;~\/.berkshelf&#8221; location. You can easily install your Cookbooks and their dependencies to a location other than default by argument &#8220;&#8211;path&#8221;:<\/p>\n\n\n\n<p>After the launch of the \u201cberks install\u201d command, your cookbooks directory will be clear, because, by default, \u201cberkshelf\u201d installs cookbooks into \u201c~\/.berkshelf\u201d location. You can easily install your Cookbooks and their dependencies to a location other than the default by the argument \u201c\u2013path\u201d argument:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ berks install --path cookbooks\n<\/pre>\n\n\n\n<p>But right now we don&#8217;t need this.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configure Chef Server node<\/h2>\n\n\n\n<p>After this, we should configure the Chef Solo node for our Chef Server. I will do this by using a role. First of all, we should create &#8220;chef.json&#8221; in the role folder with content:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n  \"name\": \"chef\",\n  \"chef_type\": \"role\",\n  \"json_class\": \"Chef::Role\",\n  \"description\": \"The base role for Chef Server\",\n  \"default_attributes\": {\n    \"chef-server\": {\n      \"version\": \"latest\",\n      \"configuration\": {\n        \"chef_server_webui\": {\n          \"enable\": true\n        }\n      }\n    }\n  },\n  \"run_list\": [\n    \"recipe[chef-server::default]\"\n  ]\n}\n<\/pre>\n\n\n\n<p>By the &#8220;configuration&#8221; key you can change settings for Chef Server. All available settings, which is possible to redefined, you can find <a href=\"https:\/\/github.com\/opscode\/omnibus-chef\/blob\/master\/files\/chef-server-cookbooks\/chef-server\/attributes\/default.rb\">here<\/a>.<\/p>\n\n\n\n<p>Next, we should create the &#8220;vagrant.json&#8221; node with the following content:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n  \"run_list\": [\n    \"role[chef]\"\n  ]\n}\n<\/pre>\n\n\n\n<p>We are ready for testing this Chef Server kitchen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Vagrant<\/h2>\n\n\n\n<p>For testing Chef Server by vagrant, we need to download the vagrant box. List of boxes you can find at <a href=\"http:\/\/www.vagrantbox.es\/\">www.vagrantbox.es<\/a>.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ vagrant box add precise64 http:\/\/dl.dropbox.com\/u\/1537815\/precise64.box\n$ vagrant init precise64\n<\/pre>\n\n\n\n<p>Next, we need to model a cluster of machines by vagrant. Let&#8217;s modify the Vagrantfile:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">require 'rubygems'\nrequire 'bundler'\n\nBundler.require\nrequire 'multi_json'\nrequire 'berkshelf\/vagrant'\n\nhost_cache_path = File.expand_path(\"..\/.cache\", __FILE__)\nguest_cache_path = \"\/tmp\/vagrant-cache\"\n\n# ensure the cache path exists\nFileUtils.mkdir(host_cache_path) unless File.exist?(host_cache_path)\n\nVagrant::Config.run do |config|\n\n  config.vm.define :chef do |chef_config|\n    config.vm.customize [\"modifyvm\", :id, \"--cpus\", 2]\n    config.vm.customize [\"modifyvm\", :id, \"--memory\", 1024]\n\n    chef_config.vm.box = \"precise64\"\n    chef_config.vm.network :hostonly, \"10.33.33.33\"\n    chef_config.vm.share_folder \"cache\", guest_cache_path, host_cache_path\n\n    chef_config.ssh.max_tries = 40\n    chef_config.ssh.timeout   = 120\n\n    chef_config.berkshelf.berksfile_path = Pathname(__FILE__).dirname.join('Berksfile')\n\n    VAGRANT_JSON = MultiJson.load(Pathname(__FILE__).dirname.join('nodes', 'vagrant.json').read)\n\n    chef_config.vm.provision :chef_solo do |chef|\n       chef.cookbooks_path = [\"site-cookbooks\", \"cookbooks\"]\n       chef.roles_path = \"roles\"\n       chef.data_bags_path = \"data_bags\"\n       chef.provisioning_path = guest_cache_path\n\n       chef.json = VAGRANT_JSON\n       VAGRANT_JSON['run_list'].each do |recipe|\n        chef.add_recipe(recipe)\n       end if VAGRANT_JSON['run_list']\n\n       Dir.glob(Pathname(__FILE__).dirname.join('roles', '*.json')).each do |role|\n        chef.add_role(Pathname.new(role).basename(\".*\").to_s)\n       end\n    end\n  end\n\n  config.vm.define :chef_client do |chef_client_config|\n    chef_client_config.vm.box = \"precise64\"\n    chef_client_config.vm.network :hostonly, \"10.33.33.50\"\n\n    chef_client_config.ssh.max_tries = 40\n    chef_client_config.ssh.timeout   = 120\n  end\nend\n<\/pre>\n\n\n\n<p>We set two nodes: chef (Chef Server) and chef\\_client (client of Chef Server). We use the &#8220;hostonly&#8221; network for these servers. In this case, both of these servers will be available by IPs: 10.33.33.33 and 10.33.33.50. Also, there&#8217;s no need to forward ports because services on these servers can be available by this IPs. To find more, read <a href=\"http:\/\/docs.vagrantup.com\/v1\/docs\/multivm.html\">&#8220;Multi-VM Environments&#8221;<\/a> and <a href=\"http:\/\/docs.vagrantup.com\/v1\/docs\/provisioners\/chef_solo.html\">&#8220;Chef Solo Provisioning&#8221;<\/a> you can find by this links.<\/p>\n\n\n\n<p>Let&#8217;s create our nodes:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ vagrant up\n\/Users\/leo\/.rvm\/gems\/ruby-1.9.3-p385\/gems\/hashie-2.0.0\/lib\/hashie\/mash.rb:80: warning: redefining `object_id' may cause serious problems\n[chef] Importing base box 'precise64'...\n\n...\n\n[Berkshelf] installing cookbooks...\n[Berkshelf] Installing chef-server (2.0.0) from git: 'git:\/\/github.com\/opscode-cookbooks\/chef-server.git' with branch: 'a3b94e30b599f901eee2eb1af5bc1f4ef011cae4'\n\n...\n\n[chef] Running chef-solo...\nstdin: is not a tty\n[Sat, 16 Feb 2013 12:09:03 +0000] INFO: *** Chef 0.10.10 ***\n[Sat, 16 Feb 2013 12:09:03 +0000] INFO: Setting the run_list to [\"role[chef]\"] from JSON\n[Sat, 16 Feb 2013 12:09:03 +0000] INFO: Run List is [role[chef]]\n[Sat, 16 Feb 2013 12:09:03 +0000] INFO: Run List expands to [chef-server::default]\n[Sat, 16 Feb 2013 12:09:03 +0000] INFO: Starting Chef Run for precise64\n[Sat, 16 Feb 2013 12:09:03 +0000] INFO: Running start handlers\n[Sat, 16 Feb 2013 12:09:03 +0000] INFO: Start handlers complete.\n[Sat, 16 Feb 2013 12:09:03 +0000] INFO: Omnitruck download-server request: http:\/\/www.opscode.com\/chef\/download-server?p=ubuntu&amp;pv=12.04&amp;m=x86_64&amp;v=latest&amp;prerelease=false&amp;nightlies=false\n\n...\n\n[Sat, 16 Feb 2013 12:17:59 +0000] INFO: Chef Run complete in 536.107466 seconds\n[Sat, 16 Feb 2013 12:17:59 +0000] INFO: Running report handlers\n[Sat, 16 Feb 2013 12:17:59 +0000] INFO: Report handlers complete\n<\/pre>\n\n\n\n<p>Our Chef Server by default takes your systems <a href=\"http:\/\/en.wikipedia.org\/wiki\/Fully_qualified_domain_name\">FQDN<\/a> as Chef Server url. We can check Chef Server web interface by &#8220;https:\/\/10.33.33.33&#8221; and info about versions by &#8220;https:\/\/10.33.33.33\/version&#8221; url. It should looks like this:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"791\" height=\"389\" src=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/chef_server_versions.png\" alt=\"\" class=\"wp-image-4297\" srcset=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/chef_server_versions.png 791w, https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/chef_server_versions-300x147.png 300w\" sizes=\"auto, (max-width: 791px) 100vw, 791px\" \/><\/figure><\/div>\n\n\n\n<p>After login by &#8220;admin\/p@ssw0rd1&#8221; you must change admin password to some secure password.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">SSH keys<\/h2>\n\n\n\n<p>After installation Chef Server with default settings, Chef will generate pem keys, which will be used for knife (command line tool for Chef) and Chef clients for authentication with the server. We should copy them from our Chef Server to &#8220;.chef&#8221; directory in the project:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ vagrant ssh chef\nWelcome to Ubuntu 12.04.1 LTS (GNU\/Linux 3.2.0-23-generic x86_64)\n\n * Documentation:  https:\/\/help.ubuntu.com\/\nWelcome to your Vagrant-built virtual machine.\nLast login: Mon Aug 20 19:28:45 2012 from 10.0.2.2\nvagrant@precise64:~$ sudo cp \/etc\/chef-server\/*.pem \/vagrant\/.chef\/\n<\/pre>\n\n\n\n<p>On prodution you can use scp command for this.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Knife configuration<\/h2>\n\n\n\n<p>Next we should create for knife configuration file (knife should know how to communicate with Chef Server):<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife configure -i\nWARNING: No knife configuration file found\nWhere should I put the config file? [\/Users\/leo\/.chef\/knife.rb] .chef\/knife.rb\nPlease enter the chef server URL: [http:\/\/macbookproleo:4000] https:\/\/10.33.33.33\nPlease enter a clientname for the new client: [leo] admin\nPlease enter the existing admin clientname: [chef-webui] \nPlease enter the location of the existing admin client's private key: [\/etc\/chef\/webui.pem] .chef\/webui.pem\nPlease enter the validation clientname: [chef-validator] \nPlease enter the location of the validation key: [\/etc\/chef\/validation.pem] .chef\/validation.pem\nPlease enter the path to a chef repository (or leave blank): \nCreating initial API user...\n<\/pre>\n\n\n\n<p>If you have such error:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ERROR: knife encountered an unexpected error\nThis may be a bug in the 'configure' knife command or plugin\nPlease collect the output of this command with the `-VV` option before filing a bug report.\nException: NoMethodError: undefined method `save' for #&lt;Hash:0x007fa8fe123668>\n<\/pre>\n\n\n\n<p>This mean, what you are using chef version 11.0.0. This bug fixed in version 11.4.0.<\/p>\n\n\n\n<p>As a result, you should have a file &#8220;.chef\/knife.rb&#8221; with similar content:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">log_level                :info\nlog_location             STDOUT\nnode_name                'admin'\nclient_key               '\/Users\/leo\/programs\/projects\/chef-server-example\/.chef\/admin.pem'\nvalidation_client_name   'chef-validator'\nvalidation_key           '\/Users\/leo\/programs\/projects\/chef-server-example\/.chef\/validation.pem'\nchef_server_url          'https:\/\/10.33.33.33'\nsyntax_check_cache_path  '\/Users\/leo\/programs\/projects\/chef-server-example\/.chef\/syntax_check_cache'\n<\/pre>\n\n\n\n<p>Let&#8217;s check knife configuration:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife client list\nchef-validator\nchef-webui\n<\/pre>\n\n\n\n<p>If you see an error on command &#8220;knife client list&#8221; &#8211; check you knife configuration, you pem keys and availability of Chef server.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Bootstrap first node<\/h1>\n\n\n\n<p>Once the Chef Server workstation is configured, it can be used to install Chef on one (or more) nodes across the organization using a Knife bootstrap operation. The &#8220;knife bootstrap&#8221; command is used to SSH into the target machine, and then do what is needed to allow the chef-client to run on the node. It will install the chef-client executable (if necessary), generate keys, and register the node with the Chef Server. The bootstrap operation requires the IP address or FQDN of the target system, the SSH credentials (username, password or identity file) for an account that has root access to the node, and (if the operating system is not Ubuntu, which is the default distribution used by knife bootstrap) the operating system running on the target system.<\/p>\n\n\n\n<p>So let&#8217;s do this:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife bootstrap 10.33.33.50 -x vagrant -P vagrant --sudo\nBootstrapping Chef on 10.33.33.50\n10.33.33.50 --2013-02-16 16:08:36--  http:\/\/opscode.com\/chef\/install.sh\n10.33.33.50 Resolving opscode.com (opscode.com)... \n10.33.33.50 184.106.28.82\n10.33.33.50 Connecting to opscode.com (opscode.com)|184.106.28.82|:80... \n10.33.33.50 connected.\n\n...\n\n10.33.33.50 Starting Chef Client, version 11.0.0\n10.33.33.50 Creating a new client identity for precise64 using the validator key.\n10.33.33.50 resolving cookbooks for run list: []\n10.33.33.50 Synchronizing Cookbooks:\n10.33.33.50 Compiling Cookbooks...\n10.33.33.50 [2013-02-16T16:09:13+00:00] WARN: Node precise64 has an empty run list.\n10.33.33.50 Converging 0 resources\n10.33.33.50 Chef Client finished, 0 resources updated\n<\/pre>\n\n\n\n<p>Let&#8217;s check clients on Chef Server:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife client list\nchef-validator\nchef-webui\nprecise64\n<\/pre>\n\n\n\n<p>As you can see we get a new client &#8220;precise64&#8221;.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife client show precise64\nadmin:      false\nchef_type:  client\njson_class: Chef::ApiClient\nname:       \npublic_key:\n<\/pre>\n\n\n\n<p>You can also see this client in Chef Server web interface:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/precise64.png\"><img loading=\"lazy\" decoding=\"async\" width=\"822\" height=\"460\" src=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/precise64.png\" alt=\"precise64\" class=\"wp-image-4299\" srcset=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/precise64.png 822w, https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/precise64-300x167.png 300w\" sizes=\"auto, (max-width: 822px) 100vw, 822px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>And new registered node:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife node list\nprecise64\n<\/pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><a href=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/precise64_2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"821\" height=\"889\" src=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/precise64_2.png\" alt=\"precise64_2\" class=\"wp-image-4298\" srcset=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/precise64_2.png 821w, https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/precise64_2-277x300.png 277w\" sizes=\"auto, (max-width: 821px) 100vw, 821px\" \/><\/a><\/figure><\/div>\n\n\n\n<h1 class=\"wp-block-heading\">Chef Solo. Part 2<\/h1>\n\n\n\n<p>Previously we&#8217;ve learned Chef, Chef Server and its setup process. Now we&#8217;ll figure out how to work with it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Directory .chef<\/h2>\n\n\n\n<p>In the Part 1 article we set up chef server and added one node (server) to it. For an authentication with chef server we use ssh keys; and for knife we have a configuration in knife.rb. All this stuff should be in \u201c.chef\u201d directory. Here&#8217;s our modified knife.rb file (fixed paths for keys):<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">log_level                :info\nlog_location             STDOUT\nnode_name                'admin'\nclient_key               File.expand_path('..\/admin.pem', __FILE__)\nvalidation_client_name   'chef-validator'\nvalidation_key           File.expand_path('..\/chef-validator.pem', __FILE__)\nchef_server_url          'http:\/\/10.33.33.33'\nsyntax_check_cache_path  'syntax_check_cache'\ncookbook_path            [ '.\/cookbooks', '.\/site-cookbooks' ]<\/pre>\n\n\n\n<p>When a node runs the chef-client for the first time, it does not yet have an API client identity, and therefore can&#8217;t send authenticated requests to the server. This is where the validation client \u2014 known as the chef-validator \u2014 comes in. When the chef-client runs, it checks if it has a \u201cclient_key\u201d; and if the client key does not exist, it tries to borrow the chef-validator identity to register itself with the server (\u201cvalidation_key\u201d).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Attribute Precedence<\/h2>\n\n\n\n<p>Attributes are always applied by the chef-client in the following order:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>A default attribute located in an attribute file<\/li><li>A default attribute located in a recipe<\/li><li>A default attribute located in an environment<\/li><li>A default attribute located in role<\/li><li>A force_default attribute located in an attribute file<\/li><li>A force_default attribute located in a recipe<\/li><li>A normal attribute located in an attribute file<\/li><li>A normal attribute located in a recipe<\/li><li>An override attribute located in an attribute file<\/li><li>An override attribute located in a recipe<\/li><li>An override attribute located in a role<\/li><li>An override attribute located in an environment<\/li><li>A force_override attribute located in an attribute file<\/li><li>A force_override attribute located in a recipe<\/li><li>An automatic attribute identified by Ohai at the start of the chef-client run<\/li><\/ol>\n\n\n\n<p>Attribute precedence in the form of an overview diagram, where the numbers in the diagram match the order of attribute precedence:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/09\/overview_chef_attributes_precedence.png-2013-09-25-16-47-03.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"380\" src=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/09\/overview_chef_attributes_precedence.png-2013-09-25-16-47-03.jpg\" alt=\"overview_chef_attributes_precedence.png 2013-09-25 16-47-03\" class=\"wp-image-5668\"\/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/09\/overview_chef_attributes_table.png\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"300\" src=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/09\/overview_chef_attributes_table.png\" alt=\"overview_chef_attributes_table\" class=\"wp-image-5666\"\/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Power of Environments<\/h2>\n\n\n\n<p>Environment is a way to map an organisation\u2019s real-life workflow on what can be configured and managed when using server. Every organisation begins with a single environment &#8211; a so called _default environment &#8211; which cannot be modified (or deleted). Additional environments can be created to reflect each organisation\u2019s patterns and workflow. Creating production, staging, testing, and development environments is a good example. An environment can be also associated with one (or more) cookbook versions.<\/p>\n\n\n\n<p>A per-environment run-list is a run-list that is associated with a role and a specific environment. There&#8217;s more than one environment that can be specified in a role, but each specific environment may be associated with only one run-list. If a run-list is not specified, the default run-list will be used. For example:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n  \"name\": \"webserver\",\n  \"default_attributes\": {\n  },\n  \"json_class\": \"Chef::Role\",\n  \"env_run_lists\": {\n    \"production\": [],\n    \"preprod\": [],\n    \"test\": [ \"role[base]\", \"recipe[apache]\" \"recipe[apache::copy_test_configs]\" ],\n    \"dev\": [ \"role[base]\", \"recipe[apache]\", \"recipe[apache::copy_dev_configs]\" ]\n    },\n  \"run_list\": [ \"role[base]\", \"recipe[apache]\" ],\n  \"description\": \"The webserver role\",\n  \"chef_type\": \"role\",\n  \"override_attributes\": {\n  }\n}<\/pre>\n\n\n\n<p>where:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>\u201cwebserver\u201d is the name of the role<\/li><li>\u201cenv_run_lists\u201d is a hash of per-environment run-lists for production, preprod, test, and dev<\/li><li>\u201cproduction\u201d and \u201cpreprod\u201d use the default run-list because they do not have a per-environment run-list<\/li><li>\u201crun_list\u201d defines the default run-list<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Chef Server And SSL Self-Signed Certificate<\/h2>\n\n\n\n<p>As you might recall from the previous article, Chef is by default working on https protocol only (security!). This can be a problem however, if you don\u2019t want to buy a valid ssl certificate for your chef server, because each command to chef server by knife will give you error with invalid ssl. The most simple solution &#8211; disable https and work only on http. For this lets modify our chef.js on role:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n  \"name\": \"chef\",\n  \"chef_type\": \"role\",\n  \"json_class\": \"Chef::Role\",\n  \"description\": \"The base role for Chef Server\",\n  \"default_attributes\": {\n    \"chef-server\": {\n      \"api_fqdn\": \"10.33.33.33\",\n      \"configuration\": {\n        \"chef-server-webui\": {\n          \"enable\": true,\n          \"web_ui_admin_user_name\": \"admin\",\n          \"web_ui_admin_default_password\": \"password\"\n        },\n        \"nginx\": {\n          \"url\": \"http:\/\/10.33.33.33\",\n          \"enable_non_ssl\": true\n        },\n        \"bookshelf\": {\n          \"url\": \"http:\/\/10.33.33.33\"\n        }\n      }\n    }\n  },\n  \"run_list\": [\n    \"recipe[chef-server]\"\n  ]\n}<\/pre>\n\n\n\n<p>I&#8217;ve added sections \u201cnginx\u201d which allows us to work with Chef server by http protocol and \u201cbookshelf\u201d which should write url to chef server without https. If we leave https, bookshelf will be available only by https.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cookbooks, roles and nodes on chef server<\/h2>\n\n\n\n<p>If compared with Chef Solo, Chef Server stores all the information on server and uses only this information for \u201ccooking\u201d nodes. Therefore, we should know how to upload our roles, cookbooks and nodes on server. First of all, we should install vender cookbooks locally by Berkshelf:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ berks install --path cookbooks\nInstalling chef-server (2.0.0) from git: 'git:\/\/github.com\/opscode-cookbooks\/chef-server.git' with branch: '18d6e951a2daa1154b7e82c8909bb7245e57ec1b'<\/pre>\n\n\n\n<p>Let\u2019s add python chef cookbook to Berkshelf and run this command again:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ berks install --path cookbooks\nInstalling chef-server (2.0.0) from git: 'git:\/\/github.com\/opscode-cookbooks\/chef-server.git' with branch: '18d6e951a2daa1154b7e82c8909bb7245e57ec1b'\nInstalling python (1.4.1) from git: 'git@github.com:opscode-cookbooks\/python.git' with branch: 'f932b3649683b58f7b0fb06a8b43eab2c6f24486'\nUsing build-essential (1.3.4)\nUsing yum (2.1.0)<\/pre>\n\n\n\n<p>As you can see, dependencies downloaded automatically. Right now we have these cookbooks only in our local directory \u201ccookbooks\u201d. Let\u2019s upload it to Chef Server. For this task we can use knife:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife cookbook upload --all --cookbook-path cookbooks\nUploading build-essential [1.3.4]\nUploading chef-server  [2.0.0]\nUploading python       [1.4.1]\nUploading yum          [2.1.0]\nUploaded all cookbooks.\n\n$ knife cookbook upload --all --cookbook-path site-cookbooks # don't forget about own custom cookbooks in 'site-cookbooks' folder<\/pre>\n\n\n\n<p>or we can use Berkshelf:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ berks upload\nInstalling chef-server (2.0.0) from git: 'git:\/\/github.com\/opscode-cookbooks\/chef-server.git' with branch: 'master' at ref: '18d6e951a2daa1154b7e82c8909bb7245e57ec1b'\nInstalling python (1.4.1) from git: 'git@github.com:opscode-cookbooks\/python.git' with branch: 'master' at ref: 'f932b3649683b58f7b0fb06a8b43eab2c6f24486'\nUsing build-essential (1.3.4)\nUsing yum (2.1.0)\nUploading chef-server (2.0.0) to: 'http:\/\/10.33.33.33:80\/'\nUploading python (1.4.1) to: 'http:\/\/10.33.33.33:80\/'\nUploading build-essential (1.3.4) to: 'http:\/\/10.33.33.33:80\/'\nUploading yum (2.1.0) to: 'http:\/\/10.33.33.33:80\/'<\/pre>\n\n\n\n<p>If you&#8217;re actively developing a cookbook, sometimes you might not want to change version with every little fix. Chef server, however, will not allow uploading same versions of cookbook by default:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife cookbook upload --all --cookbook-path cookbooks\nUploading build-essential [1.3.4]\nUploading chef-server    [2.0.0]\nUploading python         [1.4.1]\nUploading yum            [2.1.0]\nERROR: Version 1.3.4 of cookbook build-essential is frozen. Use --force to override.\nWARNING: Not updating version constraints for some cookbooks in the environment as the cookbook is frozen.\nUploaded all cookbooks.<\/pre>\n\n\n\n<p>Apparently, we can force update cookbooks by option \u201d\u2013force\u201d:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife cookbook upload --all --force --cookbook-path cookbooks\nUploading build-essential [1.3.4]\nUploading chef-server    [2.0.0]\nUploading python         [1.4.1]\nUploading yum            [2.1.0]\nUploaded all cookbooks.<\/pre>\n\n\n\n<p>All your cookbooks can be viewed in the web interface (if you enable it):<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/09\/chef_cookbooks_list.png\"><img loading=\"lazy\" decoding=\"async\" width=\"572\" height=\"524\" src=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/09\/chef_cookbooks_list.png\" alt=\"chef_cookbooks_list\" class=\"wp-image-5688\"\/><\/a><\/figure>\n\n\n\n<p>Then, we want to upload or update roles on server. It\u2019s also easy:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife role from file roles\/*.json\nUpdated Role chef!<\/pre>\n\n\n\n<p>This is a role in the web interface:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/09\/chef_role_show.png\"><img loading=\"lazy\" decoding=\"async\" width=\"605\" height=\"809\" src=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/09\/chef_role_show.png\" alt=\"chef_role_show\" class=\"wp-image-5689\"\/><\/a><\/figure>\n\n\n\n<p>Almost same commands for environment upload or update:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife environment from file environments\/*.json\nUpdated Environment staging!\nUpdated Environment production!<\/pre>\n\n\n\n<p>or nodes:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife node from file nodes\/*.json\nUpdated nodes\/web.node.json<\/pre>\n\n\n\n<p>You can also upload everything using \u201cupload\u201d command:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife upload nodes\nCreated nodes\/vagrant.json\nUpdated nodes\/web.node.json<\/pre>\n\n\n\n<p>Just don\u2019t forget to do this. It is also a good point to save current nodes, environments and roles in git (hg, svn, etc.) repo, because if you somehow lose chef server, all cookbooks and recipes will be saved.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cooking of the nodes<\/h2>\n\n\n\n<p>Let&#8217;s now cook our node \u201cweb.dev\u201d. We will install on it python. So let\u2019s add to \u201cweb.node\u201d run list:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n  \"chef_type\": \"node\",\n  \"json_class\": \"Chef::Node\",\n  \"run_list\": [\n    \"recipe[python]\"\n  ]\n}<\/pre>\n\n\n\n<p>And update web.node on chef server:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife upload nodes\nCreated nodes\/vagrant.json\nUpdated nodes\/web.node.json<\/pre>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/09\/chef_server_node.png\"><img loading=\"lazy\" decoding=\"async\" width=\"658\" height=\"804\" src=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/09\/chef_server_node.png\" alt=\"chef_server_node\" class=\"wp-image-5692\"\/><\/a><\/figure>\n\n\n\n<p>By default, chef client on nodes will not execute your run_list, but you can execute any command on nodes by command \u201cssh\u201d. For example, run chef client on all nodes:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife ssh 'name:*' 'sudo chef-client'<\/pre>\n\n\n\n<p>For this command you can use ssh options:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife ssh \"name:*\" \"sudo chef-client\" -x vagrant -a 10.33.33.50<\/pre>\n\n\n\n<p>The \u2018name:*\u2019 is query, \u2018sudo chef-client\u2019 which we must execute on nodes found by this query. For example, show uptime only nodes with role web:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife ssh \"role:web\" \"uptime\" -x vagrant<\/pre>\n\n\n\n<p>To upgrade all nodes:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ knife ssh \"name:*\" \"sudo aptitude upgrade -y\"<\/pre>\n\n\n\n<p>Sometimes, however, you may want to update you servers automatically. For example, you&#8217;ve just updated new cookbooks, roles and nodes, and all nodes should automatically fetch new cookbooks and execute it, if it&#8217;s updated (and for you not critical update speed). We can use special cookbook \u201cchef-client\u201d. It allows using bluepill, daemontools, runit or cron to configure your systems to run Chef Client as a service. Example of attributes for nodes:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n  \"name\": \"chef-client\",\n  \"chef_type\": \"role\",\n  \"json_class\": \"Chef::Role\",\n  \"default_attributes\": {\n    \"chef_client\": {\n      \"interval\": 1800,\n      \"init_style\": \"upstart\",\n      \"config\": {\n        \"client_fork\": true\n      }\n    }\n  },\n  \"description\": \"The base role for systems that have chef client\",\n  \"run_list\": [\n    \"recipe[chef-client]\",\n    \"recipe[chef-client::config]\"\n  ]\n}<\/pre>\n\n\n\n<p>So, you can add this role for each node. It will check chef server for updates each 1800 sec (30 min).<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Chef Solo. Part 3<\/h1>\n\n\n\n<p>We continue talking about Chef Solo. All the example codes mentioned here, you can find at: <a href=\"https:\/\/github.com\/le0pard\/chef-solo-example\/tree\/5.0\">github.com\/le0pard\/chef-solo-example\/tree\/5.0<\/a>.<\/p>\n\n\n\n<p>Previously we&#8217;ve learned about Chef cookbooks. Below we will learn what is Ohai and how to write an Ohai plugin.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Ohai<\/h2>\n\n\n\n<p>Ohai detects data about your operating system. It can be used standalone, but its primary purpose is to provide node data to Chef.<\/p>\n\n\n\n<p>When invoked, it collects detailed, extensible information about the machine it&#8217;s running on, including Chef configuration, hostname, FQDN, networking, memory, CPU, platform, and kernel data.<\/p>\n\n\n\n<p>When Chef configures the node object during each Chef run, these attributes are used by the chef-client to ensure that certain properties remain unchanged. These properties are also referred to as automatic attributes. In our case (in Chef Solo), these attributes are available in the node object. For example:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">node['platform'] # The platform on which a node is running. This attribute helps determine which providers will be used.\nnode['platform_version']  # The version of the platform. This attribute helps determine which providers will be used.\nnode['hostname']  # The host name for the node.\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Ohai plugin<\/h2>\n\n\n\n<p>In our cookbook &#8220;tomatoes&#8221; we already have the node.js recipe. Let&#8217;s create the ohai plugin, which will provide us with information about node.js that is already installed in the system node.js. We will use this information to check if we need to install node.js on the server.<\/p>\n\n\n\n<p>First of all, you need create new recipe &#8220;ohai_plugin.rb&#8221; in &#8220;tomatoes&#8221; with the following content:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">template \"#{node['ohai']['plugin_path']}\/system_node_js.rb\" do\n  source \"plugins\/system_node_js.rb.erb\"\n  owner \"root\"\n  group \"root\"\n  mode 00755\n  variables(\n    :node_js_bin => \"#{node['nodejs']['dir']}\/bin\/node\"\n  )\nend\n\ninclude_recipe \"ohai\"\n<\/pre>\n\n\n\n<p>This recipe will generate the ohai plugin from template &#8220;system\\_node\\_js.rb&#8221;. Next, we should create the following template in the folder &#8220;tomatoes\/templates\/default\/plugins&#8221;:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">provides \"system_node_js\"\nprovides \"system_node_js\/version\"\n\nsystem_node_js Mash.new unless system_node_js\nsystem_node_js[:version] = nil unless system_node_js[:version]\n\nstatus, stdout, stderr = run_command(:no_status_check => true, :command => \"&lt;%= @node_js_bin %> --version\")\n\nsystem_node_js[:version] = stdout[1..-1] if 0 == status\n<\/pre>\n\n\n\n<p>In the first two lines we set automatic attributes by method &#8220;provides&#8221;, which will provide us with this plugin.<\/p>\n\n\n\n<p>Most of the information we want to lookup would be nested in some way, and ohai tends to do this by storing the data in a Mash. This can be done by creating a new mash and setting the attribute to it. We did this with &#8220;system\\_node\\_js&#8221;.<\/p>\n\n\n\n<p>In the end of code, plugin sets the version of node.js, if node.js is installed on the server. That&#8217;s it!<\/p>\n\n\n\n<p>Next, let&#8217;s try this plugin by adding the following content to the &#8220;default.rb&#8221; recipe:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">include_recipe \"tomatoes::ohai_plugin\"\n# remove this in your prod recipe\nputs \"Node version: #{node.system_node_js.version}\" if node['system_node_js']\n<\/pre>\n\n\n\n<p>Now test it by running the command &#8220;vagrant provision&#8221;. When you start it for the first time, you will not see anything, as the plugin will be delivered later when the chef-client launched. But the second time, you should see a picture similar to the one below in the log:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[Sat, 26 Jan 2013 18:42:16 +0000] INFO: ohai plugins will be at: \/etc\/chef\/ohai_plugins\n[Sat, 26 Jan 2013 18:42:16 +0000] INFO: Processing remote_directory[\/etc\/chef\/ohai_plugins] action create (ohai::default line 27)\n[Sat, 26 Jan 2013 18:42:16 +0000] INFO: Processing cookbook_file[\/etc\/chef\/ohai_plugins\/README] action create (dynamically defined)\n[Sat, 26 Jan 2013 18:42:16 +0000] INFO: Processing ohai[custom_plugins] action reload (ohai::default line 42)\n[Sat, 26 Jan 2013 18:42:16 +0000] INFO: ohai[custom_plugins] reloaded\nNode version: 0.8.6\n[Sat, 26 Jan 2013 18:42:17 +0000] INFO: Processing ohai[reload_nginx] action nothing (nginx::ohai_plugin line 22)\n[Sat, 26 Jan 2013 18:42:17 +0000] INFO: Processing template[\/etc\/chef\/ohai_plugins\/nginx.rb] action create (nginx::ohai_plugin line 27)\n[Sat, 26 Jan 2013 18:42:17 +0000] INFO: Processing remote_directory[\/etc\/chef\/ohai_plugins] action nothing (ohai::default line 27)\n[Sat, 26 Jan 2013 18:42:17 +0000] INFO: Processing ohai[custom_plugins] action nothing (ohai::default line 42)\n<\/pre>\n\n\n\n<p>In this case we can change our node.js recipe a little:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">execute \"nodejs make install\" do\n  environment({\"PATH\" => \"\/usr\/local\/bin:\/usr\/bin:\/bin:$PATH\"})\n  command \"make install\"\n  cwd \"\/usr\/local\/src\/node-v#{node['nodejs']['version']}\"\n  not_if {node['system_node_js'] &amp;&amp; node['system_node_js']['version'] == node['nodejs']['version'] }\nend\n<\/pre>\n\n\n\n<p>Let&#8217;s try to change the node.js version in the role &#8220;web.json&#8221;:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\"nodejs\": {\n  \"version\": \"0.8.18\",\n  \"checksum\": \"e3bc9b64f60f76a32b7d9b35bf86b5d1b8166717\"\n}\n<\/pre>\n\n\n\n<p>And restart &#8220;vagrant provision&#8221;:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[Sat, 26 Jan 2013 19:09:32 +0000] INFO: Processing remote_file[\/usr\/local\/src\/node-v0.8.18.tar.gz] action create_if_missing (tomatoes::node_js line 16)\n[Sat, 26 Jan 2013 19:10:17 +0000] INFO: remote_file[\/usr\/local\/src\/node-v0.8.18.tar.gz] updated\n[Sat, 26 Jan 2013 19:10:17 +0000] INFO: remote_file[\/usr\/local\/src\/node-v0.8.18.tar.gz] mode changed to 644\n[Sat, 26 Jan 2013 19:10:17 +0000] INFO: Processing execute[tar --no-same-owner -zxf node-v0.8.18.tar.gz] action run (tomatoes::node_js line 25)\n[Sat, 26 Jan 2013 19:10:18 +0000] INFO: execute[tar --no-same-owner -zxf node-v0.8.18.tar.gz] ran successfully\n[Sat, 26 Jan 2013 19:10:18 +0000] INFO: Processing bash[compile node.js] action run (tomatoes::node_js line 30)\n[Sat, 26 Jan 2013 19:18:16 +0000] INFO: bash[compile node.js] ran successfully\n[Sat, 26 Jan 2013 19:18:16 +0000] INFO: Processing execute[nodejs make install] action run (tomatoes::node_js line 40)\n[Sat, 26 Jan 2013 19:18:19 +0000] INFO: execute[nodejs make install] ran successfully\n<\/pre>\n\n\n\n<p>And after some time, the server will have a new node.js:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">$ vagrant ssh\nWelcome to Ubuntu 12.04.1 LTS (GNU\/Linux 3.2.0-23-generic x86_64)\n\n * Documentation:  https:\/\/help.ubuntu.com\/\nWelcome to your Vagrant-built virtual machine.\nLast login: Sat Jan 26 19:19:00 2013 from 10.0.2.2\nvagrant@precise64:~$ node -v\nv0.8.18\n<\/pre>\n\n\n\n<p>And on the next launch of chef solo you should see the new version of node.js:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[Sat, 26 Jan 2013 19:20:22 +0000] INFO: Processing remote_directory[\/etc\/chef\/ohai_plugins] action create (ohai::default line 27)\n[Sat, 26 Jan 2013 19:20:22 +0000] INFO: Processing cookbook_file[\/etc\/chef\/ohai_plugins\/README] action create (dynamically defined)\n[Sat, 26 Jan 2013 19:20:22 +0000] INFO: Processing ohai[custom_plugins] action reload (ohai::default line 42)\n[Sat, 26 Jan 2013 19:20:22 +0000] INFO: ohai[custom_plugins] reloaded\nNode version: 0.8.18\n[Sat, 26 Jan 2013 19:20:23 +0000] INFO: Processing ohai[reload_nginx] action nothing (nginx::ohai_plugin line 22)\n[Sat, 26 Jan 2013 19:20:23 +0000] INFO: Processing template[\/etc\/chef\/ohai_plugins\/nginx.rb] action create (nginx::ohai_plugin line 27)\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n\n\n\n<p>We have learned what Chef Server is and how to setup it up. We have also learned about Ohai and how to write an Ohai plugin. I haven&#8217;t covered many things related to Chef server with this article (i.e.advanced usage, knife-ec2, opsworks &#8211; based on chef solo, etc.), but I this should be enough to start working with it.<\/p>\n\n\n\n<p>You can find all the code examples here:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/github.com\/le0pard\/chef-server-example\/tree\/1.0\">github.com\/le0pard\/chef-server-example\/tree\/1.0<\/a><\/li><li><a href=\"http:\/github.com\/le0pard\/chef-server-example\/tree\/2.0\" target=\"_blank\" rel=\"noopener noreferrer\">github.com\/le0pard\/chef-server-example\/tree\/2.0<\/a><\/li><li><a href=\"https:\/\/github.com\/le0pard\/chef-solo-example\/tree\/5.0\">github.com\/le0pard\/chef-solo-example\/tree\/5.0<\/a><\/li><\/ul>\n\n\n\n<p>This post is <a href=\"http:\/\/leopard.in.ua\/2013\/02\/17\/chef-server-getting-started-part-1\/\">crossposting from my blog<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello my dear friends. Today we will talk about a Chef Server. In this article we will learn what is the Chef Server and how to setup it up. Before reading this article, it&#8217;s better to read my articles about Chef Solo. Here I&#8217;ll explain only those things that hasn&#8217;t already been covered in those&#8230;<\/p>\n","protected":false},"author":17,"featured_media":4176,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[],"coauthors":["Alexey Vasiliev"],"class_list":["post-4292","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development"],"acf":[],"aioseo_notices":[],"categories_data":[{"name":"Engineering","link":"https:\/\/railsware.com\/blog?category=development"}],"post_thumbnails":"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2013\/02\/chef_server_versions.png","amp_enabled":true,"_links":{"self":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/4292","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/users\/17"}],"replies":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/comments?post=4292"}],"version-history":[{"count":24,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/4292\/revisions"}],"predecessor-version":[{"id":14067,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/4292\/revisions\/14067"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media\/4176"}],"wp:attachment":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media?parent=4292"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/categories?post=4292"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/tags?post=4292"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/coauthors?post=4292"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}