Verifying if package is installed before downloading it in PUPPET - puppet

That is my manifest code which download, install and remove installer on a host.
class googlechrome_2 {
package { 'GoogleChrome':
ensure => installed,
source => 'C:\Soft\ChromeSetup.msi',
install_options => ['/qn'],
require => File['GoogleChromeMsi'],
}
file { 'GoogleChromeMsi':
ensure => file,
path => 'C:\Soft\ChromeSetup.msi',
source => 'puppet:///files/production/ChromeSetup.msi',
}
exec { 'msi_removing':
command => 'C:\Windows\System32\cmd.exe /c del C:\Soft\ChromeSetup.msi',
}
}
In this case my windows host always download chromesetup.msi regardless if google chrome already installed or not. How can I realize kind of "if condition" here to avoid downloading msi package each time in case if this package already installed?

In this case my windows host always download chromesetup.msi regardless if google chrome already installed or not.
Yes. Having the File resource in the node's catalog specifies that the file should be managed. Therefore, if it is not initially in the target state then Puppet will attempt to fix that.
By managing the file present but also including an Exec that removes the file, you ensure that the target node cannot achieve a stable state.
How can I realize kind of "if condition" here to avoid downloading msi package each time in case if this package already installed?
Simplest option: don't remove the installer.
Variation: Put the installer in an accessible network folder, so that you not only don't remove it, but you also don't install it.
If you really want a conditional: then it should be based on a custom fact that reports on the installation status of the package in question. You then use a Puppet if statement to control the contents of the node's catalog appropriately. Something along these lines, for example:
package { 'GoogleChrome':
ensure => 'installed',
source => 'C:\Soft\ChromeSetup.msi',
install_options => ['/qn'],
# relationhip with File['GoogleChromeMsi'] now declared on the other end
}
if $facts['chrome_is_installed'] {
file { 'GoogleChromeMsi':
ensure => 'absent',
path => 'C:\Soft\ChromeSetup.msi',
}
} else {
file { 'GoogleChromeMsi':
ensure => 'file',
path => 'C:\Soft\ChromeSetup.msi',
source => 'puppet:///files/production/ChromeSetup.msi',
before => Package['GoogleChrome'],
}
exec { 'msi_removing':
command => 'C:\Windows\System32\cmd.exe /c del C:\Soft\ChromeSetup.msi',
require => Package['GoogleChrome'],
}
}

I've solved this by using network shared folder in the package source:
class googlechrome_smb {
package { 'Google Chrome':
ensure => installed,
source => '\\\xxx.xxx.xxx.xxx\winfiles\ChromeSetup.msi',
install_options => ['/qn'],
}
}

Related

puppet / facter: "created(corrective)"

I use puppet to update / maintain itself (among other things). For some reason every time the client runs I get these two actions:
Notice: /Stage[main]/Servers::Packages::Puppet/Package[facter]/ensure: created (corrective)
Notice: /Stage[main]/Servers::Packages::Puppet/Package[puppet]/ensure: created (corrective)
The definitions in question look like this:
package { 'puppet' :
ensure => 'latest',
require => Package['facter'];
}
package { 'facter' :
ensure => 'latest',
}
file { '/etc/default/puppet' :
ensure => 'file',
mode => '644',
source => 'puppet:///modules/servers/packages/puppet/default';
}
file{ '/etc/puppetlabs/puppet/puppet.conf' :
mode => '644',
content => template("servers/packages/puppet/puppet_conf.erb"),
require => Package[ 'puppet' ];
}
service{ 'puppet' :
ensure => 'running',
enable => true,
require => Package[ 'puppet' ],
subscribe => [
File[ '/etc/default/puppet'],
File[ '/etc/puppetlabs/puppet/puppet.conf'],
];
}
What's wrong with my definition(s)? Why do puppet / facter appear to be reinstalled with every run?
Since Puppet 4, Puppet, Inc. has provided only all-in-one packages of client-side components, not named either 'puppet' or 'facter'. The package for Puppet 6 is named puppet-agent -- this is what you should be managing, not packages named 'puppet' or 'facter'.
The messages you report indicate that Puppet does not see up-to-date 'puppet' or 'facter' packages, which is natural because these do not exist. They also indicate that puppet thinks it has corrected the problem -- which it will have attempted to do by installing / updating packages with those names, and which apparently succeeded. This seeming incongruity will have arisen because the puppet-agent packages declare that they provide features named "puppet" and "facter", which your package manager is using to associate those package names with the puppet-agent package. As a result, the installation / update succeeds without actually installing anything new, leaving the system primed to do the same thing over again on the next run.
I suspect that the "(corrective)" marks on the log output reflect package-manager exit statuses indicating success without doing anything.

Puppet code to download extract and install

I have a file at some web URL (http://www.somewhere.com/something.tar.gz).
This is direct download link.
I need a puppet code that would download this file, extract it and install the file.
Can we do this using package {} in puppet?
There isn't really an intrinsic provider for the package type that understands tarballs. There is, however, this VoxPopuli module: https://forge.puppet.com/puppet/archive which was recently Puppet certified and should do what you need.
Note under their usage example it could be modified for your needs like:
archive { '/tmp/something':
ensure => present,
extract => true,
extract_path => '/tmp',
source => 'http://www.somewhere.com/something.tar.gz',
checksum => 'checksum hash',
checksum_type => 'sha1',
creates => '/tmp/something',
cleanup => true,
}

Custom fact should run after a package is installed

I have a small custom fact in a my php module
Facter.add('php_extension_version') do
setcode do
Facter::Core::Execution.exec("php -i | awk '/^PHP Extension =>/ { print $4}'") || nil
end
end
This obviously requires the php binary to be installed. However, I noticed that all facts are run once before applying the catalog, so this fact is invalid before php installed.
Is there any way of gathering the information after the module is installed? Is there perhaps another way of exposing this information except facter?
Update
I'm using the two facts to determine which of multiple .so files is the right one to install:
if $php_zts_enabled {
$so_name = "newrelic-$php_extension_version.so"
} else {
$so_name = "newrelic-$php_extension_version-zts.so"
}
file {"/usr/lib64/php5/extensions/newrelic.so":
source => "file:///opt/newrelic-php5-$version-linux/agent/x64/$so_name",
owner => root,
group => root,
mode => 0644,
notify => Service['apache'],
require => Exec["extract-php-agent-$version"]
}
The files that are located in the agent/x64 directory can be
newrelic-20060613.so newrelic-20090626-zts.so newrelic-20121212.so newrelic-20131226-zts.so
newrelic-20060613-zts.so newrelic-20100525.so newrelic-20121212-zts.so
newrelic-20090626.so newrelic-20100525-zts.so newrelic-20131226.so
You essentially have only two opportunities to execute code on the node:
As part of a Facter fact. As you are aware, this happens before puppet applies a catalog, so any facts dependent on the results of the puppet run will not be useful until the next run.
As part of a custom provider. You can create a custom type and provider for installing the extensions that checks the node state before deciding what to do. Providers execute on the node, and as long as you know the overall provider lifecycle you can make this happen after the PHP install. However, this is incredibly complex compared to normal puppet modules.
Outside of those options, the normal way of doing this would be to enforce the version and configuration of php within your own manifests, and then pass that information to here. You should already know the version of PHP and its extensions based on what packages you have installed.
I would modify the fact so that it's present only when the binary is present (hence it won't be present at the very first run).
Facter.add('php_extension_version') do
setcode do
if system("which php > /dev/null 2>&1")
Facter::Core::Execution.exec("php -i | awk '/^PHP Extension =>/ { print $4}'") || nil
end
end
end
and then in your manifest you'd wrap the original code in the if
if $php_extension_version {
if $php_zts_enabled {
$so_name = "newrelic-$php_extension_version.so"
} else {
$so_name = "newrelic-$php_extension_version-zts.so"
}
file {"/usr/lib64/php5/extensions/newrelic.so":
source => "file:///opt/newrelic-php5-$version-linux/agent/x64/$so_name",
owner => root,
group => root,
mode => 0644,
notify => Service['apache'],
require => Exec["extract-php-agent-$version"]
}
}

Including a definition by variable

I'm working on putting together some puppet scripts - I've got a list of services (probably about 20 or so) that need to be deployed in very similar fashions.
Stop existing service
Get package out of nexus
Unzip it into directory
Set configuration variables
Start service
The problem is #4. Each service has a slightly different configuration. I'd like to use augeas to set the configurations for each service, and it seemed to make sense to make a definition for each service's config, and then that definition loaded in the main service definition.
So, I've got something like the following:
definition service ($serviceName) {
//stopping, wget, unzip
config[downcase($serviceName)] { "${servicename}_config":
serviceName => $serviceName
}
//start
}
Then, I've got (for example) in the config module's manifest folder "foo.pp"
definition config::foo {
//set some stuff
}
This isn't working due to various rules that I'm sure I've broken but are unaware of. Is there a 'standard' way of doing what I'm trying to do?
You could try the code below. You can put all these in a define type with variables for service name myserv. I would suggest of using templates to set the configuration rather than augeas... easier to control.
exec { "stop_myserv" :
command => "service stop myserv",
path => "/path/to/command/service",
refreshonly => true,
}
exec { "get_pkg_from_nexus" :
command => "/command/to/do/the/above && unzip to/dirctory",
path => "/path/to/command",
require => Exec["stop_myserv"],
}
file { "set_configuration" :
path => "/etc/somewhere/file",
content => template("modulename/file.erb"),
mode => "999",
group => "jiut",
owner => "muit",
require => Exec["get_pkg_from_nexus"],
}
service { "myserv" :
ensure => running,
subscribe => File["set_configuration"],
}

execute puppet class if file is modified by some package

I'm using puppet to deploy standardized ubuntu installs as well as configuration files.
I'm facing a problem where installing a certain package (through a dependency), will overwrite a critical config file. Is there a way to monitor whether this file changes (get's overwritten by some package) and restore it's original content?
what would be the best way of achieving this?
This is the class which takes care of configuring /etc/nsswitch.conf:
class nsswitchconfig {
# roll out nsswitch
class { 'nsswitch':
passwd => ['compat'],
group => ['compat'],
hosts => ['files'],
automount => ['files'],
}
notify { "hate #8040": message => "work around bug #8040" }
}
this is the class which overwrites /etc/nsswitch.conf
class desktop {
include nsswitchconfig
$package_name = ["ubuntu-desktop" ]
package { $package_name:
ensure => latest,
}
}
If the nsswitch class configures the file, all you need is to make sure it runs after the class that overrides it.
So in your case:
class { 'nsswitch':
passwd => ['compat'],
group => ['compat'],
hosts => ['files'],
automount => ['files'],
require => Class['desktop'],
}
should do the trick. (note the require part)

Resources