I'm working on a infrastructure where some servers don't have access to the internet, so I have to push the packages to the local repo before declaring them to be installed on Chef.
However we've been on a situation where Chef failed to install a package since the package wasn't there on some boxes and it has been successful on some other boxes.
What I want to do is to run a Ruby/RSpec test before applying Chef config on the nodes to make sure the packages declared on the recipes do actually exist on the repo.
In order to do that I need to be able to list all the packages exists in the our recipes.
My question is: Is there anyway to list all the declared packages in Chef? I had a quick look at Chef::Platform and ChefSpec but unfortunately couldn't find anything useful to my problem.
Do you have any idea where is the best place to look at?
If you use ChefSpec you can find all the packages by calling chef_run.find_resources(:package) inside some test. See the source code. Like this:
require 'chefspec'
describe 'example::default' do
let(:chef_run) { ChefSpec::Runner.new.converge(described_recipe) }
it 'does something' do
chef_run.find_resources(:package)...
end
end
You could install one or more of the community ohai plugins. For example the following will return information about installed sofware:
debian
Redhat
windows
Once the plugins are enabled they will add additional node attributes that will be searchable from chef-server.
Related
I have a base package that gives my functionality (wireguard-tools, taken from internet).
This package includes no configuration files for the network interfaces (as it should).
Then I created a few packages with this configuration files that are only to be deployed one for each respective image (e.g. image-1 includes wireguard-1-conf while image-2 includes wireguard-2-conf).
I would like to setup SystemD, but I can only do this when I have an interface configured, and it will only happen when the *-conf package is installed.
Unfortunately, the SystemD service file ("wg-quick#.service") is deployed by wireguard-tools package and my dependent package, the *-conf one, cannot see it:
ERROR: Function failed: SYSTEMD_SERVICE_wireguard-1-conf value wg-quick#wg0.service does not exist
I managed to do a dirty workaround but I feel dirtiest doing this in my *-conf recipe:
do_install_append () {
touch ${D}${systemd_system_unitdir}/wg-quick#wg0.service
pkg_postinst_${PN} () {
rm -f $D/${systemd_system_unitdir}/wg-quick#wg0.service
How should I proceed to make it work "the right way"?
Is there an elegant way of making "wg-quick#.service" from wireguard-tools accessible to *-conf?
Thanks in advance.
Additional Info
My *-conf recipes inherit systemd and include wireguard-tools dependency:
inherit systemd
...
DEPENDS_${PN} = "wireguard-tools"
RDEPENDS_${PN} = "wireguard-tools"
I so nothing else worth to mention in my recipes.
I would like to install several arbitrary APT packages using Vagrants Chef solo provisioner.
chef.json seems to allow you to execute chef commands, but I'm unclear as to how to do this. Something like:
chef.json = {
apt: {
package: {'libssl-dev': {action: 'install'}}
}
?
Chef uses recipes to define resources that are executed on nodes via a chef-client.
A recipe is basically a definition of what to do (a script)
A resource is a particular element you are configuring (a file, a service, or package etc)
A node is the machine running chef-client
The json that you are setting up for chef-solo defines attributes which are like variables that your Chef can use to decide what to do.
So you have a hash of attributes for Chef to use, but you need a recipe that configures resources based on that hash to be executed on your node
In your case you need to configure the package resource
package "name" do
some_attribute "value"
action :action
end
The package resource supports lots of different package back ends, including apt so you don't need to worry about differences (except for package names).
To install the packages from your hash you can create a recipe like:
node[:apt][:package].each do |pkg,pkg_data|
package pkg do
action pkg_data[:action].to_sym
end
end
Individual recipes are then packaged up into cookbooks which is a logical grouping of like recipes. Generally a cookbook would be for a piece of software, say httpd or mysql.
As Tensibia mentions, read through the Vagrant Chef-Solo docco for where to put your recipe/cookbook and run from there.
chef.json does not execute or define commands.
It defines attributes for the node which can be used by recipes.
I would recomand reading THIS
and THIS
Some of the json content is generated by vagrant like defining the runlist attribute with the chef.add_recipe keyword in the vagrantfile.
For your use case you should have a cookbook with a recipe parsing node['apt'] and using deb_package resource.
I am getting the message:
Puppet::Parser::AST::Resource failed with error ArgumentError: Could not find declared class git at /tmp/vagrant-puppet-1/manifests/site.pp:15 on node vagrant-ubuntu-precise-64.wp.comcast.net
Probably the best idea is to see this in action. I have created a GitHub repo of the exact manifest I am using. It is here:
https://github.com/jamorat/puppet-example
The manifests and git module are there. If you have Vagrant, this can be vagrant up and you will see the error for yourself. Would be cool to either receive an answer here and/or also as a commit (for which credit would still be given here for answer.)
Thank you so much!
You need to configure vagrant with the puppet module path. On a side note, you would also usually keep the manifest and module folder in the same folder, instead of modules inside manifests.
This:
class{ git:
svn => 'installed',
gui => 'installed',
}
is telling puppet to create a resource based on the class named git that has 2 parameters: svn and gui. Such a class declaration doesn't exist anywhere in what you've posted. If it were, it would look something like:
class git ($svn, $gui) {
package {'svn':
ensure => $svn,
}
# Whatever 'gui' is, making package b/c use of "installed"
package {'gui':
ensure => $gui,
}
}
Alternative is to declare a class and include it using the "include" directive.
Recommend a good reading of Language: Classes
I have built a cookbook for installing Jenkins CI. It uses the key and repository resources from the yum cookbook, so I end up with the following recipe:
yum_key "RPM-GPG-KEY-jenkins" do
url "http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key"
action :add
end
yum_repository "jenkins" do
description "Jenkins-CI 3rd party repository"
url "http://pkg.jenkins-ci.org/redhat"
key "RPM-GPG-KEY-jenkins"
action :add
end
When I include this recipe in another recipe:
include_recipe 'sp_jenkins::default'
and I test this with the following ChefSpec test
it 'includes the `sp_jenkins::default` recipe' do
expect(chef_run).to include_recipe('sp_jenkins::install')
end
my ChefSpec test fails with the following output:
NameError:
Cannot find a resource for yum_key on chefspec version 0.6.1
(I'm not sure why it says version 0.6.1, gem list tells me it's using 3.0.2)
The sp_jenkins cookbook does depend on the yum cookbook (metadata.rb), and runs fine, however, the cookbook I'm currently writing does not depend on the yum cookbook and therefore doesn't have the yum_key and yum_repository methods available.
Is there a way to prevent ChefSpec from 'descending' into included recipes/cookbooks and just test the current cookbook?
Ohai! Julian is correct - ChefSpec actually does a Chef Solo run in memory on your local machine. It rewrites the provider actions to be a noop, but creates a registry of all the actions taken (including those that would be taken if notifications were executed).
So just like you need the yum cookbook to converge this recipe on a real node, you need it to converge during your unit tests with ChefSpec. The easiest way to accomplish this is by using the Berkshelf or Librarian resolvers. To use the Berkshelf resolver, simply require 'chefspec/berkshelf' after requiring chefspec:
# spec_helper.rb
require 'chefspec'
require 'chefspec/berkshelf'
If you have Berkshelf installed on your system, it will pull all the cookbooks into a temporary directory and run ChefSpec for you.
You may also want to take a look at Strainer, which aims to solve a similar problem.
On a somewhat unrelated note, I am working on a fairly large refactor to the Jenkins cookbook that may better suit your needs.
Sources:
I wrote it...
No, there's no way to prevent it from descending, because it's trying to converge an entire Chef run in memory.
However, if you use the Berkshelf functionality in ChefSpec, the Berkshelf dependency resolver will feed all dependent cookbooks to the in-memory Chef run, and you'll be golden.
It is absolutely valid to expect to test your cookbook in isolation, and not include other projects' code into the scope of your tests. Unfortunately there appears to be no supported, "clean" way to do this, that I can find. I was able to achieve this, but it comes at a price.
To use this technique, do not require 'chefspec/berkshelf' anywhere in your test code, only chefspec itself, as you are intentionally not gathering other cookbook source. Here is a template of my working test module (not my complete test code, as I have omitted RSpec config options):
describe 'mycookbook::recipe' do
let(:chef_run) do
ChefSpec::SoloRunner.new(platform: 'x', version: 'x') {
# ...
}.converge(described_recipe)
end
before :each do
allow_any_instance_of(Chef::RunContext::CookbookCompiler).to receive(:cookbook_order) do
Chef::Log.debug 'Attempt to source external cookbooks blocked'
[described_cookbook]
end
allow_any_instance_of(Chef::Recipe).to receive(:include_recipe) do |recipe|
Chef::Log.debug "Attempt to include #{recipe} blocked"
end
end
it 'works' do
# ...
end
end
You need both of these in your before. The one I had to work for is the intercept of the :cookbook_order method. I had to drill down into the Chef internals to discover this. Keep in mind, this worked for me using Chef 14, but there is no guarantee that this will be future-safe. After upgrading Chef you might have to find another solution, if the implementation of CookbookCompiler ever changes. (The intercept of Chef::Recipe.include_recipe however is a supported API and therefore should be at least somewhat future-safe.)
And, I mention that this comes at a price. (Other than using an unsupported hack!) You will not be able to do any expects for your recipe or attribute includes, except within your own cookbook. A test case like this will fail, because the recipe can't actually be included, as you are preventing that:
it 'includes othercookbook::recipe' do
expect_any_instance_of(Chef::Recipe).to receive(:include_recipe).with('othercookbook::recipe')
end
Also, you must now satisfy in your before blocks all attributes and other preconditions that might otherwise be fulfilled by other recipes in your run list. So you may be signing yourself up for considerable pain by doing this. But, once you have finished, you will have much less brittle tests. (Although to achieve 100% purity regarding external dependencies, you must also surrender fauxhai, which will be even more painful.)
I have been attempting to setup a chef recipe which installs ruby using RVM and then uses the application_ruby cookbook to configure the application, however I keep running into the error
NameError: Cannot find a resource for bundle_options on ubuntu version 12.04
I am using the following code
application "application setup" do
owner "ubuntu"
group "ubuntu"
repository "https://github.com/me/myapplication.git" // Real address removed
path rails_app_path
revision "master"
rails do
bundler true
precompile_assets true
bundler_deployment true
end
end
I noticed that the bundle_options was recently added, https://github.com/opscode-cookbooks/application_ruby/commit/e7719170a661a957796e8e5d58ba8f4ecd937487 however I am unable to track down if this is causing the issue. I have included
depends "application"
depends "application_ruby"
in my metadata.rb and made sure all my dependencies are installed so I am unsure what I am doing wrong at this point.
According to documentation bundle_options is an attribute of the rails resource, not a resource itself.
The only correct way of using it is INSIDE the "rails" block, so you got the message because you either used it as :
an attribute of the application resource (but outside of the "rails" block)
standalone resource (outside of any resource).
Message you mentioned is being displayed when nonexistent resource is being referenced. e.g. if you had tried to execute following code on your system:
nonexistent_resource "failure gonna happen" do
some_attribute "whatever_value"
end
you would've got a message
NameError: Cannot find a resource for nonexistent_resource on Ubuntu version 12.04
I ran into this problem today as well. It appears the problem is that commit e771917 forgot to add the necessary getter for the bundle_option. Someone filed a PR to fix it (https://github.com/poise/application_ruby/pull/44), but it has not yet been merged. I can confirm that when I made that change locally, this error went away. The forked branch in the PR is located at https://github.com/mauriciosilva/application_ruby/tree/bundle_options_fix.