I can't provision, i search in the other threads but no one is useful!
I'm using Vagrant with Puppet both of them at the latest version, my project structure is:
prova
|
|__Vagrantfile
|
|__puppet
|__manifests
| |__ubonda.pp
|
|__modules
|
|__apache
|
|__manifests
|
|__apache.pp
My VagrantFile is:
Vagrant.configure("2") do |config|
config.vm.define "ubonda" do |vm0|
vm0.vm.hostname = "ubonda"
vm0.vm.box = "hashicorp/precise64"
vm0.vm.provision "puppet" do |puppet|
puppet.manifests_path = 'puppet/manifests'
puppet.module_path = 'puppet/modules'
puppet.manifest_file = "ubonda.pp"
end
end
end
My ubonda.pp file is:
# default path
Exec {
path => ["/usr/bin", "/bin", "/usr/sbin", "/sbin", "/usr/local/bin", "/usr/local/sbin"]
}
include apache
My apache.pp file is:
class apache {
# install apache
package { "apache2":
ensure => present,
require => Exec["apt-get update"]
}
# ensures that mode_rewrite is loaded and modifies the default configuration file
file { "/etc/apache2/mods-enabled/rewrite.load":
ensure => link,
target => "/etc/apache2/mods-available/rewrite.load",
require => Package["apache2"]
}
# create directory
file {"/etc/apache2/sites-enabled":
ensure => directory,
recurse => true,
purge => true,
force => true,
before => File["/etc/apache2/sites-enabled/vagrant_webroot"],
require => Package["apache2"],...
}
}
If i launch vagrant provision i obtain :
==> ubonda: Running provisioner: puppet...
==> ubonda: Running Puppet with ubonda.pp...
==> ubonda: warning: Could not retrieve fact fqdn
==> ubonda: Could not find class apache for ubonda at /tmp/vagrant-puppet/manifests-846018e2aa141a5eb79a64b4015fc5f3/ubonda.pp:6 on node ubonda
I search in the tmp/manifests folder of the ubonda vm and inside there is only the ubonda.pp while in the tmp/modules there is the apache but the two are not connected, so I tried to copy inside the manifest but nothing has changed, how can I do?
The solution is very simple but I leave the question for posterity.
The file containing the puppet specifications must be named as init.pp for it to be correctly recognized
Related
I have a Vagrantfile in which I am provisioning different Vm's by looping through a json file. eg.
cluster_config.each do |cluster|
cluster_name = cluster[0] # name of node
nodes_config = (JSON.parse(File.read("test_data_bags/myapp/_default.json")))['clusters'][cluster_name]['nodes']
nodes_config.each do |node|
config.vm.define node_name do |nodeconfig|
processes = node_values['processes']
processes.each do |process|
nodeconfig.vm.provision :chef_solo do |chef|
chef.data_bags_path = 'test_data_bags'
chef.run_list = run_list
chef.roles_path = "roles"
"myapp" => {
"cluster_name" => cluster_name,
"role" => node_role
},
}
end
end
end
end
I would like to do the same within kitchen ie. take an array of attributes and foreach array item - run recipe xyz - this is so I can write some tests using test-kitchen , is this possible?
Thanks
There's a few different workarounds to accomplish this, but they are all definitely workarounds. There is an issue that was opened to discuss support of multiple boxes on test-kitchen, and you can go there to read more about why this probably won't be supported any time soon. TL;DR: it's not really a goal of the project.
Workarounds include:
Chef-provisioning can bootstrap more servers from a single provisioned server/test-suite
Kitchen-nodes provisioner can share data about each server to the other test-suites in your setup
A custom Vagrantfile template for test-kitchen
I am trying to setup my Chef-Zero provisioner to execute the run list from a nodes JSON file. This is what my Vagrantfile looks like.
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu-14.04_Base_image"
config.vm.hostname = "app_node"
config.omnibus.chef_version = '12.0.3'
config.vm.provision "chef_zero" do |chef|
chef.cookbooks_path = ["../kitchen/cookbooks", "../kitchen/site-cookbooks"]
chef.roles_path = "../kitchen/roles"
chef.data_bags_path = "../kitchen/data_bags"
chef.nodes_path = "../kitchen/nodes"
chef.node_name = "app_node"
end
end
When I run vagrant up, I get the following output from the chef-zero provisioner.
==> default: Running provisioner: chef_zero...
==> default: Detected Chef (latest) is already installed
Generating chef JSON and uploading...
==> default: Warning: Chef run list is empty. This may not be what you want.
==> default: Running chef-zero...
==> default: stdin: is not a tty
==> default: [2015-01-08T01:19:51+00:00] INFO: Started chef-zero at http://localhost:8889 with repository at /tmp/vagrant-chef/bec99a1a4e96279669bc5bb3140c0f2e, /tmp/vagrant-chef/2cbca02c0b5c49646d765ae1c9c0738f
==> default: One version per cookbook
==> default: data_bags at /tmp/vagrant-chef/72ac2a17a7c339d91d27a954fc49f8c3/data_bags
==> default: nodes at /tmp/vagrant-chef/83a9002a19a985bce4d26b8c9d050540/nodes
==> default: roles at /tmp/vagrant-chef/9cdb44a6dfefce6070b32ff28cb96535/roles
==> default: [2015-01-08T01:19:51+00:00] INFO: Forking chef instance to converge...
==> default: [2015-01-08T01:19:51+00:00] INFO: *** Chef 12.0.3 ***
==> default: [2015-01-08T01:19:51+00:00] INFO: Chef-client pid: 1731
==> default: [2015-01-08T01:19:57+00:00] INFO: Run List is []
==> default: [2015-01-08T01:19:57+00:00] INFO: Run List expands to []
==> default: [2015-01-08T01:19:57+00:00] INFO: Starting Chef Run for jira
==> default: [2015-01-08T01:19:57+00:00] INFO: Running start handlers
==> default: [2015-01-08T01:19:57+00:00] INFO: Start handlers complete.
==> default: [2015-01-08T01:19:59+00:00] INFO: Chef Run complete in 1.831177529 seconds
==> default: [2015-01-08T01:19:59+00:00] INFO: Skipping removal of unused files from the cache
==> default: [2015-01-08T01:19:59+00:00] INFO: Running report handlers
==> default: [2015-01-08T01:19:59+00:00] INFO: Report handlers complete
My question is why was the runlist empty? I specified the nodes directory and the node name in the chef_zero provisioner. The JSON file that specifies the run list for "app_node" exists in the nodes directory and I can see that chef is copying up all the cookbook/nodes/roles files to the server correctly.
I feel like I am missing something here. Any help would be much appreciated. If anything is unclear let me know.
Vagrant's chef_zero provisioner is actually using chef-solo -c solo.rb -j dna.json. Your configuration in nodes is not used other than mounting the directories.
You can workaround this by doing something like this (assumes that nodes/hostname.json is the same name put in config.vm.hostname):
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "chef/centos-6.6"
config.vm.hostname = "foobarhost"
VAGRANT_JSON = JSON.parse(Pathname(__FILE__).dirname.join('../../nodes', "#{config.vm.hostname}.json").read)
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = ["../../cookbooks", "../../site-cookbooks"]
chef.roles_path = "../../roles"
chef.data_bags_path = "../../data_bags"
chef.verbose_logging = true
chef.run_list = VAGRANT_JSON.delete('run_list') if VAGRANT_JSON['run_list']
# Add JSON Attributes
chef.json = VAGRANT_JSON
end
end
Note I just use chef_solo, as what's the point of running chef_zero when it really calls chef_solo.
You aren't specifying a run list. The directory you're talking about is where the node data is stored, not where those JSON files are gotten. Chef has no idea what you are trying to do right now.
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "ubuntu-14.04_Base_image"
config.vm.hostname = "app_node"
config.omnibus.chef_version = '12.0.3'
config.vm.provision "chef_zero" do |chef|
chef.cookbooks_path = ["../kitchen/cookbooks", "../kitchen/site-cookbooks"]
chef.roles_path = "../kitchen/roles"
chef.data_bags_path = "../kitchen/data_bags"
chef.nodes_path = "../kitchen/nodes"
chef.node_name = "app_node"
chef.run_list = []
chef.json = {}
end
end
This should allow you to set your run list and include any JSON attributes you wanted to include with it.
http://docs.vagrantup.com/v2/provisioning/chef_common.html
Has more options you might want to consider if they meet your needs. :-)
Vagrant doesn't consult Chef about existing nodes. In order to use the Chef node file that you wrote, you'll need to tell vagrant about it. In your Vagrantfile, add this line beneath the line chef.node_name = "app_node":
chef.json = JSON.parse(File.read("../kitchen/nodes/app_node.json"))
Once you do that, Chef and Vagrant will both look for the node configuration data in the same place.
I am not sure how to specify a local directory (still researching), but when you specify this in the Vagrantfile in chef.run_list["stuff"], vagrant will put a /tmp/vagrant-chef/dna.json
It also creates a solo.rb, which will insert stuff like node_name, if chef.node_name is created.
I'm attempting to write a ruby script so I can edit the run_lists of a bunch of nodes resulting from a knife search command. I was told to try to use knife exec, but I am yielding the same results as I am just executing the script.
I'm using a OS command dictated by the back ticks. The first command works using the knife search, but when I feed those results into to the following each_line block, it gives me the error in the comments of the script. So, obviously the first part is working, but the second is not even though its setup the exact same way.
#!/usr/bin/env ruby
#
#
#
# %CORPCERT% = C:\Users\myuser\Documents\test\knife.rb
# This contains all the pointers to the client.pem, and other required files.
output = `knife search node "fqdn:node*test*.example.net" -i -c %CORPCERT%`
output.each_line do |result|
#puts result
puts "Adding run_list to #{result}"
`knife node run_list add #{result} "role[role_zabbix_agent_corp_prod]" -c %CORPCERT%`
#puts "#{exitcode}"
end
#C:\U\P028300\Desktop> knife exec apply_run_list.rb -c %CORPCERT%
# => Adding run_list to 8 items found
# => WARNING: No knife configuration file found
# => ERROR: Your private key could not be loaded from C:\chef\client.pem
# => Adding run_list to
# => WARNING: No knife configuration file found
# => ERROR: Your private key could not be loaded from C:\chef\client.pem
# => Adding run_list to nodeSTtestST0.example.net
# => WARNING: No knife configuration file found
# => ERROR: Your private key could not be loaded from C:\chef\client.pem
# => Adding run_list to nodeGWtestST0.example.net
# => WARNING: No knife configuration file found
# => ERROR: Your private key could not be loaded from C:\chef\client.pem
# => Adding run_list to nodeGWtestST1.example.net
# => WARNING: No knife configuration file found
# => ERROR: Your private key could not be loaded from C:\chef\client.pem
# => Adding run_list to nodeGWtestRT1.example.net
# => WARNING: No knife configuration file found
# => ERROR: Your private key could not be loaded from C:\chef\client.pem
# => Adding run_list to nodeGWtestRT2.example.net
# => WARNING: No knife configuration file found
# => ERROR: Your private key could not be loaded from C:\chef\client.pem
# => Adding run_list to nodeSTtestRT0.example.net
# => WARNING: No knife configuration file found
# => ERROR: Your private key could not be loaded from C:\chef\client.pem
# => Adding run_list to nodeGWtestRT3.example.net
# => WARNING: No knife configuration file found
# => ERROR: Your private key could not be loaded from C:\chef\client.pem
# => Adding run_list to nodeGWtestRT0.example.net
# => WARNING: No knife configuration file found
# => ERROR: Your private key could not be loaded from C:\chef\client.pem
I know I'm not doing the knife exec command correctly, and the documentation is confusing to me. I haven't found any examples that are close, or related to what I am trying to do. How should I go about trying to programmatically search for nodes, and then update, or add items to their run_list?
A simple way of doing this:
knife exec -E 'nodes.transform("fqdn:WSO2*") { |n| n.run_list << "role[role_zabbix_agent_corp_prod]" }'
nodes.transform handles the search loop and the save (as long the block doesn't return nil/false) and RunList#<< already checks if it is already in the run list.
A simpler solution is to use ridley, a ruby API library for chef server:
require 'ridley'
Ridley::Logging.logger.level = Logger.const_get 'ERROR'
ridley = Ridley.from_chef_config("C:\Users\myuser\Documents\test\knife.rb", {:ssl => {:verify => false}})
ridley.search(:node, "fqdn:node*test*.example.net").each { |n|
n.merge_data(:run_list => ["role[role_zabbix_agent_corp_prod]"])
n.save
}
This is what I did to accomplish what I wanted to do after talking with some friends and IRC chat rooms.
# similar to knife search node "fqdn:WSO2*"
search("node", "fqdn:WSO2*").each do |search_node|
# This looks at the array of the node information, and if the
# run_list already exists, do nothing and move on.
unless search_node.run_list.include?("role[role_zabbix_agent_corp_prod]")
# This adds the listed role, or recipe to the end of the run_list
search_node.run_list.push "role[role_zabbix_agent_corp_prod]"
# Save the modifications.
search_node.save
end #=> End Unless
end #=> End Search
# Make sure to add this to the end, or it will continue to keep running.
exit 0
Put the above script into a file named script.rb and run it as such:
knife exec script.rb
After doing reading through knife exec and also, chef-shell, I had to play around with the data structures and figure out how they were presented by Chef. The site here: http://www.bonusbits.com/main/Reference:Chef_Node_Data_Structure and http://www.bonusbits.com/main/Reference:Chef_Shell helped a lot as well. I hope this helps someone wanting to understand Chef a bit more.
We've got a diverse dev team, one on Windows, another on Ubuntu and another on OSX. Being windows boy, I setup the first version of the vagrant setup script which works fabulously ;)
However, when running it on the Ubuntu host, the first time it gets to a provision step that calls a bash script, it fails due to permissions.
On windows, this doesn't matter as the samba share automatically has sufficient permissions to run the bash script (which resides within the project hierarchy, so is present in the /vagrant share on the VM), but with ubuntu I need to set the permissions on this file in the provision script before I call it.
This isn't the problem and to be honest I suspect even with the extra "chmod" step it would still work fine under windows, but, is there a way in the vagrant file to flag certain provisioning steps as 'Windows Only', 'Linux Only' or 'Mac Only'?
i.e. in pseduo code, something like.
.
.
if (host == windows) then
config.vm.provision : shell, : inline => "/vagrant/provisioning/only_run_this_on_windows.sh"
else if (host == linux) then
config.vm.provision : shell, : inline => "/vagrant/provisioning/only_run_this_on_linux.sh"
else if (host == osx) then
config.vm.provision : shell, : inline => "/vagrant/provisioning/only_run_this_on_osx.sh"
end if
.
.
Thanks in advance.
Note that Vagrant itself, in the Vagrant::Util::Platform class already implements a more advanced version of the platform checking logic in the answer by BernardoSilva.
So in a Vagrantfile, you can simply use the following:
if Vagrant::Util::Platform.windows? then
myHomeDir = ENV["USERPROFILE"]
else
myHomeDir = "~"
end
Find out current OS inside Vagrantfile.
Add this into your Vagrantfile:
module OS
def OS.windows?
(/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
end
def OS.mac?
(/darwin/ =~ RUBY_PLATFORM) != nil
end
def OS.unix?
!OS.windows?
end
def OS.linux?
OS.unix? and not OS.mac?
end
end
Then you can use it as you like.
if OS.windows? [then]
code...
end
Edit: was missing the ? on if condition.
Example used to test:
is_windows_host = "#{OS.windows?}"
puts "is_windows_host: #{OS.windows?}"
if OS.windows?
puts "Vagrant launched from windows."
elsif OS.mac?
puts "Vagrant launched from mac."
elsif OS.unix?
puts "Vagrant launched from unix."
elsif OS.linux?
puts "Vagrant launched from linux."
else
puts "Vagrant launched from unknown platform."
end
Execute:
# Ran provision to call Vagrantfile.
$ vagrant provision
is_windows_host: false
Vagrant launched from mac.
Here is a version using the Vagrant utils that checks for mac and windows:
if Vagrant::Util::Platform.windows?
# is windows
elsif Vagrant::Util::Platform.darwin?
# is mac
else
# is linux or some other OS
end
When I read the original question according to me it is not how to find out on which OS vagrant it self runs, but which OS do the virtual machines to be provisioned have. That is why you want to run a different provision script depending on the diffent OSses of the new VMs, eg: "/vagrant/provisioning/only_run_this_on_${OS_OF_NEW_VM}.sh".
Unfortunately Vagrant does not have this capability (yet), so this is my solution: I define my VMs on top of my vagrant file:
cluster = {
"control.ansible.RHEL76" => { :ip => "192.168.1.31", :type => 0, :cpus => 1, :mem => 1024, :box_image => "centos/7" },
"app01.ansible.RHEL76" => { :ip => "192.168.1.32", :type => 1, :cpus => 1, :mem => 1024, :box_image => "centos/7" },
"app02.ansible.RHEL76" => { :ip => "192.168.1.33", :type => 1, :cpus => 1, :mem => 1024, :box_image => "centos/7" },
"winserver" => { :ip => "192.168.1.34", :type => 2, :cpus => 1, :mem => 1024, :box_image => "mwrock/Windows2016" },
}
Then these conditions in my code can provision different ways depending on the OS of the VM's:
if "#{info[:box_image]}" == "mwrock/Windows2016" then
puts "is_windows_host: #{info[:box_image]}"
config.vm.provision : shell, inline => "/vagrant/provisioning/only_run_this_on_windows.psl"
end
if "#{info[:box_image]}" == "centos/7" then
puts "is_linux_host: #{info[:box_image]}"
config.vm.provision : shell, inline => "/vagrant/provisioning/only_run_this_on_linux.sh"
end
By the way, only the ansible controller should have ansible installed, because in real life (yes the office) I do not use vagrant but an ansible controller, which I also want in my lab (OK Virtual Box on both my Windows 10 desktop as well as my Ubuntu laptop). I use a condition to test "type = 0" (which I use for a ansible "controller"). Only the ansible controller starts ansible_local to provision the cluster of VMs with ansible.
if info[:type] == 0 then
cfg.vm.provision "shell", inline: "if [ `which ansible` ] ; then echo \"ansible available\"; else sudo yum -y update; sudo yum -y install epel-release; sudo yum -y install ansible; fi"
cfg.vm.provision "ansible_local" do |ansible|
ansible.extra_vars = { ansible_ssh_user: 'vagrant' }
ansible.inventory_path = "./production"
ansible.playbook = "rhelhosts.yml"
ansible.limit = "local"
end # ansible_local
This is displayed during a vagrant provision:
PS D:\Documents\vagrant\top> vagrant provision control.top.RHEL76
is_linux_host: centos/7
is_linux_host: centos/7
is_linux_host: centos/7
is_windows_host: mwrock/Windows2016
This is displayed during a vagrant provision:
PS D:\Documents\vagrant\ansible> vagrant provision control.ansible.RHEL76
is_linux_host: centos/7
is_linux_host: centos/7
is_linux_host: centos/7
is_windows_host: mwrock/Windows2016
--- many more lines, not relevant ---
Have fun experimenting and deploying your multimachine / multi OS labs!
I'm relatively new to Chef, and I'm trying to setup a Vagrant Box using Digital Ocean as a provider and Chef as a provisioner. The issue seems to be with the roles, but as far as I can tell, they match up fine. Thanks.
Here is my Vagrantfile:
Vagrant.configure('2') do |config|
config.omnibus.chef_version = :latest
config.vm.provider :digital_ocean do |provider, override|
config.vm.hostname = 'majestic-chaos-ubuntu14.04x64'
override.ssh.private_key_path = '~/.ssh/id_rsa'
override.vm.box = 'digital_ocean'
provider.token = 'XXXXXXXXXXXX'
provider.image = 'Ubuntu 14.04 x64'
provider.region = 'nyc2'
provider.size = '512mb'
end
config.vm.provision :chef_solo do |chef|
chef.cookbooks_path = ['../../cookbooks']
chef.roles_path = ['../../roles']
chef.add_role ("majestic-chaos-ubuntu14.04x64")
end
end
and my roles file:
name "majestic-chaos-ubuntu-14.04x64"
ssl_verify_mode :verify_peer
run_list(
"recipe[apt]",
"recipe[open-ssl]",
"recipe[build-essential]",
"recipe[chef-ruby_build]",
"recipe[nodejs-cookbook]",
"recipe[rbenv::user]",
"recipe[rbenv::vagrant]",
"recipe[zsh]",
"recipe[vim]",
"recipe[imagemagick]",
)
override_attributes(
rbenv: {
user_installs: [{
user: 'vagrant',
rubies: ["2.1.2"],
global: "2.1.2",
gems: {
"2.1.2" => [
{ name: "bundler" }
]
}
}]
}
)
And this is the error I'm getting:
[2014-09-18T16:05:48-04:00] INFO: *** Chef 11.16.2 ***
[2014-09-18T16:05:48-04:00] INFO: Chef-client pid: 2934
[2014-09-18T16:05:51-04:00] INFO: Setting the run_list to ["role[majestic-chaos-
ubuntu14.04x64]"] from CLI options
default: [2014-09-18T16:05:51-04:00] ERROR: Role majestic-chaos-ubuntu14.04x64 (included
by 'top level') is in the runlist but does not exist. Skipping expand.
[2014-09-18T16:05:51-04:00] FATAL: Stacktrace dumped to /var/chef/cache/chef-
stacktrace.out
[2014-09-18T16:05:51-04:00] ERROR: The expanded run list includes nonexistent roles:
majestic-chaos-ubuntu14.04x64
[2014-09-18T16:05:51-04:00] FATAL: Chef::Exceptions::ChildConvergeError: Chef run process
exited unsuccessfully (exit code 1)
I had a similar problem when launching a Vagrant image where the roles file was not being picked up. The solution I found for that was that for the kitchen.yml file the roles file should be in JSON format. (The roles file listed above does not look like JSON).
As documented here: https://docs.chef.io/config_yml_kitchen.html
roles_path The relative path to the directory in which role data is located. This data must be defined as JSON.
Here are a few ruby commands to convert your .rb to JSON
require 'chef'
role = Chef::Role.new
role.from_file("./roles/useful_api_role.rb")
puts JSON.pretty_generate(role)
As a side effect, this above code will load up an rb config and you can validate that it's producing the role variables you expect.
Try using absolute paths for the roles and cookbooks:
chef.cookbooks_path = File.expand_path('../../cookbooks', __FILE__)
chef.roles_path = File.expand_path('../../roles', __FILE__)