home » search tags
Die Suche tag = code ergab 24 Treffer:

Dezember
6
janitor » #useless #code #RPM
Auch wenn ich bekennender Debianer bin, komme ich beruflich oft mit RPM-basierenden Distributionen wie CentOS und Red Hat in Kontakt.

Daher war es nur eine Frage der Zeit bis zum bau meines ersten RPM, in diesem Falle durfte es eine neue Version (1.7.7) von Nginx sein, da es CentOS bis heute nicht geschafft hat es zu integrieren (die Installation über das EPEL-Repo schied ebenfalls aus, da hier nur Version 1.0.2 liegt). Desweiteren musste das Module upload-progress-module Bestandteil des Servers sein.

Nun aber der Reihe nach...

benötigte Pakete installieren und Benutzer erstellen

Zuerst müssen die nötigen Pakete für die build-Umgebung mit
yum install -y git rpm-build rpmdevtools redhat-rpm-config make gcc

installiert werden.

Zusätzlich wird für den Bau von Nginx noch folgende Pakete installiert
yum install -y pcre-devel zlib-devel openssl-devel


Da ein build niemals als Benutzer root durchgeführt werden sollten, erstellen wir uns gleich noch einen passenden Benutzer crafter
useradd -s /bin/bash -m -d /home/crafter crafter

den wir für alle weiteren Schritte nutzen werden.

build-Umgebung einrichten

Die benötigte Verzeichnisstruktur
rpmbuild/
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

kann mit dem Befehl
rpmdev-setuptree

erzeugt werden.

Abschließen kann man das setup durch das erstellen einer Macrosdatei
echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros

.

spec-Datei erstellen

Im Verzeichniss ~/rpmbuild/SPECS/ kann nun die entsprechende nginx.spec erstellt werden
Name:		nginx
Version: 1.7.7
Release: 1%{?dist}
Summary: nginx 1.7.7 with upload module

Group: System Environment/Daemons
License: BSD
URL: http://nginx.org/
Source0: http://nginx.org/download/nginx-%{version}.tar.gz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)

BuildRequires: pcre-devel
BuildRequires: zlib-devel
BuildRequires: openssl-devel
Requires: pcre
Requires: zlib
Requires: openssl

%description
nginx version %{version}


#-- prepare build
%prep


#--
%setup -q


#-- build
%build
./configure \
--prefix= \
--conf-path=/etc/nginx/nginx.conf \
--pid-path=/var/run/nginx.pid \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--lock-path=/var/lock/subsys/nginx/lock \
--with-http_ssl_module \
--user=apache \
--group=apache \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--http-scgi-temp-path=/var/run/nginx/scgi/ \
--http-uwsgi-temp-path=/var/run/nginx/uwsgi/ \
--add-module=/home/crafter/rpmbuild/SOURCES/nginx-upload-progress-module \
make %{?_smp_mflags}

#-- make installation
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT

rm -rf $RPM_BUILD_ROOT/html
mkdir -p $RPM_BUILD_ROOT/etc/init.d/
mkdir -p $RPM_BUILD_ROOT/etc/nginx/
mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d
mkdir -p $RPM_BUILD_ROOT/etc/init.d/

#-- clean up
%clean
rm -rf $RPM_BUILD_ROOT


#-- files
%files
%defattr(-,root,root,-)
%doc
/etc/nginx/*
/etc/logrotate.d/*
/sbin/nginx
/etc/init.d/nginx
%changelog

#-- before install
%pre
getent group apache >/dev/null || groupadd -r apache
getent passwd apache >/dev/null || \
useradd -r -g apache -d /var/www -s /sbin/nologin \
-c "webserver user" apache
exit 0

#-- after install
%post
mkdir -p /var/log/nginx
mkdir -p /var/run/nginx
chmod o+x /etc/init.d/nginx
service nginx start

#-- before uninstall
%preun
service nginx stop

#-- after uninstall
%postun


RPM bauen

Nun kann das RPM mit
rpmbuild -v -bb rpmbuild/SPECS/nginx-1.7.7.spec

erstellt werden.
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.
Oktober
29
Tools zum erstellen von Screenshots gibt es wie Sand am Meer, aber alle haben einen entscheidenden Nachteil... sie benötigen einen X-Server (oder zumindest Xvfb).

Was aber wenn man keines von beiden zur Verfügung hat?

Gehen wir mal davon aus das wir den Inhalt der Konsole /dev/tty6 benötigen.

Über die entsprechende virtuale Konsole /dev/vcs6 kann man den Inhalt abrufen und bei Bedarf in eine Textdatei umleiten
cat /dev/vcs6 > /tmp/content_tty6.txt

Oktober
25
Da stolpert man im Netzwerk eines Bekannten über ein altes WD MyBook Live auf dem (lt. WD Webseite) die aktuellste Firmware
MyBookLive 02.43.03-022 : Core F/W

installiert ist... nur um festzustellen das es anfällig für Shellshock ist:
MyBookLive:~# env x='() { :;}; echo verwundbar' bash -c ""
verwundbar
MyBookLive:~#

Wenn man nun noch bedenkt das es sich um ein Debian 5 handelt
MyBookLive:~# cat /etc/debian_version 
5.0.4
MyBookLive:~#

für das kein Support mehr besteht...

Da das System unmöglich in diesem Zustand bleiben konnte hab ich mich daran gemacht und die Bash manuell aktualisiert.

Folgende Schritte waren nötig:

benötigte Pakete installieren
apt-get update && apt-get install build-essential gettext bison


Download der sourcen
wget http://ftp.gnu.org/gnu/bash/bash-3.2.tar.gz
tar zxvf bash-3.2.tar.gz
cd bash-3.2


Download und anwenden aller Patches
for i in $(seq -f "%03g" 1 57); do
wget -nv http://ftp.gnu.org/gnu/bash/bash-3.2-patches/bash32-$i
patch -p0 < bash32-$i
done


Übersetzen und installieren
./configure && make
make install

Oktober
21
janitor » #useless #code #python
Für ein Projekt (u.a. GIS) nutze ich das Tool pythonwhois. Leider kommt es bei manchen Abfragen zur Fehlermeldung.
Exception Type:	UnicodeDecodeError
Exception Value:
'utf8' codec can't decode byte 0xdf in position 706: invalid continuation byte

Der Grund liegt an der fehlerhaften Dekodierung des Rückgabewerts der Abfrage.

Als workaround kann man in pythonwhois/net.py (Zeile 94) die folgende Änderung durchführen:
return buff.decode("utf-8")

ersetzen mit
return buff.decode("utf-8", "replace")

Oktober
18
janitor » #useless #code
Gerne werden im Quellcode die Kommentare #TODO und #FIXME gesetzt um diese zu einem späteren Zeitpunkt (im einfachsten Falle durch die eingesetzte IDE) wieder zu finden.

Hier mal eine kleine Auswahl:

# TODO: give this to a perl guy who knows how to parse perl...

Aus einem Python Projekt.

# TODO: (grr)

OK, damit kann man natürlich viel Anfangen ôO

# FIXME: to be continued...

Na dann...

# FIXME: ... Not sure why. Add a reason here.

Wenn der Autor es nicht sagen kann, wer denn?

Da fällt mir doch glatt wieder diese geniale Statisik der Schimpfwörter im Kernel von Linux ein!
Juni
1
janitor » #useless #code #tooltip
Bei der Einführung von Puppet kommt irgendwann der Punkt an dem auch eigene Software/Scripte ausgerollt werden sollen...

Von der Verwendung des filebucket sollte man aus div. Gründen absehen. Daher stellt sich die Frage wie bekomme ich meinen eigenen Code auf die Systeme?

Zum Glück gibt es FPM (für mich die beste Erfindung seit es geschnittenes Brot gibt).

Damit lassen sich RPM-, DEB-Pakete oder auch Python- und Perlmodule ohne (großen) Aufwand generieren.

Folgendes Beispiel erzeugt ein passendes DEB das sich anschließend ohne Probleme per Hand (oder Puppet) aus dem privaten Repo installieren lässt:

#!/bin/bash

pkgName="um-elasticsearch"
pkgVersion="1.2.0"

debName=$pkgName\_$pkgVersion\_all\.deb

fpm --verbose \
-t deb \
-s dir \
-f \
-C ~/filespace/packages/SRC/ \
--architecture all \
--package ~/filespace/packages/DEB/$debName \
--prefix=/opt/ \
--version $pkgVersion \
--vendor "uselessmouse.de" \
--url "http://uselessmouse.de" \
--workdir ~/filespace/packages/WRK/ \
--depends libc6 \
--depends adduser \
--category web \
--description "Distributed, RESTful Search Engine (Homepage: http://www.elasticsearch.org/)" \
--name $pkgName \
elasticsearch-1.2.0/

April
19
janitor » #useless #python #code
Wann immer man Bytes summiert und Werte wie 32184729924 als Ergebnis bekommt, fragt man sich wieviele MB bzw. GB sind das?

In Python nutze ich in meinem Skripten immer die folgende Funktion

import math

def convertSize(size):
size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
i = int(math.floor(math.log(size,1024)))
p = math.pow(1024,i)
s = round(size/p,2)
if (s > 0):
return '%s %s' % (s,size_name[i])
else:
return '0B'



Wann immer ich einen Wert in eine benutzerfreundliche Form bringen will/muss genügt der Aufruf

convertSize(float("32184729924"))



und erhalte als Rückgabewert 29.97 GB
März
27
Was macht man nun mit seiner frischen Installation von elasticsearch?

Als kleines Beispiel habe ich einen Indexer erstellt, der ein definiertes Verzeichnis nach Dateien durchsucht und deren Inhalt in ES ablegt.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import magic
import os
import elasticsearch
from datetime import datetime

indexName = "local-fs"

baseDir = "/home/user"

wantedMime = ['text/x-python', 'text/x-perl', 'text/x-shellscript', 'text/plain']

#-- initialize elasticsearch connection
es = elasticsearch.Elasticsearch("localhost:9200")

#-- read given directory
for dirName, dirNameList, fileNameList in os.walk(baseDir):
for fileName in fileNameList:
filePath = os.path.join(dirName, fileName)
#-- guess file/mime type
mimeType = magic.from_file(filePath, mime=True)
#-- if mimetype is wanted
if mimeType in wantedMime:
#-- read content
with open(filePath, 'r') as infile:
filedata = infile.read()
#-- write everything to elasticsearch
es.index(index=indexName,
doc_type="fs",
body = {
"timestamp": datetime.now(),
"filename": fileName,
"filepath": dirName,
"mimetype": mimeType,
"content": filedata,
})



Das benötigte Pythonmodul magic lässt sich wie immer einfach per pip installieren

sudo pip install python-magic



Wie kommt man aber wieder an die gespeicherten Daten ran? Ein einfacher/schneller weg ist curl

Möchte man z.B. alle Dokumente mit dem mimetype python sehen, genügt der folgende Aufruf:

curl -XGET 'http://localhost:9200/local-fs/_search?pretty' -d \
'{"query":{"bool":{"must":[{"query_string":{"default_field":"fs.mimetype","query":"python"}}],\
"must_not":[],"should":[]}},"from":0,"size":50,"sort":[],"facets":{}}'

März
21
Da ich in den letzten Wochen/Monaten mich verstärkt dem Thema Logstash/Elasticsearch gewidmet habe, hier nun eine kleine Anleitung zur Installation eines Basis-/Testsystems.

Die Konfiguration von ES für den Livebetrieb sind u.U. umfangreich und abhängig von der vorhandenen Hardware und dem geplanten Einsatz.

Die aktuellste Version von ES kann man auf deren Webseite finden. Bei der hier genutzten Version handelt es sich um Version 1.0.1

Der Download klappt am einfachsten direkt per wget
wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.0.1.tar.gz



Anschließend kann man das Paket entpacken

tar xfz elasticsearch-1.0.1.tar.gz



Da ich meist mit verschiedenen Versionen arbeite, möchte ich über cd /opt/elasticsearch/ immer im passenden Verzeichnis laden, daher lege ich einen symbolischen Link an

ln -s elasticsearch-1.0.1/ /opt/elasticsearch



Die konfiguration von ES geschieht über die Datei elasticsearch/config/elasticsearch.yml und ist aufgrund der ausführlichen Dokumentation quasi selbsterklärend. Für das Testsystem ist das anpassen der folgende Parameter ausreichend

cluster.name: Jedi
node.name: "Yoda"



Um keinerlei externe Zugriffe zu ermöglichen, kann man noch den folgenden Parameter anpassen

network.host: 127.0.0.1



Nun kann man ES starten (ich starte es in einem screen)

screen -S elasticsearch /opt/elasticsearch/bin/elasticsearch



Die folgende Meldung zeigt an, das ES erfolgreich gestartet wurde

...
[2014-03-21 14:17:06,378][INFO ][node] [Yoda] started



Kontrollieren kann man es (nach STRG a + d um den screen abzuhängen) mittels netstat -tulpen | grep 9200
tcp6    0    0 127.0.0.1:9200    :::*    LISTEN    1000    3948810    5483/java



oder im Browser über die URL http://localhost:9200

{
"status" : 200,
"name" : "Yoda",
"version" : {
"number" : "1.0.1",
"build_hash" : "5c03844e1978e5cc924dab2a423dc63ce881c42b",
"build_timestamp" : "2014-02-25T15:52:53Z",
"build_snapshot" : false,
"lucene_version" : "4.6"
},
"tagline" : "You Know, for Search"
}

Februar
18
Wie hier bereits erwähnt möchte ich gerne wissen wenn ein Zombie sein Unwesen auf eines meiner Systeme treibt, daher habe ich einen passenden check für Nagios geschrieben...

Wie immer kann man die aktuellste Version in meinem öff. GIT repo finden.
Februar
17
Da ich auf den alternativen logshipper beaver setzte, nutze ich einen Nagioscheck um zu überprüfen ob dieser Dienst noch läuft.

Der check wird wie folgt aufgerufen:

./check_beaver -P /var/run/beaver.pid



Wie immer kann man diesen check im passenden GIT repo finden.
Februar
14
In einer Umgebung mit vielen RedHat-Installation möchte man gerne den Überblick behalten ob auch wirklich alle Systeme im RHN angemeldet sind.

Hierfür habe ich einen check für Nagios erstellt, der genau dieses automatisch prüft.

Die aktuellste Version kann man in meinem GIT finden.
Februar
12
janitor » #useless #code
Beim erstellen eines Checks für Nagios der auf einem System nach Zombies ausschau hält, ist mir aufgefallen das es keine (einfache) Möglichkeit mit Linuxboardmitteln gibt einen solchen Prozess zu generieren.

Also hab ich kurz folgenden Code genutzt:

#include <stdlib.h>
#include <sys>
#include <unistd.h>

int main ()
{
pid_t child_pid;

child_pid = fork ();
if (child_pid > 0) {
sleep (60);
}
else {
exit (0);
}
return 0;
}



Übersetzt werden kann es mit cc zombie.c -o zombie
Januar
31
janitor » #useless #code #python
Wer auf seinem System fail2ban betreibt um unliebsame Besucher zu blockieren kann sich mit ein paar Zeilen Pythoncode eine Übersicht generieren lassen, welche Adressen wieoft blockiert wurden

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re
import operator

f2bLog = "/var/log/fail2ban.log"
f = open(f2bLog, "r").readlines()

addrList = {}

for i in f:
if re.search(r'Ban', i):
line = i.strip()
date, time, info, severity, module, action, addr = line.split(' ')
if not addr in addrList:
count = 1
addrList[addr] = count
else:
addrList[addr] = count + 1

allAddr = sorted(addrList.iteritems(), key=operator.itemgetter(1), reverse=True)

print 10*"="
print " ALL BANNED IPs"
print 10*"="

for i in allAddr:
print "%16s => %s" % (i[0], i[1])
print 10*"="



Die Ausgabe wäre dann z.B.

==========
ALL BANNED IPs
==========
212.122.xxx.xxx => 6
208.97.xxx.xxx => 6
88.247.xxx.xxx => 4
90.145.xxx.xxx => 2
105.236.xxx.xxx => 2
89.216.xxx.xxx => 1


Die xxx in der Adresse wurden von mir manuell eingesetzt
Dezember
20
janitor » #useless #code #php
Da ich privat kein PHP nutze, aber beruflich zur Kombination von PHP/PHP-FPM gezwungen bin, liest sich der Artikel zu HHVM wirklich spannend.

Beeindruckend finde ich folgenden Vergleich:

PHP-FPM: 23,17 Requests pro Sekunde
HHVM+FastCGI: 949,21 Requests pro Sekunde


Da es fertige Pakete für Debian gibt, muss ich das mal in meinem kommenden Urlaub testen.
Dezember
19
Nutzt man matlib um Grafiken zu erzeugen, kann es vorkommen das man mit folgender Fehlermeldung "belohnt" wird

no display name and no $DISPLAY environment variable



Der Grund liegt in der Tatsache das matlib versucht nach dem erstellen des Bildes dieses mittels .show() anzuzeigen, was bei einer Webanwendung nur bedingt Sinn ergibt.
Abhilfe schafft die Wahl des passenden backends, in diesem Falle Agg beim import von matlib

import matplotlib

matplotlib.use('Agg')



Wichtig hierbei ist, das vor allen anderen Zuweisungen das backend ausgewählt wird.
Dezember
11
janitor » #code #python
Wie überprüfe ich (unter Linux) mit Python ob z.B eine Festplatte eingehängt ist und ob die Berechtigung passt? Hierfür bietet Python zwei passende Module an, zum einen os und zum anderen stat

Prüfen wir zunächst ob der mountpoint vorhanden ist

>>> import os
>>> os.path.ismount('/')
True



Scheinbar ist / vorhanden (da True), dann schauen wir uns mal die Berechtigung an

>>> import os, stat
>>> os.stat('/')
posix.stat_result(st_mode=16877, st_ino=2, st_dev=65024L, \
st_nlink=26, st_uid=0, st_gid=0, st_size=4096, st_atime=1386747118,\
st_mtime=1384790336, st_ctime=1384790336)



Die genaue Erläuterung der einzelnen Wert kann man hier nachlesen, für uns ist st_mode von Interesse.

>>> import os, stat
>>> os.stat('/').st_mode
16877



Die Ausgabe von 16877 ist nun nicht unbedingt das erwartete Ergebnis, daher muss das Ergebnis durch S_IMODE gewandelt werden.

>>> import os, stat
>>> stat.S_IMODE(os.stat('/').st_mode)
493



Eine Berechtigung von 493 scheint eher unwahrscheinlich, Daher werfen wir mal einen Blick in die Dokumentation des Modul stat und finden folgendes:

stat.S_IMODE(mode)
Return the portion of the file’s mode that can be set by os.chmod()—that is,
the file’s permission bits, plus the sticky bit, set-group-id, and set-user-id
bits (on systems that support them).


Die Lösung ist oct
>>> import os, stat
>>> oct(stat.S_IMODE(os.stat('/').st_mode))
'0755'

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"
} ]

November
27
janitor » #code #python
Hier und da will man einfach wissen (wieso auch immer) welcher epoch die letzte Mitternacht entspricht, in python kann man das z.B. mit der folgenden Funktion realisieren:

import datetime
import time

def getMidnight():
now = datetime.datetime.now()
year = now.year
month = now.month
day = now.day
hour = "00"
minute = "00"
epoch = datetime.datetime(year, month, day, 0, 0).strftime('%s')
return epoch

November
25
janitor » #useless #code #git
Da ich (wie wohl die meisten) meine Projekte mittels GIT verwalte, war ich in den letzten Wochen auf der Suche nach einem passenden Provider.

Natürlich kommt man früher oder später zu GitHub da man hier aber nur gegen Bezahlung private Repos erstellen kann, habe ich mich entschlossen selbst einen solchen Server auf uselessmouse.de zu betreiben.

Hierzu nutze ich GitLab, was sich in keinster Weise hinter GitHub verstecken muss.

Aktuell bin ich noch beim Setup, aber in Zukunft wird man unter git.uselessmouse.de meine Projekte finden.

Sollte jemand Interesse am hosting von eigenen Projekten haben (public oder auch privat), einfach eine kurze Nachricht an mich schicken.