confused with berkshelf, chef and vagrant - vagrant

I've took a look on BerkShelf documentation. I've been able to figure out it stands for managing cookbook dependencies. So, guess I'd like to build a machine with java. I've first generated my custom cookbook:
chef generate cookbook custom-java
My Berksfile is:
source 'https://supermarket.chef.io'
metadata
cookbook 'java'
and my metadata.rb is:
name 'custom-java'
...
version '0.1.0'
After that, I've simply run berks install, so all dependencies have been resolved and located under ~\.berkshelf\cookbooks.
Nevertheless, I don't quite figure out how to use my custom-java into my vagrant configuration. What do I need to do in order for vagrant to provistion this cookbook into my machines?
My vagrant structure is:
VagrantFile
├───chef
│ ├───cookbooks
│ │ ├───(((1))) <<<<<<<<<<<<<<<<<<<<<<
│ ├───roles
│ │ ├───java-dev-workstation.rb
Vagrantfile content is:
Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
config.vm.provision "chef_solo" do |chef|
chef.roles_path = "chef/roles"
chef.cookbooks_path = "chef/cookbooks"
chef.add_role "java-dev-workstation"
end
end
And java-dev-workstation.rb:
name "java-dev-workstation"
default_attributes(
# Because it's Oracle, we need to agree to the terms and conditions.
:custom-java => { >>>>>>>>> (((2)))
:install_flavor => 'oracle',
:jdk_version => '8',
:accept_license_agreement => true,
:oracle => { "accept_oracle_download_terms" => true }
}
)
run_list(
"recipe[java]"
)
I'm using Chef 12.18.31.
On (((1))): Do I need to "import" my custom-java cookbook, how? Where is it located?
On (((2))): How should I configure java?
EDIT
I've set chef.cookbooks_path:
config.vm.provision "chef_solo" do |chef|
chef.roles_path = "chef/roles"
chef.cookbooks_path = 'D:\projects\living\vagrant\production\berk\custom-java'
chef.add_role "java-dev-workstation"
end
EDIT2
Nevertheless, custom-java dependencies are not resolved now:
================================================================================
Error Resolving Cookbooks for Run List:
================================================================================
Missing Cookbooks:
------------------
No such cookbook: yum
Expanded Run List:
------------------
* custom-java
Platform:
---------
x86_64-linux
My metadata.rb content is:
name 'berk'
...
version '0.1.0'
supports 'centos'
depends 'yum'
Currently, all dependencies are located in ~/.berkshelf/cookbooks. It seems shef-solo is not looking for in it...

You did take it backward for a wrapper cookbook pattern, your custom_java should depends on java and change its default behavior (overriding node attributes).
Your custom-java metadata.rb should contain a line like this, what is in the berksfile will never be interpreted by the chef-client run, it's an outside dependency resolver to create coherent bundles.
depends 'java', '~> 1.47'
And the default.rb a line
include_recipe 'java'
Then your Berksfile can omit the cookbook line (unless you're pulling a version elsewhere than the source at top)
Next your role should use custom-java as recipe and not java, then the chef-client run (the vagrant part before edit sounds ok and should pull both cookbooks) will compute attributes from the java coobooks, overwrite those defined in custom-java and you should end up with the desired behavior.
Alternatively, you can just set the runlist to custom-java and avoid the role altogether, that will works.
I highly recommend you to go through all the tutorials on https://learn.chef.io to get a better overview.

Related

Understanding Chef Environment Attributes

Background
I am trying to understand how to correctly work with environment attributes in recipes. Note: I understand that my approach may not be Chef's best practices; however, my goal is to understand data flow here, not to necessarily use my approach in a production application.
Some details:
I am using Vagrant and Chef -- specifically, the chef-zero
provisioner (Thus I must use ruby files for my environments rather
than JSON due to a chef-vagrant limitation).
Here is my directory structure:
├── environments
├── vm.rb
├── roles
├── base.json
├── cookbooks
├── init
├── recipes
├── default.rb
├── Vagrantfile
Here are my files
Environment: vm.rb
name "vm"
description "Configuration file for the Kukla Demo VM"
default_attributes(
custom_demo: {
title: 'My demo title',
description: 'My demo description'
))
Role: base.json
{
"name": "base",
"description": "Base VM configuration",
"chef_type": "role",
"json_class": "Chef::Role",
"default_attributes": {},
"override_attributes": {},
"run_list": ["recipe[init::default]"]
}
Recipe: default.rb
#
# Cookbook:: init
# Recipe:: default
#
# Copyright:: 2020, The Authors, All Rights Reserved.
print 'I am here!'
print node[:custom_demo]
Chef provisioner in the Vagrantfile
...
chef.nodes_path = 'nodes/'
chef.environments_path = 'environments/'
chef.roles_path = 'roles/'
chef.cookbooks_path = 'cookbooks/'
# Roles
chef.add_role "base"
...
Expected Behavior
When I run the provisioner, I expect to see the custom_demo hash printed in the chef run log. Something like:
...
==> Machine: Synchronizing Cookbooks:
==> Machine: [2020-02-07T20:37:15+00:00] INFO: Storing updated cookbooks/init/recipes/default.rb in the cache.
==> Machine:
==> Machine: - init (0.1.0)
==> Machine: Installing Cookbook Gems:
==> Machine: Compiling Cookbooks...
==> Machine: I am here! custom_demo => { :title => 'My demo title', :description => 'My demo description' }
==> Machine: Converging 0 resources
==> Machine: [2020-02-07T20:37:15+00:00] INFO: Chef Infra Client Run complete in 0.118042019 seconds
...
Actual behavior
Instead, I get:
...
==> Machine: Synchronizing Cookbooks:
==> Machine: [2020-02-07T20:37:15+00:00] INFO: Storing updated cookbooks/init/recipes/default.rb in the cache.
==> Machine:
==> Machine: - init (0.1.0)
==> Machine: Installing Cookbook Gems:
==> Machine: Compiling Cookbooks...
==> Machine: I am here!
==> Machine: Converging 0 resources
==> Machine: [2020-02-07T20:37:15+00:00] INFO: Chef Infra Client Run complete in 0.118042019 seconds
...
My Question(s):
Based on the result, I'm left with the following questions:
Is my understanding of environment attributes (and therefore) my expectation correct?
If not, what am I missing? Can environment attributes be used in this fashion?
What is the proper way to debug whether an environment is being used by chef or not?
What is the proper way to reference environment attributes in a recipe so that I achieve the expected result?
You are doing everything right and your expectations are correct. The only thing, you are missing, is that you do not assign the environment to the vm. For that you need to add a line in your Vagrantfile:
...
chef.nodes_path = 'nodes/'
chef.environments_path = 'environments/'
chef.roles_path = 'roles/'
chef.cookbooks_path = 'cookbooks/'
chef.environment = 'vm' # the added line
# Roles
chef.add_role "base"
...
To understand, if the node has the right environment set, you can just print out in your recipe:
p node.chef_environment
# or
p node.environment
Concerning your last question, you actually cannot reference from a recipe environment attributes. Chef collects attributes from different sources (recipe, environment, node etc.) and combines them into 1 attribute hash using precedence, so in the end you can only reference the attribute with highest precedence or with some particular precedence, but not by the attribute source (environment, node or recipe).
node[:custom_demo] # highest precedence
node.default[:custom_demo] # default precedence, ignoring override and normal

Chef::Exceptions::CookbookNotFound: Cookbook sudo not found and Chef-Solo “undefined method `[]' for nil:NilClass”

I'm trying to make a cookbook that has some dependencies, but it doesn't work
/recipe
ls
default.rb
Recipe:
include_recipe 'sudo::default'
include_recipe 'user'
def will_create_user?(username, user)
return false if node['etc']['passwd'].key?(username)
return true if user['action'] == 'create' || !user.key?('action')
false
end
node['authorization']['sudo']['groups'].each do |group|
group group
end
node['vms']['users'].each do |username, user|
send_notification = will_create_user? username, user
user_account username do
comment user['comment'] if user['comment']
ssh_keys user['ssh_keys']
groups user['groups'] if user['groups']
if send_notification
notifies :run, "execute[reset_password_#{username}]", :delayed
end
end
execute "reset_password_#{username}" do
command "passwd -d #{username} && chage -d 0 #{username}"
action :nothing
end
end
Metadata.rb
...
version '0.1.0'
chef_version '>= 14.0'
depends "sudo"
depends "user"
Berksfile.lock
DEPENDENCIES
vms-users
path: .
metadata: true
GRAPH
sudo (5.4.5)
user (0.7.0)
vms-users (0.1.0)
sudo (>= 0.0.0)
user (>= 0.0.0)
Attributes/default.rb
{
"vms": {
"users": {
'magrini' => {
'comment' => 'Bruna Magrini',
'groups' => ['sysadmin'],
'ssh_keys' => ['chave ssh'],
},
}
}
}
I'm executing using chef-client --local-mode default.rb
Error: Chef::Exceptions::CookbookNotFound: Cookbook sudo not found
Recipe `sudo::default` is not in the run_list, and cookbook 'sudo'
is not a dependency of any cookbook in the run_list. To load this recipe,
first add a dependency on cookbook 'sudo' in the cookbook you're
including it from in that cookbook's metadata.
Running handlers:
[2019-12-19T20:42:12+00:00] ERROR: Running exception handlers
Running handlers complete
[2019-12-19T20:42:12+00:00] ERROR: Exception handlers complete
Chef Infra Client failed. 0 resources updated in 01 seconds
[2019-12-19T20:42:12+00:00] FATAL: Stacktrace dumped to /home/chef-repo/.chef/local-mode-cache/cache/chef-stacktrace.out
[2019-12-19T20:42:12+00:00] FATAL: Please provide the contents of the stacktrace.out file if you file a bug report
[2019-12-19T20:42:12+00:00] FATAL: Chef::Exceptions::CookbookNotFound: Cookbook sudo not found. If you're loading sudo from another cookbook, make sure you configure the dependency in your metadata
i have a feeling that you are confusing something, since the title of your question mentions chef-solo when you are really using chef-zero (--local-mode).
you should definitely favor chef-zero over chef-solo (but i won't get into the reasons why).
in both cases (using chef-zero or chef-solo), you will have to download all the cookbooks and make verify chef-client knows where are the cookbooks located.
if you ase using chef-zero, here are some references:
Local mode does not require a configuration file, instead it will look for a directory named /cookbooks and will set chef_repo_path to be just above that. (Local mode will honor the settings in a configuration file, if desired.) If the client.rb file is not found and no configuration file is specified, local mode will search for a config.rb file.
client.rb settings:
chef_repo_path: The path to the chef-repo containing cookbooks and other files, such as environments or data bags, when running Chef Infra Client in local mode.
cookbook_path: The sub-directory for Chef Infra Client cookbooks. This value can be a string or an array of file system locations, processed in the specified order. The last cookbook is considered to override local modifications.
since i see that you are using berkshelf, you can use vendor sub-command to download all the cookbooks dependencies and place them in the same directory. then, have a custom configuration for chef-client, that sets the value of cookbook_path to the same directory which you used in conjunction with berks vendor, and finally execute chef-client.

Chef metadata.rb dependency needs to depend on itself

I am getting a foodcritic error when I try to include a recipie within the default.rb for the apache cookbook lesson:
#
# Cookbook:: apache
# Recipe:: default
#
# Copyright:: 2017, The Authors, All Rights Reserved.
# Install apached package
package 'apache2' do
package_name 'httpd'
action :install
end
service 'apache2' do
service_name 'httpd'
action [:start, :enable]
end
include_recipe 'apache::websites'
websites.rb
file 'default www' do
path '/var/ww/html/index.html'
content 'Hello world!'
end
When I run foodcritic on default.rb
FC007: Ensure recipe dependencies are reflected in cookbook metadata:
default.rb:17
When I follow the recomendation and add the dependency in the metadata.rb and run knife cookbook upload apache I get this:
ERROR: RuntimeError: Cookbook depends on itself in cookbook apache, please
remove the this unnecessary self-dependency
Below is my metadeta.rb
name 'apache'
maintainer 'xxxxx'
maintainer_email 'xxxxx'
license 'All Rights Reserved'
description 'Installs/Configures apache'
long_description 'Installs/Configures apache'
version '0.1.1'
chef_version '>= 12.1' if respond_to?(:chef_version)
depends 'apache'
#The `issues_url` points to the location where issues for this cookbook are
# tracked. A `View Issues` link will be displayed on this cookbook's page
when
# uploaded to a Supermarket.
#
# issues_url 'https://github.com/<insert_org_here>/apache/issues'
# The `source_url` points to the development repository for this cookbook.
A
# `View Source` link will be displayed on this cookbook's page when uploaded
to
# a Supermarket.
#
# source_url 'https://github.com/<insert_org_here>/apache'
New to chef and ruby, first question on Stack Overflow.
Am I adding the dependency wrong?
Does anything jump out that would cause this issue?
The FC007 activation is wrong. Are you sure you're running foodcritic correctly? Just run foodcritic . on the base of the cookbook folder (i.e. the same place as the metadata.rb is). That should detect the name of the cookbook and not flag the include.

what is the proper way to override chef recipe attributes?

I am adding this Solr Chef recipe an existing vagrant box . I want to override the version attribute here . Do I override these variables in one of the json files or it has to be overridden in the recipe attributes file itself?
For your use case it's ok to override it in Vagrantfile directly. Check more info about chef solo and vagrant here.
tldr;
Just provide chef.json option with attributes in your Vagrantfile like:
Vagrant.configure("2") do |config|
config.vm.provision "chef_solo" do |chef|
# ...
chef.json = {
"solr" => {
"version" => "4.6.1"
}
}
end
end
In general practise it's common to set attributes inside roles, or by creating wrapper cookbooks around community ones, and with that there is no need for changing original source code.

vagrantfile cookbook path

I want to set the cookbook path to a certain place, so that I don't need to
modify the Vagrantfile everytime(after vagrant init).
I find Vagrantfile load several places, so I decide to set my cookbook path info
in ~/.vagrant.d/Vagrantfile,(this file is the 3rd of Vagrantfile Load Order) like:
...
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = ["D:/lib/chef/cookbooks"]
chef.add_recipe "dev::default"
end
...
but when I make a new vm, and modify Vagrantfile(this file is the 4th of Vagrantfile Load Order):
...
config.vm.provision :chef_solo do |chef|
chef.add_recipe "torch"
end
...
error:
[2013-02-28T03:23:36+00:00] ERROR: Running exception handlers
[2013-02-28T03:23:36+00:00] ERROR: Exception handlers complete
[2013-02-28T03:23:36+00:00] FATAL: Stacktrace dumped to /tmp/vagrant-chef-1/chef-stacktrace.out
[2013-02-28T03:23:36+00:00] FATAL: Chef::Exceptions::CookbookNotFound: Cookbook torch not found. If
you're loading torch from another cookbook, make sure you configure the dependency in your metadata
Chef never successfully completed! Any errors should be visible in the
output above. Please fix your recipes so that they properly complete.
but I am sure the specific cookbook is under my cookbook path.
Try the following steps:
- Create a folder cookbooks in the vagrantfile's directory
- checkout the cookbooks to this directory
- add the following to your vagrantfile
chef.cookbooks_path = ["cookbooks"]
hope to have helped

Resources