code. grind. sleep.

vendredi 21 octobre 2011

X11 forwarding request failed on channel 0

Quand j'essaye de me logguer sur ma box NetBSD fraichement passé en X.org modular, j'ai ça :

orgrim@serfouette ~ $ ssh rateau 
X11 forwarding request failed on channel 0
Last login: Fri Oct 21 12:20:24 2011 from serfouette.home.orgrim.net

WTF? ça tombe en marche SSH normalement.

Et bien le souci vient de l'échange des magic cookies pour l'authentification entre serveurs X à travers SSH, c'est utilisé par le X11 forwarding et on a besoin de plusieurs choses pour ça :

  • le chemin complet vers xauth sur le client
  • le chemin complet vers xauth sur le serveur
  • Avoir X11Forward yes sur le serveur quand on le demande sur le client (il vaut yes dans le /etc/ssh/ssh_config du client par flemme de taper -X sur la ligne de commande)

Le client est sous Linux, donc pas de soucis le chemin en dur /usr/bin/xauth dans le binaire sshd marche. Par contre pour NetBSD avec du X.org modular, il faut décommenter l'option XAuthLocation dans /etc/ssh/sshd_config et /etc/ssh/ssh_config pour donner le bon chemin vers xauth, comme indiqué en commentaire dans ces deux fichiers :

# If you use xorg from pkgsrc then uncomment the following line.
#  XAuthLocation /usr/pkg/bin/xauth

Enfin, comme le X11Forward est à no par défaut sur NetBSD, je l'ai activé. La vrai solution est de faire ça côté client en utilisant explicitement l'option -X quand on veut ouvrir des fenêtres sur le serveur.

Le pire c'est que Google ne sort rien sur le message "X11 forwarding request failed on channel 0", à part une question sans réponse sur un stackoverflow-like en Russe !

mardi 18 octobre 2011

Quand PostgreSQL n'a plus d'espace disque à manger

Voilà donc une question intéressante, comment se comporte PostgreSQL face à un système de fichier plein ? Un peu d'expérimentation est nécessaire pour se rassurer...

On crée deux systèmes de fichiers de faible taille pour les tests. Le premier stockera PGDATA, ainsi qu'une base de données nommée db_data. Le second sera le tablesapce ts1, dans lequel on créera une base de données db_ts1.

L'objectif est de montrer que seules les transactions modifiant des objets stockés sur des systèmes de fichier plein sont affectées, c'est pourquoi on a besoin de plusieurs tablespaces

Les binaires se trouvent dans /home/pgsql/postgresql-9.0.4, PGDATA dans /home/pgsql/postgresql-9.0.4/data, et le tablespace dans /home/pgsql/postgresql-9.0.4/ts1. On a donc monté et donné la propriété des deux filesystèmes à orgrim, que fera tourner PostgreSQL :

# df -h
...
/dev/mapper/sys-pg1   504M   54M  425M  12% /home/pgsql/postgresql-9.0.4/data
/dev/mapper/sys-pg2   504M   17M  462M   4% /home/pgsql/postgresql-9.0.4/ts1
...

# cd /home/pgsql/postgresql-9.0.4/
# chown orgrim: data ts1
# chmod 700 data ts1

Le cluster est préparé avec l'environnement suivant :

$ env | grep PG
PGPORT=5904
PGDATABASE=postgres
PGDATA=/home/pgsql/postgresql-9.0.4/data
PATH=/home/pgsql/postgresql-9.0.4/bin:$PATH

On lance donc initdb, puis on crée les bases avec le tablespace :

$ initdb
$ psql
psql (9.0.4)
Type "help" for help.

postgres=# CREATE DATABASE db_data;
CREATE DATABASE
postgres=# CREATE TABLESPACE ts1 LOCATION '/home/pgsql/postgresql-9.0.4/ts1';
CREATE TABLESPACE
postgres=# CREATE DATABASE db_ts1 TABLESPACE ts1;
CREATE DATABASE

Ensuite, on se connecte à la base de données db_ts1 et on y crée une base qui permettra de remplir le tablespace ts1 :

$ while ((1)); do psql -c "INSERT INTO t SELECT generate_series(1, 1000) AS i;" db_ts1; done

Au bout, d'un moment le système de fichier du tablespace est plein et tout requête générant des écritures sort en erreur avec un message de cette forme :

ERROR:  could not extend file "pg_tblspc/16385/PG_9.0_201008051/16386/16390": wrote only 4096 of 8192 bytes at block 58438
HINT:  Check free disk space.

Ensuite, on essaye avec le répertoire PGDATA, on crée donc une table dans la base db_data :

$ psql db_data
psql (9.0.4)
Type "help" for help.

db_data=# CREATE TABLE t (i int);
CREATE TABLE

De la même façon, on remplit cette table jusqu'à épuisement de l'espace libre :

$ while ((1)); do psql -c "INSERT INTO t SELECT generate_series(1, 1000) AS i;" db_data; done

Résultat, les requêtes sortent en erreur de la même façon. On a peut-être de la chance ici, le filesystem contenant pg_xlog, les problèmes pourraient être pis.

Il est également possible de remplir le système de fichiers de journaux de transactions, ce qui est problématique du fait que chaque transaction est écrite ici tout tablespace confondu. On vide donc les deux bases :

$ psql db_ts1
psql (9.0.4)
Type "help" for help.

db_ts1=# TRUNCATE t;
TRUNCATE TABLE

$ psql db_data
psql (9.0.4)
Type "help" for help.

db_data=# TRUNCATE t;
TRUNCATE TABLE

Et on place le paramètre checkpoint_segments à 300, valeur démesurée par rapport à la place disponible dans PGDATA.

Après un reload, on refait alors le test de remplissage de la base db_ts1, qui assure que les journaux de transactions seuls remplissent PGDATA.

Le serveur PostgreSQL s'arrête parce qu'il ne peut écrire le journal de transaction :

PANIC:  could not write to file "pg_xlog/xlogtemp.8795": No space left on device
STATEMENT:  INSERT INTO t SELECT generate_series(1, 1000) AS i;
LOG:  server process (PID 8795) was terminated by signal 6: Aborted
LOG:  terminating any other active server processes
WARNING:  terminating connection because of crash of another server process
DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
HINT:  In a moment you should be able to reconnect to the database and repeat your command.
LOG:  all server processes terminated; reinitializing

Il redémarre illico, mais le problème persiste :

FATAL:  the database system is in recovery mode
LOG:  database system was interrupted; last known up at 2011-10-12 00:01:40 CEST
LOG:  database system was not properly shut down; automatic recovery in progress
LOG:  consistent recovery state reached at 0/5FDB7480
LOG:  redo starts at 0/5AA57D68
LOG:  could not open file "pg_xlog/000000010000000000000074" (log file 0, segment 116): No such file or directory
LOG:  redo done at 0/73FFFF90
LOG:  last completed transaction was at log time 2011-10-12 00:05:11.710639+02
PANIC:  could not write to file "pg_xlog/xlogtemp.8797": No space left on device
LOG:  startup process (PID 8797) was terminated by signal 6: Aborted
LOG:  aborting startup due to startup process failure

Le seul moyen de se sortir de cette situation est d'utiliser les 5% d'espace libre du filesystème réservés au super utilisateur, de baisser la valeur de checkpoint_segments à une valeur évitant le filesystem full, les checkpoints successif supprimeront les fichiers en trop.

Lorsqu'on a plus besoin de 5% réservés, il ne faut pas oublier de remettre la réservation.

Enfin, ce cas le plus critique peut arriver assez facilement lorsqu'on a de l'archivage, si le serveur ne peut plus archiver les fichiers WAL, alors il les conserve, un filesystem full sur un espace d'archivage peut donc être transmis au serveur...

vendredi 19 août 2011

Bulk build partiel de pkgsrc

En suivant l'excellent tip de Mr GuiGui2, j'ai pu monter ma petite archi de bulk build personnelle pour fournir du package tout frais à pkgin.

J'ai donc ajouté le bloc magique suivant à mon /etc/mk.conf, qui permet de gérer la présence de commentaires dans pkgchk.conf :

# bulk build config
DEPENDS_TARGET= bulk-install
BATCH=          yes

BULK_PREREQ+=   pkgtools/lintpkgsrc
.if defined(SPECIFIC_PKGS)
PKGLIST!=               awk '$$1 !~ /^\#/ {print $$1}' ${PKGCHK_CONF}
.       for _pkg_ in ${PKGLIST}
HOST_SPECIFIC_PKGS+=    ${_pkg_}
.       endfor
.endif

Pour aller plus loin, j'ai automatisé le process au maximum pour lancer des bulk build réguliers par cron, grâce au script bulk-builder. Ce script remplace do-sandbox-build et do-sandbox-upload, il est également capable de gérer des chemins alternatifs, mettre à jour pkgsrc avant de lancer le bulk.

La procédure pour mettre ça en place est donc :

1. Ajouter le bloc montré plus haut à /etc/mk.conf et y définir PKGCHK_CONF, il s'agit du chemin vers une liste de packages au format "catetgorie/package", un par ligne, qu'on peut automatiquement créer avec pkg_chk -g.

2. Créer la sandbox :

# cd /usr/pkgsrc/mk/bulk
# sh mksandbox --without-x /usr/sandbox

3. Créer et configurer /usr/pkgsrc/mk/bulk/build.conf :

# cd /usr/pkgsrc/mk/bulk
# cp build.conf-example build.conf
# vi build.conf

4. Lancer le bulk build :

# sh bulk-builder -u -R
  • -u demande de cvs up le répertoire /usr/pkgsrc avant de commencer
  • -R demande de ne pas uploader le résultat (les packages)

Enfin, il suffit d'utiliser la ligne suivante pour utiliser les packages avec pkgin, dans /usr/pkg/etc/pkgin/repositories.conf :

file:///usr/pkgsrc/packages/All

jeudi 18 août 2011

Montrer les dépendances avec make dans pkgsrc

Généralement, on peut savoir quelles sont les dépendances d'un package en utilisant make show-depends, mais cela ne montre que les dépendances pour l'installation, les dépendances pour la compilation ne sont pas montrées.

$ cd /usr/pkgsrc/databases/postgresql90-server/
$ make show-depends
postgresql90-client>=9.0.4:../../databases/postgresql90-client

Pour connaître les dépendances selon leur type (installation ou compilation), on peut utiliser la cible show-depends-pkgpaths alliée à la variable DEPENDS_TYPE.

Pour avoir seulement les dépendances de compilation :

$ make DEPENDS_TYPE=build show-depends-pkgpaths
devel/bison
devel/gmake
pkgtools/digest

Pour avoir seulement celles d'installation :

$ make DEPENDS_TYPE=install show-depends-pkgpaths
databases/postgresql90-client

Et enfin pour montrer les deux types, qui est aussi le comportement par défaut :

$ make DEPENDS_TYPE=all show-depends-pkgpaths
databases/postgresql90-client
devel/bison
devel/gmake
pkgtools/digest

$ make show-depends-pkgpaths
databases/postgresql90-client
devel/bison
devel/gmake
pkgtools/digest

Pour plus d'information, le Makefile qui contrôle cette cible est mk/bsd.utils.mk.

mercredi 29 juin 2011

Rediriger stdout/stderr depuis un script avec du pipe

Pour rediriger stdout/stderr à l'interieur vers l'entrée standard d'un commande, il faut utiliser exec et du sous-shell. Cette astuce est un bashisme a priori.

L'objectif est de renvoyer tous les messages du script dans syslog sans mettre de redirection sur la ligne de commande. Le principe général est :

exec FD> >(COMMAND)
  • FD est le numéro du file descriptor, 1 pour stdout, 2 pour stderr
  • COMMAND est la commande a exécuter, elle doit bien sûr lire les données en entrée.

Un plus gros exemple :

SYSLOG="no"
 
# Load configuration file
CONFIG=/etc/myconfig.conf
if [ -f "$CONFIG" ]; then
    . $CONFIG
fi
 
# Redirect output to syslog if configured
if [ "$SYSLOG" = "yes" ]; then
    SYSLOG_FACILITY=${SYSLOG_FACILITY:-local0}
    SYSLOG_IDENT=${SYSLOG_IDENT:-postgres}
 
    exec 1> >(logger -t ${SYSLOG_IDENT} -p ${SYSLOG_FACILITY}.info)
    exec 2> >(logger -t ${SYSLOG_IDENT} -p ${SYSLOG_FACILITY}.err)
fi

avec dans la configuration :

  • SYSLOG : mettre à yes ou no pour activer
  • SYSLOG_FACILITY : ou envoyer
  • SYSLOG_IDENT : avec quel tag

L'exemple est pris d'un de mes scripts d'archivage pour PostgreSQL, ce qui permet de logguer dans syslog sans mettre de pipe dans archive_command (ce qu'il ne faut pas faire parce que ça casse : le code retour donné à PostgreSQL est celui de la dernière commande de la chaîne de pipe)

mardi 21 juin 2011

Combiner des PDF en un seul

Pour combiner des pdf en un seul, on peut essayer pdfjoin fournit par le projet pdfjam. En attendant que les 250 Mo de dépendances (Latex principalement) s'installent, on peut utiliser ghostscript :

gs -sDEVICE=pdfwrite -dNOPAUSE -dQUIET -dBATCH -sOutputFile=../combined_doc.pdf *.pdf

Merci à http://www.perlmonks.org/?node_id=4...

jeudi 7 avril 2011

Retrouver un trigger à partir du nom de la fonction associée

Ici encore, tout est dans le catalogue système de PostgreSQL, il suffit de regarder dans la table pg_trigger.

Avec les jointures qui vont bien, on peut obtenir les informations intéressantes :

SELECT nspname AS schema, relname AS TABLE, tgname AS TRIGGER, proname AS FUNCTION
FROM pg_trigger t
  JOIN pg_class c ON (t.tgrelid = c.oid)
  JOIN pg_namespace n ON (n.oid = c.relnamespace)
  JOIN pg_proc p ON (p.oid = t.tgfoid);

En ajoutant une clause WHERE, on peut facilement retrouver la table associée au trigger :

SELECT nspname AS schema, relname AS TABLE, tgname AS TRIGGER, proname AS FUNCTION
FROM pg_trigger t
  JOIN pg_class c ON (t.tgrelid = c.oid)
  JOIN pg_namespace n ON (n.oid = c.relnamespace)
  JOIN pg_proc p ON (p.oid = t.tgfoid)
WHERE proname = 'mafonction';

jeudi 24 mars 2011

Insérer des tabulations dans sa ligne de commande bash

Il y a longtemps que je me demandais comment faire ça, sans prendre la peine de rechercher ou lire le man. C'est chose faite, pour insérer une tabulation, il faut contourner la complétion de commandes avec le combo suivant :

C-v TAB

C'est simple, mais ça ne s'invente pas.

Pour le coup, c'est utile quand on veut voir un fichier de configuration sans les commentaires, par exemple postgresql.conf :

grep -Ev '^(( |        )*#|$)' postgresql.conf

On doit donc taper une tabulation dans l'expression régulière : on affiche toutes les lignes qui ne satisfont pas la condition « tout ce qui commence par 0 ou plusieurs espaces ou tabulations suivi d'un dièse, ou une ligne vide ».

mardi 15 mars 2011

Voir tous les champs d'une table

Avec PostgreSQL, on peut utiliser la requête suivante pour obtenir la taille de chacune des bases de données d'un cluster :

SELECT datname AS base,
  pg_size_pretty(pg_database_size(oid)) AS taille
FROM pg_database;

Qui donne par exemple :

         base          | taille  
-----------------------+---------
 template0             | 5273 kB
 postgres              | 5385 kB
 redmine               | 9057 kB
 roundcube             | 9153 kB
 template1             | 5369 kB
 dotclear              | 6833 kB
 dspam                 | 204 MB
 exim                  | 5649 kB
 (8 rows)

Mais comment est-ce possible ? on a appliqué la fonction pg_database_size() sur une colonne appelée oid, alors que la définition de pg_database est la suivante :

postgres=# \d pg_database
    Table "pg_catalog.pg_database"
    Column     |   Type    | Modifiers 
---------------+-----------+-----------
 datname       | name      | not null
 datdba        | oid       | not null
 encoding      | integer   | not null
 datcollate    | name      | not null
 datctype      | name      | not null
 datistemplate | boolean   | not null
 datallowconn  | boolean   | not null
 datconnlimit  | integer   | not null
 datlastsysoid | oid       | not null
 datfrozenxid  | xid       | not null
 dattablespace | oid       | not null
 datacl        | aclitem[] | 
Indexes:
    "pg_database_datname_index" UNIQUE, btree (datname), tablespace "pg_global"
    "pg_database_oid_index" UNIQUE, btree (oid), tablespace "pg_global"
Tablespace: "pg_global"

Il n'y a pas de colonne oid dans cette table ! Et pourtant... Cette colonne est tout simplement cachée, mais elle existe bel et bien. Pour vérifier, on recherche donc dans le catalogue système la liste des champs de la table :

SELECT attname, typname, attnum
FROM pg_attribute a
  JOIN pg_class c ON (c.oid = a.attrelid)
  JOIN pg_type t ON (t.oid = a.atttypid)
WHERE relname = 'pg_database';

Qui donne :

    attname    | typname  | attnum 
---------------+----------+--------
 tableoid      | oid      |     -7
 cmax          | cid      |     -6
 xmax          | xid      |     -5
 cmin          | cid      |     -4
 xmin          | xid      |     -3
 oid           | oid      |     -2
 ctid          | tid      |     -1
 datname       | name     |      1
 datdba        | oid      |      2
 encoding      | int4     |      3
 datcollate    | name     |      4
 datctype      | name     |      5
 datistemplate | bool     |      6
 datallowconn  | bool     |      7
 datconnlimit  | int4     |      8
 datlastsysoid | oid      |      9
 datfrozenxid  | xid      |     10
 dattablespace | oid      |     11
 datacl        | _aclitem |     12
(19 rows)

La colonne attnum de pg_attribute indique la position de la colonne, on remarque ainsi qu'il y a sept colonnes avec une position négative. Ces colonnes ne sont pas montrés par la commande \d de psql, ce sont les colonnes système de la table (plus d'information sur ce qu'elles représentent dans la doc)

En plus, on a encore utilisé cette colonne oid pour la retrouver dans la table... Maintenant, on peut être rassuré sur le catalogue système, ce n'est qu'un ensemble de tables, auxquelles on accède en SQL standard...

vendredi 4 mars 2011

pkgsrc, pkg_comp et ccache

Pour utiliser ccache dans un chroot pkg_comp, on commence par installer ccache :

# pkg_comp build devel/ccache
# pkg_add /usr/pkgsrc/packages/All/ccache-3.1.4.tgz

En utilisant la cible package-install dans le chroot, ccache s'y trouve installé. On l'installe aussi sur le système pour surveiller les statistiques plus tard.

Ensuite, on édite le etc/mk.conf du chroot, par exemple /local/pkg_comp/default/etc/mk.conf, pour y définir les variables suivantes :

# ...
# fin de la conf speciale pkg_comp

CCACHE_DIR=${WRKOBJDIR}/.ccache
PKGSRC_COMPILER = ccache gcc

On créé ensuite le répertoire du cache, si le chemin du chroot est /local/pkg_comp/default, avec la variable WRKOBJDIR laissée par défaut :

# mkdir /local/pkg_comp/default/pkg_comp/obj/pkgsrc/.ccache

Ensuite, il suffit de compiler ses packages comme d'habitude.

Enfin, on peut suivre les statistiques du cache avec la commande suivante :

# CCACHE_DIR=/local/pkg_comp/default/pkg_comp/obj/pkgsrc/.ccache ccache -s
cache directory                     /local/pkg_comp/default/pkg_comp/obj/pkgsrc/.ccache
cache hit                            133
cache miss                          3053
called for link                      383
compile failed                        43
preprocessor error                    34
autoconf compile/link                388
unsupported compiler option          216
no input file                         55
files in cache                      6201
cache size                          58.7 Mbytes
max cache size                    1024.0 Mbytes

P.S. : Une doc pour mettre en place un chroot pkg_comp est disponible sur le wiki