Chef-zero Is Broken in Ubuntu 14.04
I was playing a bit with applying chef cookbooks locally, without a chef server and found that version of Chef from Ubuntu repo is way too low for normal operation in local mode.
# apt-cache policy chef
chef:
Installed: 11.8.2-2
date = ""
Version table:
*** 11.8.2-2 0
500 http://us.archive.ubuntu.com/ubuntu/ trusty/universe amd64 Packages
There is a bug resolved in recent versions of Chef related to the way in which chef-zero parses json files. If there is metadata.json file instead of metadata.rb in a cookbook chef-zero fails to parse this file expecting just a filename instead of full file content.
For example I’ve got the following error trying to apply one of my cookbooks that depends on yum cookbook:
================================================================================
Error Resolving Cookbooks for Run List:
================================================================================
Unknown Server Error:
---------------------
The server had a fatal error attempting to load the node data.
Server Response:
----------------
Exception raised! #<Errno::ENAMETOOLONG: File name too long - {
"name": "yum",
"version": "3.5.3",
"description": "Configures various yum components on Red Hat-like systems",
"long_description": "",
"maintainer": "Chef",
"maintainer_email": "[email protected]",
"license": "Apache 2.0",
"platforms": {
"redhat": ">= 0.0.0",
"centos": ">= 0.0.0",
"scientific": ">= 0.0.0",
"amazon": ">= 0.0.0",
"fedora": ">= 0.0.0"
My first idea was to simply install needed version of Chef using install script during initial node configuration.
# curl -L https://www.chef.io/chef/install.sh | sudo bash -s -- -v 11.18.6-1
My second idea was to simply add omnibus_updater cookbook to the base role:
# cat roles/base.json
{
"name": "base",
"override_attributes": {
"omnibus_updater": {
"version": "11.18.6-1"
}
},
"run_list": [
"recipe[omnibus_updater]"
]
}
Unfortunately this approach does not work very well - first you need to get omnibus_updater cookbook to the server. It’s not a big deal but adds an additional step to whole process. Other problem is that Chef client is unable to configure node within one run: during the initial run you have to execute chef-client on the node with only omnibus_updater cookbook in the run list. If you have other cookbooks in run list chef-client will fail due to json parsing bug described above. Even if everything works well omnibus_updater kills chef-client immediately after performing upgrade which makes lot of sense but once again prevents chef-client from configuring a node within one run:
* ruby_block[omnibus chef killer] action create
================================================================================
Error executing action `create` on resource 'ruby_block[omnibus chef killer]'
================================================================================
RuntimeError
------------
New omnibus chef version installed. Killing Chef run!
so I decided to fallback to my first decision with installing correct version of chef-client using installer script. Having omnibus_updater in a base role run list is still a good idea - we’re locking chef-client to the particular version this way.
Another local-cookbook-installation gotcha.
If you’re trying to install cookbooks into the directory one level above your cookbook using –path option you’ll get an ugly stack trace:
root@ubuntu1404:~/chef-zero/cookbooks/openvpn# berks install --path /root/chef-zero/cookbooks
Using openvpn (2.1.1)
Using apt (2.7.0)
Using yum (3.5.3)
Using yum-epel (0.6.0)
/var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/locations/path_location.rb:70:in `expand_path': No such file or directory - getcwd (Errno::ENOENT)
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/locations/path_location.rb:70:in `expand_path'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/locations/path_location.rb:70:in `relative_path'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/cookbook_source.rb:206:in `block in to_hash'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/cookbook_source.rb:196:in `tap'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/cookbook_source.rb:196:in `to_hash'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/cookbook_source.rb:218:in `to_json'
from /var/lib/gems/1.9.1/gems/json-1.7.7/lib/json/common.rb:285:in `generate'
from /var/lib/gems/1.9.1/gems/json-1.7.7/lib/json/common.rb:285:in `pretty_generate'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/lockfile.rb:150:in `to_json'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/lockfile.rb:177:in `block in save'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/lockfile.rb:176:in `open'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/lockfile.rb:176:in `save'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/lockfile.rb:90:in `update'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/berksfile.rb:426:in `install'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/cli.rb:153:in `install'
from /usr/lib/ruby/vendor_ruby/thor/command.rb:27:in `run'
from /usr/lib/ruby/vendor_ruby/thor/invocation.rb:121:in `invoke_command'
from /usr/lib/ruby/vendor_ruby/thor.rb:363:in `dispatch'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/lib/berkshelf/cli.rb:21:in `dispatch'
from /usr/lib/ruby/vendor_ruby/thor/base.rb:440:in `start'
from /var/lib/gems/1.9.1/gems/berkshelf-2.0.18/bin/berks:6:in `<top (required)>'
from /usr/local/bin/berks:23:in `load'
from /usr/local/bin/berks:23:in `<main>'
The point is that berkshelf in this case actually recreates directory you’ve launched it from. The correct way is to install cookbooks to some temporary directory:
root@ubuntu1404:~/chef-zero/cookbooks/openvpn# berks install --path ./tmp
Using openvpn (2.1.1) from metadata
Using apt (2.7.0)
Using yum (3.5.3)
Using yum-epel (0.6.0)
and then move them to your cookbook_path directory.