Search code examples
jsonvagrantchef-infraprovisioningchef-solo

Vagrant chef_solo provisioner raising NoMethodError - undefined method 'default_attributes' for #<Hash: ....>


I'm trying to provision a VM using Vagrant in order to test a cookbook (chef-mycookbooks-test) I created. It depends on data_bags in chef-repo. I can't find any answers as to why this isn't working.

The VM starts up fine but it throws an exception when it runs chef-solo:

INFO: Setting the run_list to ["recipe[mycookbooks-test::default]"] from CLI options
DEBUG: Applying attributes from json file
Error expanding the run_list:
NoMethodError: undefined method `default_attributes' for #<Hash:0x0000000384e3a7>

I don't know if it matters, but the environment I'm using (local.json) has default_attributes defined. When I log on to the VM and look at solo.rb I see some of the data from my provisioning (eg. environment "local") but not all of it (eg. no role set, default cookbook_path, role_path is []). I get the same error when I try to run chef-solo from the VM manually.

Directory structure on host machine:

.
├── chef-repo
│   ├── data_bags
│   │   ├── groups
│   │   │   └── test.json
│   │   └── users
│   │       └── test.json
│   ├── environments
│   │   └── local.json
│   └── roles
│       └── test_server.json   
└── chef-mycookbooks-test
    ├── Berksfile
    ├── Berksfile.lock
    ├── Vagrantfile
    ├── files
    │   └── default
    │       └── sudoers.test
    ├── metadata.rb
    └── recipes
        └── default.rb

Vagrantfile:

Vagrant.configure("2") do |config|
    config.omnibus.chef_version = :latest
    config.vm.box = "hansode/centos-6.3-x86_64"
    config.berkshelf.enabled = true

    config.vm.provision :chef_solo do |chef|
        chef.cookbooks_path = ".."
        chef.data_bags_path = "../chef-repo/data_bags"
        chef.environments_path = "../chef-repo/environments"
        chef.environment = "local"
        chef.roles_path = "../chef-repo/roles"
        chef.add_role("test_server")
        chef.run_list = [
            "recipe[mycookbooks-test::default]"
        ]
    end
end

Interestingly, if I remove the line defining chef.environment, the run_list expands just fine to [mycookbooks-test::default], but chef-solo fails later when it tries to run some of the dependencies, for which the environment data is needed.

Any help at all would be greatly appreciated. I am completely out of ideas.

Note: I cleaned up some of the unnecessary things in the directory tree (eg. README.md) and Vagrantfile (eg. debug level) for clarity.


Solution

  • Things like cookbooks_path are relative to the host machine, not the guest. Are you sure you really have your cookbooks at /? Chances are you are loading a bunch of invalid data and Chef is choking on it. You can also up your logging level via chef.log_level = :debug.