Containing a defined resource type in Puppet - puppet

I'm trying to create an instance of a defined resource type (::apt::ppa) that comes before other resources. I am using the PuppetLabs Apt Module.
When adding a new repository via the module, the defined type contains an exec statement that notifies apt::update so that any packages that might be required can be installed correctly. However, when I run my below code, the notify gets scheduled after I attempt to install Java, thereby causing the Java install to fail. I've tried putting anchors around the apt::ppa declaration, but that doesn't help. What else can I do?
class rap::java(
$version = '7',
) {
$package = "oracle-java${version}-installer"
apt::ppa { 'ppa:webupd8team/java': } ->
exec { 'accept-java-license':
command => "/bin/echo ${package} shared/accepted-oracle-license-v1-1 select true | /usr/bin/sudo /usr/bin/debconf-set-selections",
unless => "/usr/bin/debconf-show ${package} | grep 'shared/accepted-oracle-license-v1-1: true'",
} ->
class { '::java':
package => $package,
distribution => 'oracle-jre',
}
file_line { 'java_environment':
path => '/etc/environment',
line => "JAVA_HOME=\"/usr/lib/jvm/java-${version}-oracle\"",
}
}

I believe the issue is that you need to include the apt class within the class you've made to get the ordering right.
This works for me on a new Precise box:
class rap::java(
$version = '7',
) {
$package = "oracle-java${version}-installer"
include apt
apt::ppa { 'ppa:webupd8team/java':
package_manage => true,
}
exec { 'accept-java-license':
command => "/bin/echo ${package} shared/accepted-oracle-license-v1-1 select true | /usr/bin/sudo /usr/bin/debconf-set-selections",
unless => "/usr/bin/debconf-show ${package} | grep 'shared/accepted-oracle-license-v1-1: true'",
}
class { '::java':
package => $package,
distribution => 'oracle-jre',
require => [
Apt::Ppa['ppa:webupd8team/java'],
Exec["accept-java-license"],
]
}
file_line { 'java_environment':
path => '/etc/environment',
line => "JAVA_HOME=\"/usr/lib/jvm/java-${version}-oracle\"",
}
}
Log of run:
Notice: Compiled catalog for precise64 in environment production in 0.78 seconds
Notice: /Stage[main]/Apt/File[preferences]/ensure: created
Notice: /Stage[main]/Rap::Java/Exec[accept-java-license]/returns: executed successfully
Notice: /Stage[main]/Rap::Java/File_line[java_environment]/ensure: created
Notice: /Stage[main]/Apt/Apt::Setting[conf-update-stamp]/File[/etc/apt/apt.conf.d/15update-stamp]/ensure: defined content as '{md5}0962d70c4ec78bbfa6f3544ae0c41974'
Notice: /Stage[main]/Rap::Java/Apt::Ppa[ppa:webupd8team/java]/Package[python-software-properties]/ensure: created
Notice: /Stage[main]/Rap::Java/Apt::Ppa[ppa:webupd8team/java]/Exec[add-apt-repository-ppa:webupd8team/java]/returns: executed successfully
Notice: /Stage[main]/Apt::Update/Exec[apt_update]: Triggered 'refresh' from 1 events
Notice: /Stage[main]/Java/Package[java-common]/ensure: created
Notice: /Stage[main]/Java/Package[java]/ensure: created
Notice: Applied catalog in 39.58 seconds
To extend the question further, generally things that are blockers for a standard setup to run are usually moved into a run stage (documented here).
So I would probably move all of the various repo setup puppet code into pre run stage with other prerequisites (normally you put in repo setup), the run stage will always be run first before the main stage, so you don't have to worry about explictly setting requirements that repos are setup on each package. This makes making changes to repos and prerequisites a lot easier

Related

Puppet can't find class firewall

I have a basic puppet install using this tutorial https://www.digitalocean.com/community/tutorials/how-to-install-puppet-4-on-ubuntu-16-04
When I run /opt/puppetlabs/bin/puppet agent --test on my node I get
Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Error while evaluating a Resource Statement. Could not find declared class firewall at /etc/puppetlabs/code/environments/production/manifests/site.pp:7:1 on node mark-inspiron.
On my node:
/opt/puppetlabs/bin/puppet module list
returns
/etc/puppetlabs/code/environment/production/modules
----- puppetlabs-firewall (v1.9.0)
On my puppet master at /etc/puppetlabs/code/environments/production/manifests/site.pp:
file {'/tmp/it_works.txt': # resource type file and filename
ensure => present, # make sure it exists
mode => '0644', # file permissions
content => "It works on ${ipaddress_eth0}!\n", # Print the eth0 IP fact
}
class { 'firewall': }
resources { 'firewall':
purge => true,
}
firewall { "051 asterisk-set-rate-limit-register":
string => "REGISTER sip:",
string_algo => "bm",
dport => '5060',
proto => 'udp',
recent => 'set',
rname => 'VOIPREGISTER',
rsource => 'true';
}
firewall { "052 asterisk-drop-rate-limit-register":
string => "REGISTER sip:",
string_algo => "bm",
dport => '5060',
proto => 'udp',
action => 'drop',
recent => 'update',
rseconds => '600',
rhitcount => '5',
rname => 'VOIPREGISTER',
rsource => true,
rttl => true;
}
The file part works but not firewall.
You need to install the modules on your master in a master setup with Puppet. They need to be somewhere in your modulepath. You can either place it in the modules directory within your $codedir (normally /etc/puppetlabs/code/modules) or in your directory environment modules directory (likely /etc/puppetlabs/code/environments/production/modules in your case since your cited site.pp is there). If you defined additional module paths in your environment.conf, then you can also place the modules there.
You can install/deploy them with a variety of methods, such as librarian-puppet, r10k, or code-manager (in Enterprise). However, the easiest method for you would be puppet module install puppetlabs-firewall on the master. Your Puppet catalog will then find the firewall class during compilation.
On a side note, that:
resources { 'firewall':
purge => true,
}
will remove any changes to associated firewall configurations (as defined by Puppet's knowledge of the system firewall configuration according to the module's definition of what the resource manages) that are not managed by Puppet. This is nice for eliminating local changes that people make, but it can also have interesting side effects, so be careful.

fail when a file exist in puppet

I am trying to write a puppet script which will install a module by un-tar. I want puppet to fail if it is already un tar. I tried to do below code but it always fails even if directory is absent.
I am checking if /opt/sk is present then fail otherwise proceed on installation.
define splunk::fail($target)
{
$no = 'true'
case $no {
default : { notice($no) }#fail('sk is already installed.')}
}
}
define splunk::forwarder( $filename , $target )
{
file{"$target/sk":
ensure => present
}
splunk::fail{"NO":
target => '/opt/',
require => File[$target],
}
file{"$target/A.tgz":
source => $filename ,
replace => false ,
}
exec{"NO1":
command => "tar xzvf A.tgz" ,
cwd => $target ,
require => File["$target/A.tgz"] ,
}
exec{"Clean":
command => "rm -rf A.tgz" ,
cwd => target ,
require => Exec["NO1"],
}
}
splunk::forwarder {"non":
filename => 'puppet:///modules/splunk/files/NO.tgz' ,
target => '/opt/',
}
Thanks
Define custom_fact and use it combined with fail resource.
In your ruby directory e.g /usr/lib/ruby/vendor_ruby/facter define file tmp_exist.rb with content:
# tmp_exist.rb
Facter.add('tmp_exist') do
setcode do
File.exist? '/root/tmp'
end
end
Next use it in puppet manifest. E.g I combined it with str2bool function from stdlib:
class test {
if !str2bool($::tmp_exist) {
fail('TMP NOT EXIST')
}
if !str2bool($::foo_exist) {
fail('FOO NOT EXIST')
}
}
include test
In /root create only tmp file.
In result you will have:
Error: FOO NOT EXIST at /etc/puppet/deploy/tests/test.pp:8 on node dbmaster
UPDATED: I updated my answer. Chris Pitman was right, my previous solution works only on puppet master or with puppet apply.
I have also found an article describing how to define custom function file_exists in puppet. That also might be helpful.
You should use "creates" attribute of exec, for example:
exec { 'install':
command => "tar zxf ${package}",
cwd => $some_location,
path => $path,
creates => "${some_location}/my_package",
}
Puppet will only execute 'install' if "${some_location}/my_package" doesn't exist.

Only classes can set 'stage'; normal resources like XXX cannot change run stage

I have a manifest where a package depends on an apt::source resource. I've tried to make sure the apt::source runs first by setting a stage:
include apt
stage { 'first':
before => Stage['main']
}
apt::source { 'erlang_repo':
location => 'http://packages.erlang-solutions.com/ubuntu',
repos => 'contrib',
key => 'A14F4FCA',
stage => first
}
package { 'erlang':
ensure => '1:17.3'
}
However, I'm hitting the following error:
==> default: Error: Puppet::Parser::AST::Resource failed with error ArgumentError: Only classes can set 'stage'; normal resources like Apt::Source[erlang_repo] cannot change run stage at /tmp/manifests/default.pp:12 on node vagrant-ubuntu-trusty-64.home
==> default: Wrapped exception:
==> default: Only classes can set 'stage'; normal resources like Apt::Source[erlang_repo] cannot change run stage
==> default: Error: Puppet::Parser::AST::Resource failed with error ArgumentError: Only classes can set 'stage'; normal resources like Apt::Source[erlang_repo] cannot change run stage at /tmp/manifests/default.pp:12 on node vagrant-ubuntu-trusty-64.home
Any pointers will be appreciated.
If you really want to use stages, you should wrap the appropriate resources in (possibly dedicated) classes.
class site::apt_sources {
apt::source { ... }
}
and declare it like
class { 'site::apt_sources': stage => first }
Please note that the use of stages is discouraged.
If you don't use virtual resources, you can probably achieve the desired effect through this relationship instead:
Apt::Source<| |> -> Package<| |>
I decided to go with this in the end:
include apt
Apt::Pin <| |> -> Package <| |>
Apt::Source <| |> -> Package <| |>
apt::source { 'erlang_repo':
location => 'http://packages.erlang-solutions.com/ubuntu',
repos => 'contrib',
key => 'A14F4FCA'
}
package { 'erlang':
ensure => '1:17.3',
}

How can i install a local rpm using puppet

I am trying to install a particular rpm using puppet, my init.pp is:
class nmap {
package {'nmap':
provider => 'rpm',
source => "<Local PATH to the RPM>",
}
}
and the rpm is in ...modules/nmap/files
If i move the rpm to manifests, and provide the rpm name in source => ''
class nmap {
package {'nmap':
provider => 'rpm',
source => "rpm-name.rpm",
}
}
it works, but how can i specify source path with ../files/ and do puppet apply successfully
When i use :
source => 'puppet:///files/nmap-6.45-1.x86_64.rpm',
i get an error:
Debug: Executing '/bin/rpm -i puppet:///files/nmap-6.45-1.x86_64.rpm'
Error: Execution of '/bin/rpm -i puppet:///files/nmap-6.45-1.x86_64.rpm' returned 1: error: open of puppet:///files/nmap-6.45-1.x86_64.rpm failed: No such file or directory
Error: /Stage[main]/Nmap/Package[nmap]/ensure: change from absent to present failed: Execution of '/bin/rpm -i puppet:///files/nmap-6.45-1.x86_64.rpm' returned 1: error: open of puppet:///files/nmap-6.45-1.x86_64.rpm failed: No such file or directory
`
when running the command:
sudo puppet apply --modulepath=/home/user1/qa/puppet_qa/modules/ -e "include nmap" --debug
Unlike the file resource type, the package type has no support for Puppet fileserver URLs. You will need to use a file resource to download the rpm prior to installing it. If this is a recurring problem for you, make a defined type that does those in one go (think macros), e.g.
define fileserver_package($source, $ensure='installed') {
file { "/my/tmp/dir/$name.rpm": source => $source }
package { $name:
ensure => $ensure,
provider => 'rpm',
source => "/my/tmp/dir/$name.rpm",
require => File["/my/tmp/dir/$name.rpm"],
}
}
Edit: it is generally advisable to use a local yum repo instead, see also the first comment by #rojs below.
The RPM package can be installed this way:
package { 'epel-release-6':
provider => 'rpm',
ensure => 'present',
source => '/usr/local/rpms/epel-release-latest-6.noarch.rpm',
}
It seems the module name you are using is nmap. You can use the same source parameter like this,
source => 'puppet:///modules/nmap/nmap-6.45-1.x86_64.rpm',
The syntax to access a file under a module goes like this,
puppet:///modules/<modulename>/<file you want to access>
See this link here, http://docs.puppetlabs.com/puppet/latest/reference/modules_fundamentals.html#files
Lets start from start :
on server:
$rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-pc1-el-7.noarch.rpm
$yum -y install puppetserver
$vi /etc/sysconfig/puppetserver #change JAVA args
$systemctl start puppetserver
$systemctl enable puppetserver
$vi /etc/puppetlabs/puppet/puppet.conf #Add “dns_alt_names” in [master]
On Agent:
$rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-pc1-el-7.noarch.rpm
$yum -y install puppet-agent
$systemctl start puppet
$systemctl enable puppet
$vi /etc/puppetlabs/puppet/puppet.conf # Add “server = pupmaster” in [main]
puppet cert list
puppet cert sign
/etc/puppetlabs/code/environments/production/manifests/site.pp:
node webserver {
class { 'apache': }
}
node dbserver {
class { ‘mysql’: }
}
mkdir –p /etc/puppetlabs/code/environments/production/modules/apache/{manifests, files}
apacheinstall.pp:
class apache::apacheinstall {
if $osfamily == 'redhat' {
package { 'httpd':
ensure => 'latest'
}
service {'httpd':
ensure => 'running',
require => Package["httpd"],
}
file { '/var/www/html/ndex.html':
mode => "0644",
owner => 'root',
group => 'root',
source => 'puppet:///modules/apache/index.html',
}
}
elsif $osfamily == 'debian' {
package { 'apache2':
ensure => 'latest'
}
service {'httpd':
ensure => 'running',
require => Package["httpd"],
}
}
}
INIT.pp
class apache {
notify { 'Installing and Configuring Webserver for $osfamily': }
include apache::mysqlinstall
}
Mysqlinstall.pp:
class apache::mysqlinstall {
exec { 'wget':
path => [ "/bin/", "/sbin/", "/usr/bin/", "/usr/sbin/" ],
command => "/usr/bin/wget https://dev.mysql.com/get/mysql57-community-release-el7-9.noarch.rpm && rpm -ivh /tmp/mysql57-community-release-el7-9.noarch.rpm",
cwd => '/tmp/',
creates => '/etc/firstruns/p1.done',
}
}

Puppet Exec what "<| |>" means?

I'm learning puppet language and noticed one very intriguing line of code: Exec["apt-update"] -> Package <| |> on following context:
class manifest::module {
exec { "apt-update":
command => "/usr/bin/apt-get -y update",
timeout => 3600;
}
package {
["alien", "bc", "libaio1", "unixodbc", "unzip", "rlwrap"]:
ensure => installed;
}
Exec["apt-update"] -> Package <| |>
}
Why Exec is followed by the ->? And most important, what's the meaning of <| |> ???
This expression essentially instructs Puppet to have any package resource require the "apt-update" exec resource. In other words Puppet will be sure to execute apt-get update before installing/purging/... a package.
It matches any package, see http://docs.puppetlabs.com/puppet/latest/reference/lang_collectors.html for more details

Resources