Specify return codes with chef package? - windows

I'm installing an exe using chef's package resource and the run is failing with a return code of 3010. A return code of 3010 means the install was successful, but a reboot is required.
I can get around this by putting ignore_failure true on the resource, but I think this would let legitimate errors go through.
Chef's resource windows_package has a returns property which allows you to specify an array of possible return values. However, windows_package is deprecated in favor of the more generic package resource, but package does not have a returns property.
Is there some other way that I'm not aware of that would allow me to specify return codes with the generic package resource?
Current code structure:
package 'Install Something' do
source source_location
package_name name_of_package
options argument_list
action :install
provider Chef::Provider::Package::Windows
ignore_failure true
end

It is not deprecated, use windows_package.

Related

Source for package SQLServer2012SP4KB4018073x64ENU.exe does not exist in chef

i am trying to install sql server 2012 using chef to a virtual box.. Below is the code that i use but i am getting source does not exist error. Below is the server.rb code that i have..
package package_name do
source 'C:\Users\user\AppData\Local\Temp\SQLServer2012SP4KB4018073x64ENU.exe'# package_url
checksum package_checksum
timeout node['sql_server']['server']['installer_timeout']
installer_type :custom
options "/q /ConfigurationFile=#{config_file_path} #{passwords_options}"
action :install
notifies :request_reboot, 'reboot[sql server install]'
returns [0, 42, 127, 3010]
Error
* template[C:\Users\vagrant\AppData\Local\Temp\kitchen\cache\ConfigurationFile.ini] action create (up to date)
windows_package[SQLServer2012SP4KB4018073x64ENU.exe] action install
* Source for package SQLServer2012SP4KB4018073x64ENU.exe does not exist
Aside from making the file accessible for windows_package resource, one more change can be made.
The name of windows_package resource should match the application name displayed in Control Panel. As you are using SQLServer2012SP4KB4018073x64ENU.exe as the name, Chef will start installation of the package every time it is run (which is probably not what we want).
For e.g. if I want to install a simple package like WinSCP, which is displayed in Control Panel as WinSCP <version>, then I should name my resource with that.
windows_package 'WinSCP 5.17.7' do
source 'C:\Users\Administrator\Downloads\WinSCP-5.17.7-Setup.exe'
installer_type :custom
options '/silent'
end
Now if Chef runs again, it will make this install idempotent.

Chef - run install block based on variable condition

Background: our systems are setup in a way that I will only be able to see the local chef log and will have no access to the Chef server console or any other sysadmin privileges. Hence I have a need to log locally if I want to see if or why something failed.
I can hear you asking " If you don't trust the pkg or Chef to install it correctly, then..." My answer is that while you are correct, I still want to be covered by the occasional anomaly.
My goal is to install a pkg, check to see that it installed correctly than go on to the next pkg.
On to the question:
I would like to set a variable that checks for the existence of a directory that was created by the first package using the following code:
mycond = ::File.directory?('/opt/MyPkg/conf')
Chef::Log.fatal("MyPkg package not installed ? conf dir is missing") unless mycond
the next stage in the recipee is to run the next install block checking to see if the variable has been set.
yum_package 'OtherPkg' do
action :install
only_if { mycond }
end
My question is since the only_if is failing, I was wondering if there was something wrong with the way I am setting the mycond variable ? perhapes {} braces are needed somewhere in the code ?
Total Chef newbie so please be specific with your answer.
Thanks !
Full code below:
yum_package 'MyPkg' do
flush_cache [ :before ]
action :install
end
mycond = ::File.directory?('/opt/MyPkg/conf')
Chef::Log.fatal("MyPkg package not installed ? conf dir is missing") unless mycond
yum_package 'OtherPkg' do
action :install
only_if { mycond }
end
The problem is Chef's two-pass model. See https://coderanger.net/two-pass/ for the full explanation for for this you just need to move the condition check in to the only_if block itself since that is delayed until converge time: only_if { ::File.directory?('/opt/MyPkg/conf') }.
Using the fatal log level is also probably not a good idea as this isn't actually a fatal error as written.
Chef has an order of precidance that controls the flow of execution.
Code inside resource blocks (e.g. 'yum_package') will execute AFTER any loose code in your recipe.
The following lines are being executed FIRST, before your 'yum_package' blocks:
mycond = ::File.directory?('/opt/MyPkg/conf')
Chef::Log.fatal("MyPkg package not installed ? conf dir is missing") unless mycond
I believe you can nest resource blocks. You cold be able to combind all this code in a 'ruby_block' and it should execute in order as you'd expect.

Custom package provider to work around namespace conflicts

I have a set of RHEL / CentOS systems where I am using the NetBSD pkgsrc system
to install various packages into a certain tree (e.g. /opt/local). I want to
manage this with Puppet. I started out simply using the pkgin provider, but
I quickly ran into namespace conflicts. For example, both the yum and pkgin
providers were adding Package[openssl], and they conflicted.
To fix this, I have been trying to use a static prefix on my pkgsrc packages,
then strip it off when it is actually passed to the pkgin command for handling.
First, I wrote a define to add the prefix and set the provider.
define mypkgin::package($ensure='latest') {
package { "mypkgin_${title}":
ensure => $ensure,
provider => 'mypkgin',
}
}
This will show up in the namespace as Mypkgin::Package[openssl], which does
not itself conflict with anything. And its goal is to add a resource named
Package[mypkgin_openssl], to not conflict with Package[openssl] from yum.
Then, I copied the pkgin provider code and modified it to provide a thing
named mypkgin. I have a small method in here to strip the prefix from the
name, and that is used in a few places so that the pkgin command receives
the pkgsrc package name instead of the prefixed version.
require "puppet/provider/package"
Puppet::Type.type(:package).provide :mypkgin, :parent => Puppet::Provider::Package do
desc "Package management using pkgin/pkgsrc, my local edition."
# Specify full path since it's not in Puppet's exec path
commands :pkgin => "/opt/local/bin/pkgin"
has_feature :installable, :uninstallable, :upgradeable, :versionable
# Strip prefix off of package name
def my_pkgname(package)
package.gsub(/^mypkgin_/, '')
end
def self.parse_pkgin_line(package)
# e.g.
# vim-7.2.446 = Vim editor (vi clone) without GUI
match, name, version, status = *package.match(/(\S+)-(\S+)(?: (=|>|<))?\s+.+$/)
if match
{
:name => name,
:status => status,
:ensure => version
}
end
end
def self.prefetch(packages)
super
# Without -f, no fresh pkg_summary files are downloaded
pkgin("-yf", :update)
end
def self.instances
pkgin(:list).split("\n").map do |package|
new(parse_pkgin_line(package))
end
end
def query
packages = parse_pkgsearch_line
if packages.empty?
if #resource[:ensure] == :absent
notice "declared as absent but unavailable #{#resource.file}:#{resource.line}"
return false
else
#resource.fail "No candidate to be installed"
end
end
packages.first.update( :ensure => :absent )
end
def parse_pkgsearch_line
packages = pkgin(:search, my_pkgname(resource[:name])).split("\n")
return [] if packages.length == 1
packages.slice!(-4, 4)
pkglist = packages.map{ |line| self.class.parse_pkgin_line(line) }
pkglist.select{ |package| my_pkgname(resource[:name]) == package[:name] }
end
def install
if String === #resource[:ensure]
pkgin("-y", :install, "#{my_pkgname(resource[:name])}-#{resource[:ensure]}")
else
pkgin("-y", :install, my_pkgname(resource[:name]))
end
end
def uninstall
pkgin("-y", :remove, my_pkgname(resource[:name]))
end
def latest
package = parse_pkgsearch_line.detect{ |package| package[:status] == '<' }
return properties[:ensure] if not package
return package[:ensure]
end
def update
pkgin("-y", :install, my_pkgname(resource[:name]))
end
end
Every time I run puppet agent --test, it tells me that it has added all of these
packages. So clearly I have some namespace bit wrong. It thinks on each run that
the package either needs to be installed, or upgraded, and it tries to do that.
I assume that in one or more places, I should add or remove calls to
my_pkgname(), but I can't seem to figure out where I've gone wrong.
Your provider determines which packages are already available on the system by means of prefetching. It looks like you have not replaced or overridden the bits that will result in that process ultimately relying on the instances() method.
Looking at that method, it appears that it will generate instances exactly as the pkgin provider would do, right down to the generated package names. That's a problem for you, because your scheme involves translating package names. It's not enough just to translate the names Puppet uses to the native ones -- you must also translate the native ones to the ones you want Puppet to see when you create instances on the provider side.
It looks like self.parse_pkgin_line() could be modified pretty easily to prepend the needed prefix to your package names. That seems like it would be the right thing for it to do, but I'm uncertain whether it would have any undesirable side effects. It is possible that additional changes will be required as well, such as in parse_pkgsearch_line(), but that's not immediately clear to me.

Chef guard multiple resources with single not_if

When using chef, I only want to execute a sequence of resources if a certain condition is fulfilled. Currently, I have to add the not_if guard to each resource individually. Is there a way to wrap multiple resources inside with a single not_if guard like so:
wrap_resources do
service 'my-service'
package 'my-package'
not_if certain_condition
end
And I do not want to use that nasty notify!
Simple solution for at compile time condition:
if !certain_condition
service 'my-service'
package 'my-package'
end
Recipes allow pure ruby, you can just skip defining those resources in your recipe with a simple if block.
According to your example, you're looking for a LWRP or from chef 12.5 custom_resource
The syntax is near the same, LWRP use two files (resource and provider) where custom_resource use only one.
The idea behind this is to create a new resource which will do some tests at converge time and then run it's inner resources if needed. The LWRP/custom_resource inner resources are run in a separate context.
I.e:
my_cookbook/resources/wrapper.rb
property :name, RubyType, default: 'value'
default_action: run
action :run do
service 'my-service'
package 'my-package'
end
my_cookbook/recipes/default.rb
my_cookbook_wrapper 'service and package' do
not_if lazy { certain_condition }
end
Beware if you're using - in your cookbook name, this char is not allowed for Ruby Classes and is replaced by a _ if found.
You can also do the following:
unless certain_condition
service 'my-service'
package 'my-package'
end
So that you don't need to use a negative statement. Makes it a little more cleaner!

Why chef does not execute recipe line by line?

Problem is that chef tries to install template first, and only then installs packages. If i comment template block, chef will install sphinxsearch package fine.
But if template block is not commented, sphinxsearch package is not installed, and chef fails with error
resource template[/etc/sphinxsearch/sphinx.conf] is configured to notify resource service[sphinxsearch] with action reload, but service[sphinxsearch] cannot be found in the resource collection`
Why this happens?
##
# Install system packages
##
node['website']['packages'].each do |pkg|
log 'Installing ' + pkg
package pkg
end
##
# Configure sphinx
##
template "/etc/sphinxsearch/sphinx.conf" do
source 'sphinx.erb'
owner 'root'
group 'root'
mode 00644
notifies :reload, 'service[sphinxsearch]', :delayed
end
notifies and subscribes in chef are both trying to reach out to resources that have been defined in your chef run. They will then call teh indicated action on those resources. In your case:
notifies :reload, 'service[sphinxsearch]', :delayed
is looking for a resource of type service named sphinxsearch and call the reload action on it. If, at the end of the resource gathering (compile) phase, chef cannot find a service[sphinxsearch] resource, then it throws the error. You don't see the package installed because chef never enters the execution phase. (See this answer for more on the two phase nature of chef)
As indicated by #IsabelHM, you could solve the problem by adding
service 'sphinxsearch' do
action [:enable, :start]
end
I suggest you use [:enable, :start] rather than :nothing as this will ensure that the service is always running, even if your template doesn't change. Also, please note that the service resource does not add a service config for you. So if the sphinxsearch package does not add a service config, you'll also need a cookbook_file, template, or remote_file resource to create the service config with.
Add this in your recipe.
service 'sphinxsearch' do
action :nothing
end

Resources