Preinstall Windows Treiber

Gerade musste ich eine Windows 7 als VM installieren. Da Windows etwas zickig ist, was die Treiber angeht, habe ich mir gedacht, ich installiere die ganzen virtio Treiber schon mal vor, so dass Windows diese dann selber findet und auch benutzen kann.
Schnell mal den Windowsadmin angehauen: “Du sag mal, wie kann ich Windows Treiber vorinstallieren?” Und schon war Ratlosigkeit angesagt. “Äh, vielleicht einfach in einem Ordner ablegen?!?”

Nach ein bischen googeln stellt sich raus, dass es garnicht so schwierig ist. Der (natürlich entpackte Treiber) muss im Explorer in das Verzeichnis %SystemRoot%\inf kopiert werden.

Danach kommt Windows von alleine klar.

Python logging über den syslogd (rsyslog)

In diversen Programmen logge ich gerne unter Umständern sehr viele Daten mit. Gerade für die Fehlersuche finde ich das sehr hilfreich.
Nach verschiedenen Test ist das hier für mich bisher die beste Lösung.

Über das Python logging Module baue ich mir in jedem Programm mit folgender Funktion schnell einen Logger. Rufe ich das Programm dann mit dem Parameter -d auf, wird das Logging direkt auf das debug Level gestellt. Hier exemplarisch unter der Version 3.3:

import argparse
import logging
import logging.handlers


def create_logger():
    # parse commandline arguments
    parser = argparse.ArgumentParser()
    # define arguments
    parser.add_argument("-d", "--debug", help="Run in debug mode.", action="store_true")
    # get args
    args = parser.parse_args()

    # define logger
    my_logger = logging.getLogger('logger')

    # define log level based on commandline arguments
    if args.debug:
        my_logger.setLevel(logging.DEBUG)
    else:
        my_logger.setLevel(logging.INFO)

    # create logging handler
    handler = logging.handlers.SysLogHandler(address='/dev/log', facility=20)

    # define log format
    formatter = logging.Formatter('image_creator [%(process)s]: %(message)s')
    handler.setFormatter(formatter)

    # add handler to logger
    my_logger.addHandler(handler)
    return my_logger

logger = create_logger()
logger.info('info')
logger.warn('warn')
logger.debug('debug')
logger.error('error')

Um in Zeile 24 die facilitiy zu definieren, ist diese Tabelle sehr hilfreich:

Numerical CodeFacilityDescription
0kernkernel messages
1useruser-level messages
2mailkernel messages
3daemonsystem daemons
4authsecurity/authorization messages
5syslogmessages generated internally by syslogd
6lprline printer subsystem
7newsnetwork news subsystem
8uucpUUCP subsystem
9cronclock daemon
10securitysecurity/authorization messages
11ftpFTP daemon
12ntpNTP subsystem
13logauditlog audit
14logalertlog aler
15clockclock daemon
16local0
16local0
16local0local use 0(local0)
17local1local use 1(local1)
18local2local use 2(local2)
19local3local use 3(local3)
20local4local use 4(local4)
21local5local use 5(local5)
21local6local use 6(local6)
22local7local use 7(local7)

Wer dann noch alles in ein extra Log schreiben möchte, kann dies über folgende Änderung in der Datei /etc/rsyslog.conf tun:

local4.*		/var/log/pylogging.log
&~

Die im Script genutzt facility sollte dann natürlich zu der in der rsyslog.conf passen. Die letzten zwei Zeichen &~ sorgen dafür, dass keine weiter Konfiguration ausgewertet wird. D.h. es wird nur in die entsprechende Datei geschrieben.

Dadurch, dass der Systemlogger genutzt wird, muss man sich keine Gedanken mehr über große Logsfiles, Archivierung etc. machen. Diese übernimmt alles der Systemlogger.

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.