home » search tags
Die Suche tag = puppet ergab 12 Treffer:

Januar
28
janitor » #useless #puppet #bug
Eigentlich wollte ich nur einen NFS-mount mit Puppet durchführen

mount { '/mnt/code/' :
ensure => 'mounted',
device => 'nfs-server:/mnt/code',
fstype => 'nfs',
options => 'defaults',
atboot => true,
}

und beim ersten Durchlauf des agent wurde auch kein Fehler gemeldet und der mount war vorhanden. Ab dem zweiten Durchlauf trat aber der folgende Fehler auf:
Could not evaluate: Execution of '/bin/mount -o defaults /mnt/code/' returned 32: \
mount.nfs: /mnt/code is busy or already mounted



Grund hierfür ist ein Bug von Puppet im handling der mount-ressource, denn tauscht man den resource identifier von /mnt/code/ zu /mnt/code (also ohne abschließenden /) dann läuft alles sauber durch.

Den passenden Bug kann man hier bei Puppet finden.
Januar
10
janitor » #useless #puppet
Am 24.04. findet in Berlin wieder ein Puppet Camp statt.

Ticket? => Checked!

Hotel? => Checked!

Ich bin gespannt und freu mich.

November
27
janitor » #useless #puppet #code
Puppet ist aktuell das Tool der Wahl für mich, doch leider gibt es etwas das ich schmerzlich vermisse... Puppet versteht kein yum groupinstall.

Was aber wenn man z.B. einen kompletten Desktop nachinstallieren möchte? Alle Pakete per Hand identifizieren und entsprechende Definitionen zu schreiben macht keinen Spaß!
Eine wirklich praktische Lösung dafür konnte ich bei ServerFault finden.

Gehen wir davon aus das wir im Modul gnome u.a. die Paketgruppe basic-desktop installieren wollen, dann muss gnome/lib/puppet/provider/yumgroup/default.rb
Puppet::Type.type(:yumgroup).provide(:default) do
desc 'Support for managing the yum groups'

commands :yum => '/usr/bin/yum'

def self.instances
groups = []

yum_content = yum('grouplist')

collect_groups = false

yum_content.each do |line|
break if line.chomp =~ /Available Groups:/

if collect_groups and line.chomp !~ /(Installed|Available)/
current_name = line.chomp.sub(/^\s+/,'\1').sub(/ \[.*\]/,'')
groups << new(
:name => current_name,
:ensure => :present
)
end

collect_groups = true if line.chomp =~ /Installed Groups:/
end
groups
end

def self.prefetch(resources)
instances.each do |prov|
if resource = resources[prov.name]
resource.provider = prov
end
end
end

def create
yum('-y', 'groupinstall', @resource[:name])
@property_hash[:ensure] == :present
end

def destroy
yum('-y', 'groupremove', @resource[:name])
@property_hash[:ensure] == :absent
end

def exists?
@property_hash[:ensure] == :absent
end

end

und gnome/lib/puppet/type/yumgroup.rb
Puppet::Type.newtype(:yumgroup) do
@doc = "Manage Yum groups

A typical rule will look like this:

yumgroup { 'Development tools':
ensure => present,
}
"
ensurable

newparam(:name) do
isnamevar
desc 'The name of the group'
end

end

erstellt werden.

Anschließend kann man im entsprechenden Manifest auf die ressource yumgroup zugreifen
yumgroup {'basic-desktop': ensure => 'present', }

November
15
janitor » #useless #puppet #code
Sicherlich fragt sich der eine oder andere zu Beginn seiner Puppet-Karriere wie er diese oder jene resource type in sein Modul einbinden kann bzw. wie er diesen definieren muss/kann.

Gerade wenn man bereits laufende Systeme mit Puppet verwalten will, kommt es vor das z.B. ein Benutzer bereits vorhanden oder ein Paket bereits installiert ist. Hier kommt puppet resource zum einsatz.

Gehen wir davon aus das es den Benutzer janitor bereits auf einem System vorhanden ist und wir diesen 1:1 in unserem Modul abbilden wollen... Nach dem Aufruf von
puppet resource user developer

wird der folgende Puppet-Code erzeugt
user { 'developer':
ensure => 'present',
comment => 'developer,,,',
gid => '4711',
groups => ['adm', 'cdrom', 'sudo', 'dip', 'plugdev', 'lpadmin', 'docker'],
home => '/home/developer',
shell => '/bin/bash',
uid => '6666',
}

welcher direkt in ein entsprechendes Modul eingebunden werden kann.
November
5
janitor » #useless #puppet
Kann man Puppet auch ohne einen Master nutzen?

Diese Frage hat sich der eine oder andere sicherlich schon gestellt... die Antwort ist ein klares Ja natürlich!.

Grundsätzlich spricht nichts gegen den Einsatz von Puppet ohne einen zentralen Master (wenn man auf Dinge wie Reporting oder zenrales Management verzichten kann).

Der Vorgang zum erstellen von neuen Modulen ist immer gleich, egal ob diese später über einen Master verwaltet odr lokal ausgeführt werden.

Für das folgende Beispiel gehe ich davon aus das ~/puppet-modules/ unser Basisverzeichnis ist, daher erstellt man hier zwei Verzeichnisse mit mkdir {modules,manifests}

Erstellen wir zuerst das Skelett für unser Module in modules/(nennen wir es testmod) mit puppet module generate testmod. Anschließend sollte folgende Verzeichnisstruktur vorhanden sein
my-testmod
├── Gemfile
├── manifests
│   └── init.pp
├── metadata.json
├── Rakefile
├── README.md
├── spec
│   ├── classes
│   │   └── init_spec.rb
│   └── spec_helper.rb
└── tests
└── init.pp

Nun kann my-testmod/manifests/init.pp editiert werden, um z.B. ein Verzeichnis /root/puppet-test/ von Puppet erstellen zu lassen.
class testmod {

file { 'test directory' :
ensure => 'directory',
owner => 'root',
path => '/root/puppet-test/'
}

}

.
Um dieses Modul nun lokal ausführen zu können muss unter ~/puppet-modules/manifests/ die Datei site.pp mit folgendem Inhalt erstellt werden
node default {

include testmod
}

Um nun das Modul lokal auszuführen genügt
puppet apply manifests/site.pp --modulepath ~/puppet-modules/modules/

Wenn alles ohne Probleme ablief, sollte die Ausgabe wie folgt sein
Notice: Compiled catalog for nodename.local in environment production in 0.09 seconds
Notice: /Stage[main]/Testmod/File[test directory]/ensure: created
Notice: Finished catalog run in 0.04 seconds

und das Verzeichnis /root/puppet-test/ sollte vorhanden sein.
November
5
janitor » #useless #puppet
Um die Netzwerkeinstellungen eins RH-basierenden Systems zu verwalten gibt es das Wunderbare Module Network.

Wer das Module nicht mit puppet module install razorsedge-network installiert, der wird u.U. beim Aufruf des Moduls folgende Fehlermeldung erhalten
err: Could not retrieve catalog \
from remote server: Error 400 on SERVER: Unknown function is_ip_address at ... \
on node ...

Der Grund hierfür liegt in der Abhängigkeit zum Modul stdlib. Dieses kann man (wie immer) am einfachsten mit puppet module install puppetlabs-stdlib auf seinem Puppet-Master installieren.
November
4
Wie hier bereits beschrieben kann man das off. repo von elasticsearch mittels Puppet aktivieren.

Möchte man nun elasticsearch installieren, kann man folgenden Code in seinem Manifest nutzen
package { 'elasticsearch pkg' :
ensure => 'latest',
name => 'elasticsearch',
}



Um die benötigte Abhänigkeit zwischen repo und Paket zu definieren, muss die entsprechende Klasse um
before      => Package['elasticsearch pkg'],

erweitert werden.

Alles zusammen in einem Manifest würde dann wie folgt aussehen
class elasticsearch::install {

include apt

apt::source { 'elasticsearch.list' :
before => Package['elasticsearch pkg'],
location => 'http://packages.elasticsearch.org/elasticsearch/1.3/debian',
repos => 'stable main',
release => '',
key => 'D88E42B4',
key_source => 'http://packages.elasticsearch.org/GPG-KEY-elasticsearch',
include_src => false,
}

package { 'elasticsearch pkg' :
ensure => 'latest',
name => 'elasticsearch',
}

}

November
3
Da elasticsearch passende repos für DEB bzw. RPM zur Verfügung stellt, stellte sich die Frage wie kann ich diese per Puppet einbinden?.

Hierzu bietet Puppet-Labs ein passendes Modul Namens apt an.

Um das repo von elasticsearch auf einem System zu aktivieren, kann folgender Code im entsprechenden Manifest genutzt werden
include apt

apt::source { 'elasticsearch' :
location => 'http://packages.elasticsearch.org/elasticsearch/1.3/debian',
repos => 'stable main',
release => '',
key => 'D88E42B4',
key_source => 'http://packages.elasticsearch.org/GPG-KEY-elasticsearch',
include_src => false,
}

Juni
1
Wie bereits erwähnt kam ich in den Genuß ein 3-tägiges Puppet Training im Linuxhotel zu genießen.

Unterkunft

Das Linuxhotel liegt am Rande von Essen in einer wirklich wundervollen Parkanlage, leider konnte ich den Park nicht ausgiebig genießen da es drei Tage wie aus Eimern gegossen hat... aber ich bin mir sicher das es bei gutem Wetter herrlich sein muss dort zu sitzen und zu IT-Themen zu diskutieren.

Die Zimmer sind praktisch, sauber und super ausgestattet (WLAN, eine Schublade mit Gadgets, zwei Fernseher,...)

Im Linuxhotel herrscht das Motto "SB ist Trumpf", d.h. man kann/darf/muss sich selbst bedienen.

Schulung

Die Schulung selbst wurde von Martin Alfke gehalten und man merkte von der ersten Sekunde an das Martin nicht erst seit gestern mit Puppet arbeitet. ;)

Es handelte sich zwar nur um eine Grundlagenschulung, aber die behandelten Themen waren sowohl für Einsteiger als auch alte Hasen spannend und jeder konnte etwas neues dazulernen.

Der für mich größte AHA-Effekt kam beim Thema puppet parameterized class, nach dessen Abschluß ich feststellen musste das ich 99% meine bisherigen Module in die Tonne klopfen kann und besser nochmal von Null beginne.

Fazit

Sowohl das Hotel als auch die Schulung kann ich ohne Einschränkungen empfehlen.
Dezember
9
janitor » #code #puppet #python
Wie bereits hier und hier beschrieben bietet Puppet eine REST API... abgesehen der Zugriffe mittels curl kann man (natürlich) auch mit Python darauf zugreifen.

Das folgende Script erstellt die gleiche Abfrage wie in Teil1 bzw. Teil2
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
import urllib
import simplejson as json

# --
# config
# --

apiURL = 'https://[PUPPETDB]:8081'
apiPath = 'v2/nodes'
apiKey = '/etc/puppetlabs/puppet/ssl/certs/ca.pem'
apiMethod = 'get'
clientKey = ('/etc/puppetlabs/puppet/ssl/certs/[LOCALNAME].pem',
'/etc/puppetlabs/puppet/ssl/private_keys/[LOCALNAME].pem')

apiQuery = {'query':'["=", "name", "operatingsystem"]'}

def puppetApiRequest(api_base_url, path='',
method=None,
data=None,
params={},
verify=True,
cert=list()):
method = method.lower()
headers = {
'Accept': 'application/json',
'Content-type': 'application/json',
}
methods = {
'get': requests.get,
'post': requests.post,
}

if path[0] != '/':
path = '/{0}'.format(path)
if params:
path += '?{0}'.format(urllib.urlencode(params))
url = '{0}{1}'.format(api_base_url, path)
resp = methods[method](url, data=json.dumps(data), headers=headers,
verify=verify, cert=cert)
return resp

def makePuppetApiRequest(api_url=None,
path=None,
verify=False,
cert=list(),
params={}):
resp = puppetApiRequest(api_url,
path,
apiMethod,
params=params,
verify=verify,
cert=cert)
data = json.loads(resp.content)
return data

output = makePuppetApiRequest(apiURL,
'v2/facts',
apiKey,
clientKey,
apiQuery)

for i in output:
print "%s | %s" % (i['certname'], i['value'])

Dezember
9
janitor » #code #puppet
Wie im letzen Posting beschrieben bietet Puppet eine REST API. Diese kann nicht nur von localhost aus genutzt werden, sondern auch von einem remote host.

Unterschiede sind bei der Art der Verbindung, da eine Abfrage der API auf einem ungeschützen Kanal (http) nur von lokal aus möglich sind, muss bei der Verbindung von remote der SSL Port (8081) genutzt werden. Der angepasste curl aufruf lautet dann wie folgt:

curl -H 'Accept: application/json' \
-X GET https://[PUPPETDB]:8081/v2/facts \
--cacert /etc/puppetlabs/puppet/ssl/certs/ca.pem \
--cert /etc/puppetlabs/puppet/ssl/certs/[LOCALNAME].pem \
--key /etc/puppetlabs/puppet/ssl/private_keys/[LOCALNAME].pem \
--data-urlencode 'query=["=", "name", "operatingsystem"]'



[PUPPETDB] muss durch den DNS des PuppetMaster und [LOCALNAME] durch den DNS des lokalen Clients ersetzt werden.

Da Puppet den Zugriff auf die API per default verweigert, muss der Client in die whitelist auf dem PuppetMaster eingetragen werden, hierzu muss [LOCALNAME] in /etc/puppetlabs/puppetdb/certificate-whitelist eingetragen werden, ansonsten wird zwar eine Verbindung hergestellt, aber mit der Meldung You shall not pass! beendet.
Dezember
6
janitor » #code #puppet
PuppetDB bietet die Möglichkeit mittels einer REST API auf die bestehenden Informationen zu zugreifen.

Um eine Liste aller Betriebssysteme zu erhalten, genügt auf der Shell folgender Aufruf

curl -H 'Accept: application/json' -X GET \
http://localhost:8080/v2/facts \
--data-urlencode 'query=["=", "name", "operatingsystem"]'



Die Ausgabe könnte dann wie folgt aussehen

[ {
"certname" : "host001",
"name" : "operatingsystem",
"value" : "CentOS"
}, {
"certname" : "host002",
"name" : "operatingsystem",
"value" : "CentOS"
}, {
"certname" : "host003",
"name" : "operatingsystem",
"value" : "CentOS"
}, {
"certname" : "host004",
"name" : "operatingsystem",
"value" : "CentOS"
} ]