My puppet config is:
class { 'elasticsearch':
java_install => true,
manage_repo => true,
repo_version => '2.x',
version => "2.4.4",
}
elasticsearch::instance { 'es-01': }
After running puppet agent got this error:
Error: Failed to apply catalog: Section "base" is already defined, cannot redefine in /etc/yum.repos.d/centos.repo
Elasticsearch is running on centos-7
This is caused by puppet pre-fetching the yum repos.
If there are more than one repository with the same label you will see your already defined error when puppet is set to use Yumrepo. The error will show the first duplicate alphabetically and abort.
You can reproduce the error following these steps: duplicate a .repo, apply manifest with yumrepo
Initial Repo:
puppet apply -e "yumrepo { 'test': ensure => 'present', baseurl => 'http://test/repourl', descr => 'test' }"
Then duplicate the repo so you have two [test] repos:
cp -p /etc/yum.repos.d/test.repo /etc/yum.repos.d/test2.repo
Now any attempt to use puppet with Yumrepo fails, reproduced below:
# puppet apply -e "yumrepo { 'someapp': ensure => 'present', baseurl => 'http://test/repourl', descr => 'some app' }"
...which yields the following error:
Error: Failed to apply catalog: Section "test" is already defined, cannot redefine in /etc/yum.repos.d/test2.repo
For your error, see which files are duplicating [base]:
grep '^\[base]$' /etc/yum.repos.d/*.repo
Related
I am working on a script that would require passing the Instance profile arn. I have been using puppet to retrieve some information using its facter capability. Below is an (snippet)example of a facter output found online, the full output can be found here (https://gist.github.com/cliff-wakefield/b232ef51799908a0264eb7e95af09092). What I'd like to obtain is the "InstanceProfileArn"
ec2_metadata => {
ami-id => "ami-34281c57",
ami-launch-index => "0",
ami-manifest-path => "(unknown)",
block-device-mapping => {
ami => "/dev/sda1",
root => "/dev/sda1"
},
hostname => "ip-10-180-0-40.ap-southeast-2.compute.internal",
iam => {
info => "{
"Code" : "Success",
"LastUpdated" : "2016-08-28T23:12:36Z",
"InstanceProfileArn" : "arn:aws:iam::750105279227:instance-profile/AnexPrereqs-AnexIAMInstanceProfile-11O8QJAS4XO7S",
"InstanceProfileId" : "AIPAI6YKKPRVVX2XD6LCK"
}"
By running facter ec2_metadata.iam.info, I get:
{
"Code" : "Success",
"LastUpdated" : "2016-08-28T23:12:36Z",
"InstanceProfileArn" : "arn:aws:iam::750105279227:instance-profile/AnexPrereqs-AnexIAMInstanceProfile-11O8QJAS4XO7S",
"InstanceProfileId" : "AIPAI6YKKPRVVX2XD6LCK"
}
However, I am struggling to get the "InstanceProfileArn" printed on the console.
So, two things I want to be able to achieve:
By running facter ec2_metadata.iam.info.<InstanceProfileArn>
from within my instance, I want to be able to see instance profile
arn printed in the console.
Secondly, I understand that the way the above command is passed in
puppet will be slightly different and would look something like
$facts[ec2_metadata][iam][info][InstanceProfileArn]. What
would be the correct syntax to then be passed into puppet manifest?
There is a function called parsejson in the Puppet Forge stdlib module. It can be used to parse a string containing JSON into a Puppet hash. An example using your data:
$ cat Puppetfile
forge "https://forgeapi.puppetlabs.com"
mod "puppetlabs-stdlib", "4.25.1"
$ r10k puppetfile install
$ cat foo.pp
include stdlib
# should be $info_json = $facts[ec2_metadata][iam][info], but for this example
# we'll use a literal...
$info_json = #(INFO)
{
"Code" : "Success",
"LastUpdated" : "2016-08-28T23:12:36Z",
"InstanceProfileArn" : "arn:aws:iam::750105279227:instance-profile/AnexPrereqs-AnexIAMInstanceProfile-11O8QJAS4XO7S",
"InstanceProfileId" : "AIPAI6YKKPRVVX2XD6LCK"
}
INFO
$info = parsejson($info_json)
$instance_profile_arn = $info['InstanceProfileArn']
notice($instance_profile_arn)
$ puppet apply --modulepath=modules foo.pp
Notice: Scope(Class[main]): arn:aws:iam::750105279227:instance-profile/AnexPrereqs-AnexIAMInstanceProfile-11O8QJAS4XO7S
[...]
I am trying to instal node on a fresh vagrant box using puppet however when running the manifest i get the following errors on the box.
Warning: Config file /etc/puppet/hiera.yaml not found, using Hiera defaults
Warning: Scope(Apt::Source[nodesource]): $include_src is deprecated and will be removed in the next major release, please use $include => { 'src' => false } instead
Warning: Scope(Apt::Source[nodesource]): $required_packages is deprecated and will be removed in the next major release, please use package resources instead.
Warning: Scope(Apt::Source[nodesource]): $key_source is deprecated and will be removed in the next major release, please use $key => { 'source' => https://deb.nodesource.com/gpgkey/nodesource.gpg.key } instead.
Warning: Scope(Apt::Key[Add key: 9FD3B784BC1C6FC31A8A0A1C1655A0AB68576280 from Apt::Source nodesource]): $key_source is deprecated and will be removed in the next major release. Please use $source instead.
Error: undefined method `ref' for nil:NilClass on node vagrant-ubuntu-trusty-64.efiling.local
Error: undefined method `ref' for nil:NilClass on node vagrant-ubuntu-trusty-64.efiling.local
My vagrant file looks like this:
config.vm.provision :shell do |shell|
shell.inline = "mkdir -p /etc/puppet/modules;
puppet module install puppetlabs-apt;
puppet module install puppetlabs/nodejs"
end
config.vm.provision "puppet" do |puppet|
puppet.manifests_path = "manifests"
puppet.manifest_file = "default.pp"
end
This is my manifest file:
class { 'nodejs': }
The next part is to get vagrant to run the manifest file but I believe these errors are stopping this from happening.
This is all relatively new to me so looking for some guidance on the issue.
you should replace puppetlabs/nodejs by puppetlabs-nodejs so your Vagrantfile will look like
config.vm.provision :shell do |shell|
shell.inline = "mkdir -p /etc/puppet/modules;
puppet module install puppetlabs-apt;
puppet module install puppetlabs-nodejs"
end
Which version of puppet are you using ? I had to upgrade to newer version on my ubuntu box to make it work, I upgrade to puppet v3.8.4 to make it work - see below the log
==> default: Running provisioner: puppet...
==> default: Running Puppet with default.pp...
==> default: stdin: is not a tty
==> default: Warning: Setting templatedir is deprecated. See http://links.puppetlabs.com/env-settings-deprecations
==> default: (at /usr/lib/ruby/vendor_ruby/puppet/settings.rb:1139:in `issue_deprecation_warning')
==> default: Warning: Config file /etc/puppet/hiera.yaml not found, using Hiera defaults
==> default: Warning: Scope(Apt::Source[nodesource]): $include_src is deprecated and will be removed in the next major release, please use $include => { 'src' => false } instead
==> default: Warning: Scope(Apt::Source[nodesource]): $required_packages is deprecated and will be removed in the next major release, please use package resources instead.
==> default: Warning: Scope(Apt::Source[nodesource]): $key_source is deprecated and will be removed in the next major release, please use $key => { 'source' => https://deb.nodesource.com/gpgkey/nodesource.gpg.key } instead.
==> default: Warning: Scope(Apt::Key[Add key: 9FD3B784BC1C6FC31A8A0A1C1655A0AB68576280 from Apt::Source nodesource]): $key_source is deprecated and will be removed in the next major release. Please use $source instead.
==> default: Notice: Compiled catalog for ubuntu.localdomain in environment production in 0.71 seconds
==> default: Notice: /Stage[main]/Apt/Apt::Setting[conf-update-stamp]/File[/etc/apt/apt.conf.d/15update-stamp]/ensure: defined content as '{md5}0962d70c4ec78bbfa6f3544ae0c41974'
==> default: Notice: /Stage[main]/Apt/File[preferences]/ensure: created
==> default: Notice: /Stage[main]/Nodejs::Repo::Nodesource/Nodejs::Repo::Nodesource::Apt/Apt::Source[nodesource]/Apt::Key[Add key: 9FD3B784BC1C6FC31A8A0A1C1655A0AB68576280 from Apt::Source nodesource]/Apt_key[Add key: 9FD3B784BC1C6FC31A8A0A1C1655A0AB68576280 from Apt::Source nodesource]/ensure: created
==> default: Notice: /Stage[main]/Nodejs::Repo::Nodesource/Nodejs::Repo::Nodesource::Apt/Apt::Source[nodesource]/Apt::Setting[list-nodesource]/File[/etc/apt/sources.list.d/nodesource.list]/ensure: created
==> default: Notice: /Stage[main]/Apt::Update/Exec[apt_update]/returns: E: The method driver /usr/lib/apt/methods/https could not be found.
==> default: Error: /Stage[main]/Apt::Update/Exec[apt_update]: Failed to call refresh: /usr/bin/apt-get update returned 100 instead of one of [0]
==> default: Error: /Stage[main]/Apt::Update/Exec[apt_update]: /usr/bin/apt-get update returned 100 instead of one of [0]
==> default: Notice: /Stage[main]/Nodejs::Install/Package[nodejs]/ensure: ensure changed 'purged' to 'present'
==> default: Notice: Finished catalog run in 29.83 seconds
The SSH command responded with a non-zero exit status. Vagrant
assumes that this means the command failed. The output for this command
should be in the log above. Please read the output to determine what
went wrong.
fhenri#machine:~/project/examples/vagrant/ubuntu$ vagrant ssh
Welcome to Ubuntu 12.04.1 LTS (GNU/Linux 3.2.0-29-virtual x86_64)
* Documentation: https://help.ubuntu.com/
Last login: Thu Nov 19 06:46:10 2015 from 172.16.42.1
vagrant#ubuntu:~$ node -v
v0.6.12
--- This is an alternative method
This took a while to de-bug but the best approach I found to installing node on a server through puppet is to run a manual instal through puppet.
I found this repo, and took what I needed from the manifest file.
class apt_update {
exec { "aptGetUpdate":
command => "sudo apt-get update",
path => ["/bin", "/usr/bin"]
}
}
class othertools {
package { "git":
ensure => latest,
require => Exec["aptGetUpdate"]
}
package { "vim-common":
ensure => latest,
require => Exec["aptGetUpdate"]
}
package { "curl":
ensure => present,
require => Exec["aptGetUpdate"]
}
package { "htop":
ensure => present,
require => Exec["aptGetUpdate"]
}
package { "g++":
ensure => present,
require => Exec["aptGetUpdate"]
}
}
class nodejs {
exec { "git_clone_n":
command => "git clone https://github.com/visionmedia/n.git /home/vagrant/n",
path => ["/bin", "/usr/bin"],
require => [Exec["aptGetUpdate"], Package["git"], Package["curl"], Package["g++"]]
}
exec { "install_n":
command => "make install",
path => ["/bin", "/usr/bin"],
cwd => "/home/vagrant/n",
require => Exec["git_clone_n"]
}
exec { "install_node":
command => "n stable",
path => ["/bin", "/usr/bin", "/usr/local/bin"],
require => [Exec["git_clone_n"], Exec["install_n"]]
}
}
include apt_update
include othertools
include nodejs
I am developing an application with PhP and client asked me to set up a vagrant machine and install every needed extensions and modules, so that with just one Vagrant up command the client will have the same environment as I have,
I firstly installed a vagrant machine from one of the boxes lsit
vagrant box add ubuntu1 http://goo.gl/KwQSa2
Then I run these commands:
vagrant init ubuntu1
vagrant up
in the directory that I made this file there is only a vagranrfile
The Question:
I need to know if I make any changes to my server for example, installing php or mysql how it is going to saved in the setting so that if I just give this file to my client he will be able to have an identical machine to mine with everything installed?
I mean there will be any changes to vagrantfile or I made some mistake and I had to install a machine with puppet?
thanks in advance
No, the vagrant file is not going to change as you install things in the VM.
If you want your client to have the same machine as you, you'll have to avoid installing softwares through the VM's shell. You should only use the provisioner, for everything, even mysql tables, apache virtual hosts etc..
And don't use vagrant box add ubuntu1 http://goo.gl/KwQSa2, add the box's url to the vagrantfile with:
config.vm.box_url = "http://goo.gl/KwQSa2"
Example puppet provisioning for a mysql/php server:
group { 'puppet':
ensure => 'present',
}
#
# Apache configuration
#
class { 'apache' :
default_mods => false,
default_confd_files => false,
mpm_module => 'prefork',
default_vhost => false,
sendfile => 'Off'
}
class { 'apache::mod::php' : } # mod_php
class { 'apache::mod::rewrite' : } # mod_rewrite
# VHost configuration
apache::vhost { 'dev.XXX.fr' :
port => '80',
docroot => '/var/sites/myXXX/web',
access_log => true,
access_log_file => 'XXX_access.log',
error_log => true,
error_log_file => 'XXX_error.log',
aliases => [{alias => '/myXXX', path => '/var/sites/toto/web'}],
directories => [{path => '/var/sites/myXXX/web', 'allow_override' => ['FileInfo', 'Indexes']}, {path => '/var/sites/toto/web', 'allow_override' => ['FileInfo', 'Indexes']}]
}
#
# Mysql configuration
#
class { '::mysql::server' :
root_password => 'XXX',
databases => {
'XXX' => {
ensure => 'present',
charset => 'utf8'
}
},
users => {
'XXX#localhost' => {
ensure => 'present',
password_hash => 'XXX' # XXXmdp
}
},
grants => {
'XXX#localhost/XXX' => {
ensure => 'present',
options => ['GRANT'],
privileges => ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'CREATE'],
table => 'XXX.*',
user => 'XXX#localhost'
}
}
}
class { '::mysql::client' : }
package { 'php5-mysql' :
require => [Class['apache::mod::php'], Class['::mysql::server']],
ensure => 'present'
}
You will need the following modules:
apache
concat
mysql
stdlib
The puppet config above is just for the example, I highly encourage you to read there documentation which is really well done: http://docs.puppetlabs.com/learning/introduction.html
Honestly, puppet is a great tool, take the time to learn it.
One more thing, avoid using the shell provisionner, the commands are executed everytime you run "vagrant provision", puppet only executes changes. (I only use the shell provisionner for apt-get update and apt-get upgrade)
Vagrantfile is a recipe which tells Vagrant how to set up your machine. In a way, it serves as an installation automation tool (and of course does much more as well). If you do any changes to the machine after it was created, Vagrant would not know about that.
What I do is I create Vagrantfile and inside of it I specify a shell script which Vagrant will execute only once, after machine boots the first time.
VAGRANTFILE_API_VERSION = "2"
$bootstrap = <<SCRIPT
# Installing all dependencies and other required software.
# Add "-y" switch to make sure installation is fully automatic.
apt-get install -y python-software-properties
# Any other stuff I might want to do (like edit conf files)
...
SCRIPT
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "precise64"
config.vm.provision "shell", inline: $bootstrap
end
See the doc for config.vm.provision.
I do this inline for convienience, so all configuration is still kept in only one file.
Of course any configuration which is supported directly by Vagrant, is better kept out of this $bootstrap script.
I seem to have run into a syntax error on a previously-working puppet manifest. This is running on a local vagrant box with Ubuntu 12.04, and Puppet version 3.4.2. The puppet stuff was all generated at puphpet.com.
The error I'm getting is:
Error: Could not parse for environment production: Syntax error at '|'
at /tmp/vagrant-puppet/manifests/default.pp:263:29 on node
vagrant.example.com
Line 263 of default.pp is the second line of this snippet:
if count($php_values['ini']) > 0 {
$php_values['ini'].each { |$key, $value|
puphpet::ini { $key:
entry => "CUSTOM/${key}",
value => $value,
php_version => $php_values['version'],
webserver => $php_webserver_service
}
}
}
It looks like you haven't set parser to future.
Run this command:
puppet config print parser
If it returns current, you don't have access to the .each function. To change this, edit /etc/puppet/puppet.conf, and put parser = future under the [main] block. The above command should then return future.
Reference: http://docs.puppetlabs.com/references/latest/function.html#each
I am trying to provision a vagrant VM to allow users to supply their own bash_profile.local but I don't want this file tracked in the vm's vcs repo. I have a tracked bash_profile.local.dist file that they can rename. How can I tell puppet to only create a file if the source file exists? It is currently working correctly but logs an error during provisioning and this is what I'm trying to avoid.
This is the manifest:
class local
{
file { '.bash_profile.local':
source => 'puppet:///modules/local/bash_profile.local',
path => '/home/vagrant/.bash_profile.local',
replace => false,
mode => 0644,
owner => 'vagrant',
group => 'vagrant',
}
}
You could abuse file in this way :
$a = file('/etc/puppet/modules/local/files/bash_profile.local','/dev/null')
if($a != '') {
file { '.bash_profile.local':
content => $a,
...
}
}
This is not exactly what you asked but you can supply multiple paths in the source, so you can have a default empty file if the user didn't supplied his own.
class local
{
file { '.bash_profile.local':
source => [
'puppet:///modules/local/bash_profile.local',
'puppet:///modules/local/bash_profile.local.default'
],
path => '/home/vagrant/.bash_profile.local',
replace => false,
mode => 0644,
owner => 'vagrant',
group => 'vagrant',
}
}
You can try something like this:
file { 'bash_profile.local':
ensure => present,
source => ['puppet:///modules/local/bash_profile.local', '/dev/null'],
path => '/home/vagrant/.bash_profile.local',
before => Exec['clean-useless-file'],
}
exec { 'clean-useless-file':
command => 'rm .bash_profile.local',
onlyif => 'test -s .bash_profile.local',
cwd => '/home/vagrant',
path => '/bin:/usr/bin',
}
If the admin don't make a copy of ".bash_profile.local" available in "modules/local/bash_profile.local", the file resource will use the second source and then create a blank file. Then, the "onlyif" test fails and the exec will remove the useless blank file.
Used this way this code can be a little cumbersome, but it's better than a provisioning failure. You may evaluate if retaining a blank .bash_profile.local file can be okay in your case. I normally use a variation of this, with wget instead of rm, to get a fresh copy of the file from the internet if it was not already made available as a source.
If you're using puppetmaster, be aware you can use it to provision the own server, presenting two versions of the catalog, according to the .bash_profile.local is present or not.