Install NetBSD 5.1 sgimips sur Indy R4000

date
11 / 10 / 2011
comments
0

Il y a quelques mois déjà, un généreux collègue m'a refilé un tas de machines bizarres à des fins ludiques comme celle de réussir à installer un OS récent dessus. Dans mon inventaire des machines exotiques j'ai donc:

Ce billet concerne l'installation de NetBSD 5.1 (la dernière), sur une SGI Indy. Coté exotisme on est comblé :)

Indy

>> hinv
                   System: IP22
                Processor: 100 Mhz R4000, with FPU
     Primary I-cache size: 8 Kbytes
     Primary D-cache size: 8 Kbytes
     Secondary cache size: 1024 Kbytes
              Memory size: 64 Mbytes
                 Graphics: Indy 8-bit
                SCSI Disk: scsi(0)disk(1)
                SCSI Disk: scsi(0)disk(2)
                    Audio: Iris Audio Processor: version A2 revision 4.1.0

Préparation

Pour commencer, impossible d'y brancher un écran à moins d'avoir un connecteur vidéo DB13W3, la machine est pourvue de deux ports série mini din 8 et elle démarre dessus quand il n'y a pas de clavier branché. Très bien, mais si comme moi on a pas de cable Mini DIN 8 vers série (9 ou 25 broches) alors il faut sortir les bobines de fil et s'en faire un, le grand Internet fourmille de doc à ce sujet, moi j'ai trouvé ce schéma très parlant (s/mac/indy):

Mini din 8 - DB9

On se connecte donc et on tombe sur le bios (qui n'a rien à envier à nos bios x86 de 2011), on en profite pour récupérer l'adresse ethernet de la machine:

System Maintenance Menu

1) Start System
2) Install System Software
3) Run Diagnostics
4) Recover System
5) Enter Command Monitor

Option? 5

>>> printenv eaddr
eaddr=08:00:69:06:f4:9b

Let's go

Je suppose que vous savez configurer un serveur tftp/dhcp/nfs. Moi j'ai fait ça sur une machine Debian sauf le serveur dhcp qui est mon routeur FreeBSD:

sudo apt-get install tftpd-hpa bsdtar nfs-kernel-server
mkdir ~/indy
wget ftp://ftp.fr.netbsd.org/pub/NetBSD/NetBSD-5.1/sgimips/installation/netboot/diskimage.tgz
wget ftp://ftp.fr.netbsd.org/pub/NetBSD/NetBSD-5.1/sgimips/binary/sets/kern-GENERIC32_IP2x.tgz
bsdtar xvzf kern-GENERIC32_IP2x.tgz
(sudo mkdir root; cd root; sudo bsdtar xvzpf ../diskimage.tgz)

#/etc/default/tftpd-hpa
TFTP_DIRECTORY = "/home/phil/indy"

#/etc/exports (gruiiik gruiiik)
/home/phil/indy/root/ 192.168.31.0/24(rw,no_subtree_check,all_squash,anonuid=0,anongid=0)

sudo exportfs -r

#dhcpd.conf
host indy {
    hardware ethernet 08:00:69:06:f4:9b;
    fixed-address 192.168.31.8;
    option tftp-server-name "192.168.31.3"; # le serveur tftp (debian)
    next-server 192.168.31.3;               # le serveur nfs (debian)
    filename "netbsd";                      # le nom du kernel à loader en tftp
    option root-path "/home/phil/indy/root";# path racine nfs
}

On retourne configurer notre bios de l'indy:

>> setenv SystemPartition bootp():
>> setenv netaddr 192.168.31.8
>> boot

Mince ça ne marche pas, on fouille partout sur internet pour trouver des infos, puis on finit par lancer un tcpdump pour voir que c'est au niveau tftp que ça coince. Ensuite on lit la doc d'install NetBSD et on y trouve ceci:

 Note that some older bootproms have an interesting bug in reading the
 kernel via TFTP.  They handle the port number as a signed entity, and can
 thus not connect to ports >32767.  You can work around this problem on
 the TFTP server (given that it is a NetBSD host) by using ``sysctl'' to
 set ``net.inet.ip.anonportmin'' and ``net.inet.ip.anonportmax'' to more
 suitable values.  For example:

       # sysctl -w net.inet.ip.anonportmin=16384
       # sysctl -w net.inet.ip.anonportmax=32767

Pour faire la même chose avec linux:

echo "16384 32767" | sudo tee /proc/sys/net/ipv4/ip_local_port_range

Installation

L'installation de NetBSD se passe sans problème. Sauf à la fin où il faut se mettre dans un shell pour taper ces quelques commandes, sans quoi on ne pourra pas démarrer sur le disque

cd /usr/mdec
./sgivol -w boot /usr/mdec/ip2xboot sd0

# => yes

reboot

On reboot sur le disque

Tout est dans la doc d'install, et ça marche(tm). Moi par exemple j'ai installé NetBSD sur le premier disque (sd0):

>> setenv systempartition scsi(0)disk(1)rdisk(0)partition(8)
>> setenv osloadpartition scsi(0)disk(1)rdisk(0)partition(8)
>> setenv osloadfilename netbsd
>> setenv osloadoptions auto
>> setenv osloader boot

Pour les curieux, voyez le dmesg de la machine.

À vous de compiler tout et n'importe quoi, juste pour le plaisir de dire "Hey mec, c'est pas portable ton code là !" :-)

Arduino cli

date
29 / 9 / 2011
comments
0

Je me suis offert une petite carte Arduino avec un Starter Kit de chez SnootLab. J'en suis très content, je suis une bille complète en éléctronique et en seulement 3 jours de documentations et autres tutoriels j'ai déjà quelques bases et j'entrevoie des possibilités infinies liant harware et software.

Seulement, l'IDE officiel d'arduino m'a vite gonflé, je suis très réticent à prendre en main de nouveaux logiciels, surtout quand ils sont graphiques, c'est plus fort que moi, trop de boutons et autres ClickClickClick ça me file des ... boutons. J'ai donc essayé de coder pour arduino en utilisant mon IDE habituel, c'est à dire vim et make, voilà la manip (pour une machine debian)

# La lib arduino http://arduino.cc/en/Main/Software (ici linux x86_64)
wget http://arduino.googlecode.com/files/arduino-0022-64-2.tgz -O - | tar xvzf -
# Le travail est déjà tout fait ici: http://mjo.tc/atelier/2009/02/arduino-cli.html
wget http://mjo.tc/atelier/2009/02/acli/arduino-mk_0.6.tar.gz -O - | tar xvzf -
sudo mkdir -p /usr/local/bin
sudo install -m 755 -o root -g root arduino-mk-0.6/ard-parse-boards /usr/local/bin/

Ensuite copiez le fichier arduino-mk-0.6/Arduino.mk dans votre projet et incluez le dans un Makefile:

TARGET = hello # Le nom du programme final (doit correspondre à un fichier hello.pde)
ARDUINO_DIR = /path/to/arduino-0022
BOARD_TAG = uno # Voir Arduino.mk pour toutes les cartes supportées
ARDUINO_PORT = /dev/ttyACM0          
AVR_TOOLS_PATH = /usr/bin
AVRDUDE_CONF = $(ARDUINO_DIR)/hardware/tools/avrdude.conf
AVRDUDE = $(ARDUINO_DIR)/hardware/tools/avrdude

include Arduino.mk

# Petit alias perso, make com lance cu sur le bon port avec un baud de 9600
com:
    cu -l $(ARDUINO_PORT) -s 9600

Ne pas oublier les outils indispensables:

sudo apt-get install gcc-avr binutils-avr avr-libc libyaml-perl cu

Pour compiler c'est make et pour envoyer le code sur la carte make upload.

Backup zfs

date
23 / 6 / 2011
comments
1

J'ai mis en place un système de backup de mon serveur FreeBSD (dédié) vers un autre serveur FreeBSD (@home). Les deux machines sont en zfs, c'était pour moi l'occasion de tester zfs (send|recv) over ssh. L'idée c'est qu'on envoie les donnés de manière incrémentale entre un snapshot du jour et un snapshot de la veille. Ce que l'on gagne par rapport à des solutions comme rsync c'est de la rapidité et moins d'accès disques (zfs sait exactement ce qui a bougé entre deux snapshot), l'autre avantage c'est sur la machine de backup on a un snapshot par jour, on peut donc facilement retrouver des fichiers supprimés.

#!/bin/sh

set -e

# Used in ssh command, example user@host -p 2222
REMOTE_HOST="diophante"

# Source zfs pool
POOL_SRC="tank"

# zfs sets to backup (relative to POOL_SRC)
SETS="usr/local/vmail usr/local/data usr/local/pgsql/backups usr/home usr/local/git var/backups"

# Destination pool
POOL_DST="tank/backup/${REMOTE_HOST}"

# We use ssh connection sharing
SSH_ARGS="-o ControlPath=~/.ssh/%r@%h:%p"

# zfs snapshot prefix => tank/foo@bck-2011-05-25
PREFIX="bck-"

# Remote zfs command
REMOTE_ZFS="ssh ${SSH_ARGS} ${REMOTE_HOST} sudo zfs"

# Local zfs command
LOCAL_ZFS="sudo zfs"

# Launch master ssh for sharing connections
ssh -MNn ${SSH_ARGS} ${REMOTE_HOST} &
ssh_master_pid=$!

for zfs_set in ${SETS}
do
    # Test if destination exist
    ${LOCAL_ZFS} list -H ${POOL_DST}/${zfs_set} >/dev/null

    date_suffix="${PREFIX}`date +%F`"
    snap="${POOL_SRC}/${zfs_set}@${date_suffix}"
    old_snap=`${REMOTE_ZFS} list -Ht snapshot 2>/dev/null | grep "^${POOL_SRC}/${zfs_set}@${PREFIX}" 2>/dev/null| awk -F' ' '{ print $1 }' 2>/dev/null`
    if [ "${old_snap}" ]
    then

        if [ "${old_snap}" != "`echo ${old_snap} | head -n 1`" ]
        then
            echo "[!] Multiple zfs snapshot found: ${old_snap}"
            echo "[!] Consider changing PREFIX or fix the issue yourself"
            continue
        fi

        if [ "${old_snap}" = "${snap}" ]
        then
            echo "[!] ${snap} exists"
            continue
        fi
    fi
    echo ${REMOTE_ZFS} snapshot "${snap}"
    ${REMOTE_ZFS} snapshot "${snap}"

    if [ "${old_snap}" ]
    then
        extra_args="-i ${old_snap}"
    else
        extra_args=""
    fi

    echo ${REMOTE_ZFS} send $extra_args "${snap}" '|' ${LOCAL_ZFS} recv -F "${POOL_DST}/${zfs_set}"
    ${REMOTE_ZFS} send $extra_args "${snap}" | ${LOCAL_ZFS} recv -F "${POOL_DST}/${zfs_set}"

    if [ "${old_snap}" ]
    then
        echo ${REMOTE_ZFS} destroy "${old_snap}"
        ${REMOTE_ZFS} destroy "${old_snap}"
    fi
done

kill $ssh_master_pid

Le script est aussi disponible sous forme de gist github.

Sur mes deux machines j'ai un user backup qui peut exécuter zfs avec sudo, l'user backup sur la machine de backup peut accéder en ssh à l'user backup (vous suivez ?) sur la machine à sauvegarder au moyen d'une clé ssh dédiée sans mot de passe.

Le script se lance donc sur la machine de backup (en ayant pris soin de créer tous les sets zfs qu'on va sauvegarder). La première fois il va transférer le set en entier, et les jours suivants il va envoyer de l'incrémental, il faut au minimum un jour entre chaque backup mais rien ne vous empêche de mettre l'heure dans le nom du snapshot.

Commentaires, patchs bienvenus.

PS: Ça fait 6 mois que j'ai pas posté sur ce blog, c'est parce que je travaille et même si je trouve encore un peu de temps pour faire mon propre code c'est moins le cas quand il faut le décrire ici. Par contre je maintient une liste de posts à faire sur ce blog, je rattraperais mon retard bientôt.

NanoBSD avec / en nfs

date
3 / 11 / 2010
comments
0

Dans un précédent post j'expliquais comment utiliser le script /usr/src/tools/tools/nanobsd.sh des sources FreeBSD pour construire un système FreeBSD pour l'embarqué.

Dans le processus de création d'un tel système, il peut être utile de tester son système sans utiliser la carte flash. On peut adapter le système en le testant sur NFS et n'écrire l'image finale sur la carte flash que quand on a fini.

kernel

Il faut compiler le kernel avec support NFS et NFS comme système de fichier racine

options NFSCLIENT
options NFS_ROOT

dhcpd.conf

Avec l'option root-path on spécifie le path du montage nfs au client dhcp.

filename "pxeboot";
next-server 192.168.0.20; # le serveur tftpd
option root-path "192.168.0.20:/usr/obj/nanobsd.solo/_.w; # le montage NFS

inetd.conf

Le bootloader pxeboot est récuperé via tftp, lui même activé par inetd

tftp    dgram   udp     wait    root    /usr/libexec/tftpd      tftpd -l -s /tftpboot

pxeboot

On compile pxeboot avec un baud de 115200 sur la sortie série.

cd /usr/src/sys/boot
make BOOT_PXELDR_ALWAYS_SERIAL=1 BOOT_COMCONSOLE_SPEED=115200
mkdir /tftpboot
cp i386/pxeldr/pxeboot /tftpboot

nfs

Juste une ligne dans /etc/exports, 192.168.0.1 étant l'IP donnée par mon serveur dhcp à la machine cible.

/usr/obj/nanobsd.solo/_.w -alldirs -maproot=root 192.168.0.1

rc.conf

On active tout ça dans /etc/rc.conf

 inetd_enable="YES"
 nfs_server_enable="YES"
 rpcbind_enable="YES"
 mountd_flags="-r"
 dhcpd_enable="YES"

Et on démarre les services :

 /usr/local/etc/rc.d/isc-dhcpd start
 /etc/rc.d/inetd start
 /etc/rc.d/rpcbind start
 /etc/rc.d/nfsd start

Maintenant il faut modifier le système généré par NanoBSD car il s'attend à avoir la carte flash comme système de fichier.

J'ai juste crée une fonction dans ma config nanobsd (fonction à enlever quand on crée les images disques bien entendu) :

post_nfsroot {
    rm ${NANO_WORLDDIR}/etc/fstab
    rm ${NANO_WORLDDIR}/conf/default/etc/remount
    echo "" > ${NANO_WORLDDIR}/conf/base/etc/fstab
}

late_customize_cmd post_nfsroot

Voilà, n'oubliez pas l'option -i pour gagner le temps de construction des images disques et bon debug :)

Faire son CDN perso avec nginx

date
15 / 10 / 2010
comments
0

Dans ce billet je vais expliquer comment j'ai mis en place un petit CDN (Content Delivery Network) pour servir du contenu statique (images/css/javascript).

Le problème :

  • Avec une connexion 800kbs envoyer des images ça peut prendre du temps.
  • Sur les sites dynamiques, l'application web envoie souvent des cookies valides pour le domaine en question. Du coup le client envoie son cookie quand il demande le contenu statique du site dynamique, c'est une perte de temps.

La solution :

  • Mettre le contenu statique sur un domaine propre.
  • Plusieurs serveurs peuvent servir ce contenu statique, ainsi le client peut faire des requêtes sur plusieurs serveurs à la fois.

Les moyens que j'ai :

  • Un serveur à Toulouse qui contient les applications dynamiques et le contenu statique (la source), servi par de multiples jails FreeBSD avec un nginx en reverse proxy. aldo.philpep.org
  • Un serveur chez lost-oasis à Marseille, qui fait uniquement du MX et DNS secondaire. d.philpep.org

L'idée

L'idée est dont de servir le contenu statique des sites suivant par mes deux serveurs, sur un domaine sans cookie :

Step one: static.philpep.org

J'ai configuré le domaine avec nginx, pour qu'il serve le contenu statique sur static.philpep.org/$host/$uri

Par exemple http://static.philpep.org/blog.philpep.org/static/ouverta/style.css doit servir http://blog.philpep.org/static/ouverta/style.css.

Pour ça je me suis pas cassé la tête, dans /usr/local/data j'ai des liens symboliques vers le virtual root de chaque virtual host (les dossier étant des points de montage pour les jails FreeBSD qui servent le contenu dynamique)

(phil@aldo.philpep.org ~) % ls -l /usr/local/data/
total 26
drwxr-xr-x  3 root  wheel  212 Oct 14 16:40 awstats
drwxr-xr-x  5 root  wheel    5 Sep 12 02:33 banach
lrwxr-xr-x  1 root  wheel   23 Oct 14 16:41 blog.philpep.org -> cantor/blog.philpep.org
drwxr-xr-x  7 root  wheel    8 Sep 28 15:00 bolzano
drwxr-xr-x  5 root  wheel    5 Oct 14 16:36 cantor
lrwxr-xr-x  1 root  wheel   25 Oct 14 16:40 cerf-gresigne.org -> bolzano/cerf-gresigne.org
lrwxr-xr-x  1 root  wheel   21 Oct 14 16:40 dl.philpep.org -> banach/dl.philpep.org
lrwxr-xr-x  1 root  wheel   19 Oct 14 16:40 dl.wmfs.info -> banach/dl.wmfs.info
drwxr-xr-x  3 root  wheel    4 Oct 14 16:36 fourier
lrwxr-xr-x  1 root  wheel   19 Oct 14 16:41 oujevipo.fr -> bolzano/oujevipo.fr
lrwxr-xr-x  1 root  wheel   18 Oct 14 16:40 philpep.org -> banach/philpep.org
lrwxr-xr-x  1 root  wheel   22 Oct 14 17:09 projects.philpep.org -> fourier/redmine/public
lrwxr-xr-x  1 root  wheel   21 Oct 14 16:41 sica.vaour.net -> cantor/sica.vaour.net
lrwxr-xr-x  1 root  wheel    7 Oct 14 16:40 stats.philpep.org -> awstats
lrwxr-xr-x  1 root  wheel   27 Oct 14 16:41 webmail.philpep.org -> bolzano/webmail.philpep.org
lrwxr-xr-x  1 root  wheel   22 Oct 14 17:09 wmfs.info -> fourier/redmine/public

Et la conf nginx qui va avec :

server {
    listen 80;
    server_name static.philpep.org;
    location ~* \.(ico|png|jpg|jpeg|gif|css|js)$ {
        root /usr/local/data/;
        expires 10y; # 10 ans
        add_header Cache-Control public;
    }
}

Un petit coup de bind pour créer static.philpep.org et ça marche.

Step two: configurer les applications

C'est la partie la plus difficile. Suivant comment est codée l'application ça peut être très long à faire.

  • Pour le blog c'est fait maison et j'avais prévu le coup.
  • Pour redmine facile aussi grâce à au framework rails : il faut mettre ActionController::Base.asset_host = "static.philpep.org/projects.philpep.org" dans config/environments/production.rb
  • Pour dotclear il y a des options dans about:config, le problème c'est les plugins qui ne l'utilisent pas.
  • Pour joomla c'est l'horreur ! J'ai du mettre un preg_replace avec une regexp horrible pour faire du remplacement sur toute la chaine retournée par php.

Step three: nginx cache sur d.philpep.org

Il faut configurer nginx pour faire du proxy cache de static.philpep.org, en gros si le contenu demandé n'est pas dans le cache nginx demande au serveur source aldo.philpep.org, il met en cache et le renvoie au client.

http {

    proxy_cache_path "/usr/local/www/cache/static" levels=1:1:2 keys_zone=STATIC:1000m inactive=1y max_size=1g;
    # Cache pendant 1 an, avec une taille inférieure à 1G.

    upstream aldo {
        server 82.229.137.130:80;
    }
    server {
        listen 80;
        server_name static.philpep.org;
        location ~* \.(ico|png|jpg|jpeg|gif|css|js)$ {
            proxy_pass http://aldo;
            proxy_set_header Host $host;
            proxy_cache_key "$request_uri";
            proxy_cache STATIC;
        }
    }
}

Step four : DNS

static IN A 82.229.137.130 ; aldo.philpep.org
static IN A 212.85.155.53 ; d.philpep.org

Et après ?

  • Regardez votre cache se remplir, et les sites qui sont plus rapides à charger.
  • Configurez nginx pour qu'il fasse de la compression gzip sur le css et le javascript.
  • Regardez comme la configuration du cache est simple, on peut facilement rajouter un noeud dans le cdn.