I'm trying to write a Foodcritic rule which verifies only Private Supermarkets are listed in a Berksfile. Are the Berksfile source URLs included in the Ruby AST?
No, but you could use RuboCop. Foodcritic is only for cookbook stuffs specifically.
Related
I'm attempting to create a Chef cookbook that, for now, is mostly just a wrapper cookbook for another cookbook (the audit cookbook). I'm still learning Chef, but from what I can gather from the About Recipes documentation and the Resources Reference documentation, Chef recipes should execute in the order that they're defined (via Ruby code and/or Chef resources).
In the About Recipes documentation, it mentions that
When a recipe is included, the resources found in that recipe will be
inserted (in the same exact order) at the point where the
include_recipe keyword is located.
In the Resources Reference documentation, they have an apt_update resource that presumably executes before the include_recipe method due to the fact that it's defined earlier in the recipe.
My wrapper cookbook has a single recipe, default.rb, which is literally these two lines:
package 'ruby-dev'
include_recipe 'audit'
However, during a chef-client or chef-solo run I see that the audit::inspec recipe runs before the security::default recipe which causes things to break because InSpec has some other dependencies that need to be installed beforehand. Before I used the package resource I was using the execute resource to explicitly run apt-get install ruby-dev or yum install ruby-dev depending on the platform using a case statement, but same problem (all that code was skipped and the include_recipe method called first).
In case it's useful, I'm using Chef 12 which I realize is EOL but I have other dependencies that require me to stick with this version of Chef for now.
I may very well just be misunderstanding how Chef converges work and the order in which execution occurs, but it's causing me a lot of grief so I'd really appreciate some pointers! Does include_recipe always occur before other code within your recipe? Is there any way around this? Am I missing something?
-- EDIT --
I was able to get the desired functionality (install other packages and gems before an include_recipe call triggered installation of a dependency gem) using the following code in my cookbook recipe:
package 'build-essential' do
action :nothing
end.run_action(:install)
chef_gem 'train' do
version "1.4.4"
action :install
end
chef_gem 'signet' do
version "0.11.0"
action :install
end
include_recipe 'audit'
Note that I ended up installing the build-essential package rather than the ruby-dev package from my original code snippet, and also installed two gems for Chef client to use. This all gets installed in the order I expected during the compile phase of the Chef run.
Sources:
https://docs.chef.io/resource_reference.html#run-in-compile-phase
https://docs.chef.io/resource_chef_gem.html
if you would examine the audit::inspec rescipe, you will find that it uses a compile time installation of the inspec rubygem (see the last line)
inspec_gem 'inspec' do
version node['audit']['inspec_version']
source node['audit']['inspec_gem_source']
action :nothing
end.run_action(:install)
from chef documentation:
run_action
Use .run_action(:some_action) at the end of a resource block to run the specified action during the compile phase.
i am managing my cookbooks with berkshelf.
i would like to play a little bit with the cookbook dependency graph. for instance:
given a cookbook, get its dependencies (the same as the resolver does it)
given a cookbook, get depended cookbooks (same as berks contingent)
i tried
require 'berkshelf'
Berkshelf::Lockfile.new(file_path: './Berksfile.lock')
but it did not work.
how can berkshelf be invoked programmatically under ruby and achieve the above?
This is not supported, or anything even in the same area code as supported. We have no public Ruby APIs for this data, sorry. You can look at the Solve gem, but it's not really used outside of our own use cases.
If you have Berksfile, It might be helpful for you.
require 'berkshelf'
# initializing berksfile
s = Berkshelf::Berksfile.from_file('./find_versions/Berksfile')
#install dependencies to create Berksfile.lock
s.install()
# parse lockfile
s.lockfile().parse()
# find dependencies
puts s.find('cookbook_name').locked_version
eg.
I am writing a wrapper cookbook (my_cookbook) for the same purpose I am using the community cookbook (community_cookbook). I face an issue regarding the dependency list present in community_cookbook.
The metadata.rb file in community_cookbook has the following dependency list.
...
depends mysql
depends postfix
...
So, by default the run-list has the latest version (say 8.3.0) of mysql cookbook.
My question is what changes should I be making in order to get previous version of mysql (say 5.3.6).
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
What steps did I take to solve this problem ?
Ans:
I wrote the following in metadata.rb of my_cookbook.
...
depends 'mysql', '~> 5.6.3'
depends 'community_cookbook', '~> 1.1.0'
...
And I got this following message on the console
>>>>>> Failed to complete #converge action: [Unable to satisfy the following requirements:
- `mysql (= 8.3.0)` required by `user-specified dependency`
- `mysql (~> 5.6.3)` required by `my_cookbook-0.1.0`
- `mysql (>= 0.0.0)` required by `community_cookbook-1.1.0`
- `mysql (>= 6.0.0)` required by `php-3.0.0` # This is because the community_cookbook also has php as it's dependency list.
You might have changed the Berksfile.lock manually and it is causing the above issue.
can you try to deleting Berksfile.lock(take backup) and do berks install and then upload?
it should install all the necessary version of mysql cookbook
and then all the cookbook can have the mysql version they require
It sounds like you have something funky in your Berkfile or Policyfile. Check for unintended version pins there and possibly run berks update to force a re-solve. The user-specified-dependency means that constraint is coming from outside the cookbook system, usually via a manual cookbook 'mysql', '8.3.0' in a Berksfile but there are other ways like environment constraints or run list version hacks.
Basically, I'm trying to build a gem that does some form of test failure when certain dependencies are outdated. In the testing framework I can easily stub the crap out of Gem so that Gem.loaded_specs("foo") returns the spec for the gem foo. What I'm looking for is a way to provide a fixture Gemfile and then parse the lock file.
When I use Gem.loaded_specs it somehow magically knows which Gemfile to use, how do I feed it a different gemfile (ie: my fixture)?
I know somebody mentioned "use bundler" and that makes sense but in my code for the gem I do this:
gem_here = Gem.loaded_specs[gem_name]
gem_here.nil? ? :not_in_bundle : gem_here.version.to_s
I need to make this work with my fixture Gemfile and not the current projects gemfile.
Does this make any sense? Sorry if this is vague.
Note: I'm not trying to do this via the CLI. I'd like to use programmatic (ie: ruby api) methods if I can.
Edit:
I'm going with this kind of source now:
gem_here = Bundler.load.specs.detect do |specs|
specs.name == gem_name
end
gem_here.nil? ? :not_in_bundle : gem_here.version.to_s
Parsing yourself isn’t desirable as Bundler does the heavy-lifting (parsing, dependency resolution).
Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile))
Then, use gemspecs and the lockfile to visit all runtime and/or development dependencies. Runtime/development deps for specific gems are available via a (currently undocumented, needs contrib) RubyGems JSON API https://api.rubygems.org/api/v2/rubygems/rails/versions/5.0.0.1.json
Note: Bundler 2.0 Gemfile.lock -> gems.locked
We are facing a situation, where end users Windows VM does not have internet connectivity, but only have access to file store.
We are using windows_zipfile resource in one of our recipe. So cookbook execution failed in Windows cookbook, due to the reason that, it is not able to download rubyzip from "rubygems.org" site.
We are thinking of solving the issue in either of these two ways,
Replace the windows_zipfile code with powershell_script and implement the code using Powershell commands
Load the rubyzip gem and its dependency in file store and install the gems before calling windows_zipfile resource.
Please provide suggestions to handle the scenario. Also let me know, is there any other way to solve the issue.
You should be able to install a chef_gem from a local path, after downloading it from a source inside your network (just replace the URL of https://rubygems.org):
{"httpclient" => "2.7.1", "rubyzip" => "1.1.7"}.each do |gem,version|
filename = "#{gem}-#{version}.gem"
remote_file File.join(Chef::Config[:file_cache_path], filename) do
source "https://rubygems.org/downloads/#{filename}"
end
chef_gem gem do
source File.join(Chef::Config[:file_cache_path], filename)
version version
end
end
As the Gem is used by Chef's ruby, make sure to use the chef_gem resource.