Weitere Module- / Manifestbeispiele

Mit folgendem Module kann ein User incl. Gruppe und Gruppenzugehörigkeit angelegt werden. Außerdem wird ihm direkt ein ssh-key hinterlegt:
Zuerst muss der entsprechende Ordner angelegt werden:

class user_shellmann {
        group { 'shellmann':
                ensure => present, 
                gid => 1000
        }       
        user { 'shellmann': 
                ensure => present,
                require    => Group['shellmann'],
                gid => 'shellmann',
                groups => ['sudo', 'cdrom', 'floppy', 'audio', 'dip', 'video', 'plugdev', 'netdev', 'bluetooth',],
                shell => '/bin/bash',
                home => '/home/shellmann',
                purge_ssh_keys => true,
        }
        ssh_authorized_key { 'private':
                user => 'shellmann',
                type => 'ssh-rsa',
                key => 'AAAAB3NzaC1yc2EAAAADAQABAAABAQDSNp/edM111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111',
        }
}

Damit man dem Benutzer z.B. eigene Config Dateien zur Verfügung zu stellen, sollte vorher der Fileserver in Puppet konfiguriert werden.

# This file consists of arbitrarily named sections/modules
# defining where files are served from and to whom

# Define a section 'files'
# Adapt the allow/deny settings to your needs. Order
# for allow/deny does not matter, allow always takes precedence
# over deny
[dotfiles]
        path /mnt/puppet_dotfiles
        allow puppetclient.home

[plugins]
#  allow *.example.com
#  deny *.evil.example.com
#  allow 192.168.0.0/24

Über die allow Direktive kann man den Zugriff reglementieren. Bisher habe ich noch keine Möglichkeit gefunden ganze Netze frei zugeben. Im Netz taucht hier oft allow_ip auf. Dies funktionierte bei meinen Tests aber genau so wenig wie allow.
Die Manifest wird dann wie folgt erweitert:

class user_shellmann {
        group { 'shellmann':
                ensure => present, 
                gid => 1000
        }       
        user { 'shellmann': 
                ensure => present,
                require    => Group['shellmann'],
                gid => 'shellmann',
                groups => ['sudo', 'cdrom', 'floppy', 'audio', 'dip', 'video', 'plugdev', 'netdev', 'bluetooth',],
                shell => '/bin/bash',
                home => '/home/shellmann',
                purge_ssh_keys => true,
        }
        ssh_authorized_key { 'private':
                user => 'shellmann',
                type => 'ssh-rsa',
                key => 'AAAAB3NzaC1yc2EAAAADAQABAAABAQDSNp/edM111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111',
        }
        file {'/home/shellmann/.vimrc':
                ensure => 'file',
                mode => '0660',
                owner => 'shellmann',
                group => 'shellmann',
                source => 'puppet:///dotfiles/user_shellmann/.vimrc',
        }
}

In meiner persönlichen vim config sind ein paar Ordner definiert, die noch nicht existieren. Auch dabei kann uns puppet helfen.

class user_shellmann {
        group { 'shellmann':
                ensure => present, 
                gid => 1000
        }       
        user { 'shellmann': 
                ensure => present,
                require    => Group['shellmann'],
                gid => 'shellmann',
                groups => ['sudo', 'cdrom', 'floppy', 'audio', 'dip', 'video', 'plugdev', 'netdev', 'bluetooth',],
                shell => '/bin/bash',
                home => '/home/shellmann',
                purge_ssh_keys => true,
        }
        ssh_authorized_key { 'private':
                user => 'shellmann',
                type => 'ssh-rsa',
                key => 'AAAAB3NzaC1yc2EAAAADAQABAAABAQDSNp/edM111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111',
        }
        file {'/home/shellmann/.vimrc':
                ensure => 'file',
                mode => '0660',
                owner => 'shellmann',
                group => 'shellmann',
                source => 'puppet:///dotfiles/user_shellmann/.vimrc',
        }
        file { '/home/shellmann/.vim':
                ensure => 'directory',
                owner  => 'shellmann',
                group  => 'shellmann',
                mode   => '0660',
        }
        file { '/home/shellmann/.vim/backup':
                ensure => 'directory',
                owner  => 'shellmann',
                group  => 'shellmann',
                mode   => '0660',
        }
        file { '/home/shellmann/.vim/swap':
                ensure => 'directory',
                owner  => 'shellmann',
                group  => 'shellmann',
                mode   => '0660',
        }
}

Konfiguration von puppet (nodes und manifest)

Weiter geht es mit der Konfiguration der einzelnen Nodes.
Zuerst müssen die Nodes eingetragen werden:

node 'puppetclient.home' {
}

node 'puppetserver.home' {
}

Das bewirkt aber erst mal noch garnichts. Die erste Aufgabe, die wir per puppet erledigen wollen, ist z.B. das Installieren von diversen “Admin Tools”. Dazu müssen wir als erstes ein neues Modul anlegen.

mkdir -p /etc/puppet/modules/admintools/manifests

In dem neu angelegten Verzeichnis erstellen wir nun ein Manifest:

class admintools {
        package { 'tmux': ensure => 'installed' }
        package { 'multitail': ensure => 'installed' }
        package { 'htop': ensure => 'installed' }
        package { 'vim': ensure => 'installed' }
        package { 'sudo': ensure => 'installed' }
        package { 'openssh-server': ensure => 'installed' }
        package { 'vim-puppet': ensure => 'installed' }
}

Das neue Module kann danach dann eingebunden werden:

node 'puppetclient.home' {
    include admintools
}

node 'puppetserver.home' {
    include admintools
}

Weiter geht es im 3. Teil

Installation von puppet

Zum Testen und für erste Gehversuche mit Puppet habe ich mir zwei VMS mit Debian Jessie installiert.
Die Installation von Puppet selbst ist dann sehr einfach.
Auf dem Server muss folgender Befehl ausgeführt werden:

root@puppetserver:~# apt-get install puppetmaster puppet

Das Paket puppet installiere ich mit, da der Server selber auch Client sein sollen.
Auf dem Client muss dann folgendes installiert werden:

root@puppetclient:~# apt-get install puppet

Damit der Client dann den Server auch erreicht muss muss die puppet.conf angepasst werden (gleiches gilt für den Server, wenn er gleichzeitig auch Agent sein soll)

[main]
logdir=/var/log/puppet
vardir=/var/lib/puppet
ssldir=/var/lib/puppet/ssl
rundir=/var/run/puppet
factpath=$vardir/lib/facter
prerun_command=/etc/puppet/etckeeper-commit-pre
postrun_command=/etc/puppet/etckeeper-commit-post
server=puppetserver.home

[master]
# These are needed when the puppetmaster is run by passenger
# and can safely be removed if webrick is used.
ssl_client_header = SSL_CLIENT_S_DN 
ssl_client_verify_header = SSL_CLIENT_VERIFY

Der Agent muss dann aktiviert werden:

root@puppetclient:~# puppet agent --enable

Um für den Client jetzt einen neuen SSL Key und einen Request zu generieren muss folgender Befehl ausgeführt werden:

root@puppetclient:~# puppet agent -t
Info: Creating a new SSL key for puppetclient.home
Info: csr_attributes file loading from /etc/puppet/csr_attributes.yaml
Info: Creating a new SSL certificate request for puppetclient.home
Info: Certificate Request fingerprint (SHA256): 74:FC:D5:F1:1D:94:48:14:8D:44:69:00:F4:F2:08:46:42:3E:25:8F:1A:81:EA:AF:44:98:33:21:0B:AD:AE:18
Exiting; no certificate found and waitforcert is disabled

Zur Erklärung:
Auf dem Puppetserver läuft eine CA. Aus Sicherheitsgründen muss deshalb zuerst am Server ein Zertifikat ausgestellt werden.
Die Wortwahl der Befehle ist im nachfolgenden Beispiel etwas ungüstig.
Mit dem ersten Befehl werden all Request und “Zertifikate” bzw. deren Fingerprint angezeigt. Zertifikate haben ein + als erstes Zeichen
Mit dem zweiten Befehl wird dann ein Request signiert. Befehl drei zeigt dann noch mal alle Zertifikate an.

root@puppetserver:~# puppet cert --list --all
  "puppetclient.home" (SHA256) 74:FC:D5:F1:1D:94:48:14:8D:44:69:00:F4:F2:08:46:42:3E:25:8F:1A:81:EA:AF:44:98:33:21:0B:AD:AE:18
+ "puppetserver.home" (SHA256) A6:17:03:8D:F8:2E:C0:E5:76:49:24:E8:84:4D:EB:91:DB:63:82:45:75:2F:33:60:F6:79:A9:AF:D2:06:1B:E1 (alt names: "DNS:puppet", "DNS:puppet.home", "DNS:puppetserver.home")
root@puppetserver:~# puppet cert sign "puppetclient.home"
Notice: Signed certificate request for puppetclient.home
Notice: Removing file Puppet::SSL::CertificateRequest puppetclient.home at '/var/lib/puppet/ssl/ca/requests/puppetclient.home.pem'
root@puppetserver:~# puppet cert --list --all
+ "puppetclient.home" (SHA256) F2:7A:B7:54:0D:F9:18:EE:0E:17:E5:CF:EB:44:E7:D4:CE:68:75:B9:4D:1E:65:0B:E8:05:A8:5D:97:C8:7D:A8
+ "puppetserver.home" (SHA256) A6:17:03:8D:F8:2E:C0:E5:76:49:24:E8:84:4D:EB:91:DB:63:82:45:75:2F:33:60:F6:79:A9:AF:D2:06:1B:E1 (alt names: "DNS:puppet", "DNS:puppet.home", "DNS:puppetserver.home")

Am Client kann nun das Zertifikat abgeholt werden:

root@puppetclient:~# puppet agent -t
Info: Caching certificate for puppetclient.home
Info: Caching certificate for puppetclient.home
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for puppetclient.home
Info: Applying configuration version '1455277912'
Notice: Finished catalog run in 0.06 seconds

Damit ist die Grundinstallation fertig. Per default meldet sich der Client alle 30 Minuten am Server. Der Client kann von Hand ausgeführt werden, mit entsprechendem Verbose / Debug Output:

root@puppetclient:~# puppet agent --no-daemonize --onetime --verbose --debug

Gleiches kann man natürlich auch mit dem Server / Daemon machen:

root@puppetserver:~# puppet master --no-daemonize --verbose --debug

Um das vim Plugin zu aktivieren, muss es zuerst in den Plugin Ordner des Homesverzeichnisses verlinkt werden:

root@puppetserver:~# mkdir -p /root/.vim/plugin
root@puppetserver:~# ln -s /usr/share/vim/addons/syntax/puppet.vim .vim/plugin/puppet.vim

Außerdem muss die vimrc noch angepasst werden:

syntax on

Weiter gehts im 2. Teil

Arduino Plugin in Eclipse aktivieren

Folgende Programme werden benötigt:

Ich habe beide Pakete (Arduino IDE + Eclipse) in meinem Homesverzeichnis in den Unterordner Tools entpackt.

Damit der User auch Zugriff auf den Arduino hat sollte er den Gruppen tty und uucp hinzugefügt werden:

sudo usermod -a -G tty,uucp shellmann

Danach start man eclipse. Dort muss nun das Plugin installiert werden:

Help => Install New Software

install_pluginHier muss man auf Add klicken.

install_plugin2Die Daten für das Repository wie oben abgebildet eingeben
(URL: http://www.baeyens.it/eclipse/V2)

 install_plugin3Nun kann das Repository über die Drop Down Liste ausgewählt werden.
ACHTUNG: Unten müssen auch die Haken passend gesetzt werden.

Das Plugin kann nun installiert werden. Eclipse muss anschliessend neu gestartet werden. Bei mir kam aber z.B. beim Zugriff auf den “Serial Monitor”  noch eine Fehlermeldung:

java.lang.UnsatisfiedLinkError: Can't load library: /home/user/tools/arduino/lib/librxtxSerial64.so
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1854) at java.lang.Runtime.load0(Runtime.java:795)
at java.lang.System.load(System.java:1062) at it.baeyens.arduino.common.Common.LoadRXTX(Common.java:528)
at it.baeyens.arduino.ui.ArduinoPreferencePage$1.widgetSelected(ArduinoPreferencePage.java:248)
at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:248)
...

Dafür musste ich das Paket dev-java/rxtx nachinstallieren und in den entsprechenden Ordner verlinken.

sudo ln -s /usr/lib64/rxtx-2/librxtxSerial-2.2pre1.so ~/tools/arduino/lib/librxtxSerial64.so

UPDATE:
Alternativ kann man die librxtxSerial auch noch /lib linken:

sudo ln -s /usr/lib64/rxtx-2/librxtxSerial-2.2pre1.so /lib/librxtxSerial64.so

Erste Gehversuche mit dem Arduino und einem HD44780 mit i2c Adapter

Meine ersten Gehversuche mit Arduino waren eher kläglich. Anscheinend habe ich mir eine nicht so ganz einfach Sache vorgenommen:

Der Uno sollte ein 4*20 HD44780 LCD über einen i2c Adapter ansprechen. Wie sich im Nachinein herausgestellt hat, gibt es wohl unterschiedliche Adapter, die dann auch unterschiedlich angesprochen werden.

Zuerst aber mal die Verdrahtung:

i2c AdapterArduino
GNDGND
VCC5V
SDAA4
SCLA5

Als Software wird folgendes benötigt:

WICHTIG: Die Liquid Crystal Library ersetzt die von Arduino vor installiert. d.h. im Ordner libraries der Arduinoinstallation muss zuerst der Ordner LiquidCrystal gelöscht werden. Anschließend wird der gleichnamige Ordner aus dem Liquid Crystal Library Paket dorthin kopiert.

Danach müssen wir zuerst einmal die Adresse des Displays herausfinden. Dazu können wir folgenden Code nutzen. Erklärungen dazu gibt es hier.

Mein kleiner Freund mit der “vielsagenden” Bezeichnung UC-146 hat anscheinend die “default” Adresse 0x27.

IMG_20150529_195841

Anschließend kann man mit folgendem Code Text zum Display schicken:

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// define variables
#define I2C_ADDR 0x27

// Set the pins on the I2C chip used for LCD connections:
//                    addr,    en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(I2C_ADDR, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

// setup
void setup()
{
  lcd.begin(20,4);    // initialize the lcd for 20 chars 4 lines and turn on backlight
  lcd.backlight();   // finish with backlight on
}

void loop()
{
  lcd.setCursor(3,0);
  lcd.print("Hello, world!");
  lcd.setCursor(0,1);
  lcd.print("--------------------");
  lcd.setCursor(1,3);
  lcd.print("http://pcspinnt.de");
}

IMG_20150529_210814

Der Code ist bewusst sehr simpel gehalten. Das eigentlich spannende ist diese Zeile:

LiquidCrystal_I2C lcd(I2C_ADDR, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address

Hier erklärt die Doku der Liquid Crystal Library sehr gut, wofür diese Werte stehen:

Class constructor. Initializes class variables and defines the I2C address of the LCD. The constructor does not initialize the LCD.

Parameters:
lcd_Addr[in]    I2C address of the IO expansion module. For I2CLCDextraIO, the address can be configured using the on board jumpers.
En[in]    LCD En (Enable) pin connected to the IO extender module
Rw[in]    LCD Rw (Read/write) pin connected to the IO extender module
Rs[in]    LCD Rs (Reset) pin connected to the IO extender module
d4[in]    LCD data 0 pin map on IO extender module
d5[in]    LCD data 1 pin map on IO extender module
d6[in]    LCD data 2 pin map on IO extender module
d7[in]    LCD data 3 pin map on IO extender module

Die Pin Belegung des Displays dazu im Vergleich:

01 	GND
02 	+5V
03 	Contrast
04 	RS
05 	RW
06 	E
07 	Data 0
08 	Data 1
09 	Data 2
10 	Data 3
11 	Data 4
12 	Data 5
13 	Data 6
14 	Data 7
15 	+5V
16 	GND

Eine große Hilfe war diese Seite. Hier sind auch die verschiedenen i2c Adapter incl. entsprechendem Code erklärt.

Make your prompt ($PS1) more functional

This is a very simple prompt with only different colors:

PS1="\[\e[0;37m\][\[\e[0;32m\]\u\[\e[0;37m\]@\[\e[0;33m\]\h\[\e[0m] "

snapshot-2014-03-31-23-01-35
Some scripting foo to get a different color for root (for better readability split into multiple lines):

PS1=""
# add user
if [[ ${EUID} == 0 ]]; then 
        PS1+="\[\e[0;31m\]\u"
else
        PS1+="\[\e[0;32m\]\u"
fi
# add @ + host
PS1+="\[\e[0;37m\]@\[\e[0;33m\]\h "

snapshot-2014-03-31-23-31-47
Now adding some brackets and the working directory:

# opening brackets
PS1="\[\e[0;37m\]["
# add user
if [[ ${EUID} == 0 ]]; then 
        PS1+="\[\e[0;31m\]\u"
else
        PS1+="\[\e[0;32m\]\u"
fi
# add @ + host
PS1+="\[\e[0;37m\]@\[\e[0;33m\]\h"
# add working dir
PS1+="\[\e[0;37m\]:\[\e[01;34m\]\w"
# closing brackets + reset 
PS1+="\[\e[0;37m\]]\e[0m "

snapshot-2014-03-31-23-28-33
Now some functionall things.
I’m using the prompt_command to add last exit code to my prompt. Short descriptione from the bash man page:

PROMPT_COMMAND
If set, the value is executed as a command prior to issuing each
primary prompt.

Adding last exit code:

function prompt () {
        exitcode=$?
        # add exit code
        PS1=" "
        if [ $exitcode == 0 ]; then
                PS1+="\[\033[01;32m\]\342\234\223"
        
        else
                PS1+="\[\033[01;31m\]\342\234\227"
        fi

        PS1+="$exitcode "
        # opening brackets
        PS1+="\[\e[0;37m\]["
        # add user
        if [[ ${EUID} == 0 ]]; then
                PS1+="\[\e[0;31m\]\u"
        else
                PS1+="\[\e[0;32m\]\u"
        fi
        # add @ + host
        PS1+="\[\e[0;37m\]@\[\e[0;33m\]\h"
        # add working dir
        PS1+="\[\e[0;37m\]:\[\e[01;34m\]\w"
        # closing brackets + reset 
        PS1+="\[\e[0;37m\]]"
        # reset color
        PS1+="\e[0m "
}
PROMPT_COMMAND='prompt'

snapshot-2014-03-31-23-46-21

Combinig all this stuff with one of my last posts, it could look like this:

function prompt () {
        exitcode=$?
        # add exit code
        PS1=" "
        if [ $exitcode == 0 ]; then
                PS1+="\[\033[01;32m\]\342\234\223"
    
        else
                PS1+="\[\033[01;31m\]\342\234\227"
        fi  
    
        PS1+="$exitcode "
        # opening brackets
        PS1+="\[\e[0;37m\]["
        # add user
        if [[ ${EUID} == 0 ]]; then 
                PS1+="\[\e[0;31m\]\u"
        else
                PS1+="\[\e[0;32m\]\u"
        fi  
        # add @ + host
        PS1+="\[\e[0;37m\]@\[\e[0;33m\]\h"
        # add working dir
        PS1+="\[\e[0;37m\]:\[\e[01;34m\]\w"
        # closing brackets + reset 
        PS1+="\[\e[0;37m\]]"
        # display git branch
        if [ -f /usr/bin/git ]; then
                branch="$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ \(\1\)/')"
                PS1+="$branch"
        fi  
        PS1+=" \$"
        # reset color
        PS1+="\e[0m "
}
PROMPT_COMMAND='prompt'

snapshot-2014-04-01-00-05-11

bash history and a lot of terminals

If you are using many terminals you know the problem, that the bash_history is only written after logging out. So if you want to share commands between two terminals you have to copy and paste them.

Reading the bash man page i found the PROMPT_COMMAND:

PROMPT_COMMAND
    If set, the value is executed as a command prior to issuing each primary prompt.

With this little guy it’s easy. Simple write this to your .bashrc and commands will be written directly to your history:

export PROMPT_COMMAND='history -a'