Archives pour juillet, 2013

Bind : serveur DNS en forward uniquement (cache DNS)

root@srv-beta:~# nano /etc/bind/named.conf.options
options {
        [...]

        forward only;
        forwarders { 10.0.2.221; 10.0.2.222; };

        [...]
};

Apache : désactiver l’authentification pour un sous-répertoire spécifique

<Directory /var/www/>
   AuthUserFile /etc/apache2/user-passwd
   AuthType Basic
   AuthName "Restricted access"
   Require valid-user
   Order allow,deny
   Allow from 192.168.0
   Satisfy any
</Directory>

<Directory /var/www/public>
   Order allow,deny
   Allow from all
   Satisfy any
</Directory>

Munin : configuration en mode asynchrone

La version 2 de Munin apporte un nouveau mode de récupération des données entre le master et ses nodes : le mode asynchrone. Celui-ci vise à corriger deux situations critiques à savoir :

  • lorsque le nombre de nodes à monitorer est important, le temps de récupération des données depuis les nodes est supérieur à celui de mise à jour.
  • lorsque les nodes sont distants, les connexions peuvent finir en timeout du fait d’une ligne lente ou d’un trop grand nombre d’éléments monitorés.

Dans les deux cas, le monitoring est impossible. Toutefois, ces contraintes sont levées en activant le mode asynchrone. Un démon supplémentaire munin-asyncd est alors lancé sur chaque node, dont le rôle est de se connecter à munin-node pour récupérer et stocker temporairement les résultats au format texte. Le serveur munin se contente ensuite de récupérer ces fichiers par connexion SSH pour en générer les fichiers RRD.

Je présente ici la configuration d’un node en asynchrone.

Configuration du node

root@node:~# apt-get install munin-node munin-async munin-plugins-extra

Seule l’écoute réseau en local est nécessaire :

root@node:~# nano /etc/munin/munin-node.conf
listen 120.0.0.1
allow ^127\.0\.0\.1$

Le node est prêt pour être démarré ; munin-asyncd doit être lancé à la suite  :

root@node:~# /etc/init.d/munin-node restart && /etc/init.d/munin-async restart

Configuration du serveur

root@server:~# apt-get install munin

Les clés SSH de l’utilisateur munin doivent être générées afin que celui-ci puisse se connecter en tant que munin-async sur le node :

root@server:~# su -s /bin/bash munin
munin@server:~$ ssh-keygen -t rsa
munin@server:~$ ssh-copy-id munin-async@node

L’utilisateur munin peut alors se connecter sur le node. La première connexion SSH doit être faite manuellement afin de valider la confirmation (ne pas le faire bloque la récupéreration des données) :

munin@server:~$ ssh munin-async@node

Par sécurité, je vous invite à restreindre la connexion SSH sur le node :

  • en insérant une ligne de ce type dans le fichier /etc/security/access.conf :
    +munin-async : [IP_SRV_MUNIN]
    
  • limiter la connexion SSH de l’utilisateur munin à ne pouvoir exécuter que la commande munin-async :
    munin-async@node$ nano .ssh/authorized_keys
    
    no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,command="/usr/share/munin/munin-async --spoolfetch" ssh-rsa [PUBLIC KEY]
    

Vous pouvez relancer la connexion SSH, munin-async prend la main comme shell. Ceci validera au final la configuration réseau. Reste à déclarer ce node au niveau du master :

root@server:~# nano /etc/munin/munin-node.conf
[node]
   address ssh://munin-async@node

Patientez quelques minutes (dix minutes) pour que les graphes soient visibles.

Linux : vérifier l’entropie en temps réel

root@srv:~# watch --interval 0.1 cat /proc/sys/kernel/random/entropy_avail

Debian : afficher l’origine des packages installés

La commande apt-show-versions fait le job :

root@vks10205:~# apt-get install apt-show-versions

Par exemple, pour afficher les packages installés depuis testing :

root@vks10205:~# apt-show-versions|grep testing
libc-dev-bin/testing uptodate 2.17-7
libc6/testing uptodate 2.17-7
libc6-dev/testing uptodate 2.17-7
libfontconfig1/testing uptodate 2.10.2-2
libgd3/testing uptodate 2.1.0-2
libhtml-parser-perl/testing uptodate 3.71-1
libopendbx1/testing uptodate 1.4.6-3
libopendbx1-mysql/testing uptodate 1.4.6-3
libopendbx1-sqlite3/testing uptodate 1.4.6-3
libopendkim9/testing uptodate 2.8.3-1
libopendmarc1/testing uptodate 1.1.3-1
librbl1/testing uptodate 2.8.3-1
libtiff4/testing uptodate 3.9.7-1
libvbr2/testing uptodate 2.8.3-1
libvpx1/testing uptodate 1.2.0-2
libx11-6/testing uptodate 2:1.6.0-1
libx11-data/testing uptodate 2:1.6.0-1
libxau6/testing uptodate 1:1.0.8-1
libxcb1/testing uptodate 1.9.1-3
locales/testing uptodate 2.17-7
nginx/testing uptodate 1.4.1-3
nginx-common/testing uptodate 1.4.1-3
nginx-full/testing uptodate 1.4.1-3
opendkim/testing uptodate 2.8.3-1
opendmarc/testing uptodate 1.1.3-1

Nginx : support des Etags

Depuis sa version 1.3.3, Nginx intégre enfin le support des Etags. Ca tombe bien la version 1.4.1 est disponible dans les backports Wheezy et les packages Dotdeb Squeeze/Wheezy. Il n’est donc plus nécessaire d’utiliser un module dédié comme celui-ci.

Mise en place

Il est nécessaire d’ajouter l’option d’activation dans la directive http, server ou location. Ainsi, pour une application globale :

http {
   [...]

   etag on;
}

Test

bhuisgen@muse:~$ wget --no-check-certificate --spider --server-response https://localhost/backuppc/image/logo.gif
Spider mode enabled. Check if remote file exists.
--2013-07-18 12:35:59--  https://localhost/backuppc/image/logo.gif
Resolving localhost (localhost)... 127.0.0.1
Connecting to localhost (localhost)|127.0.0.1|:443... connected.
WARNING: The certificate of ‘localhost’ is not trusted.
WARNING: The certificate of ‘localhost’ hasn't got a known issuer.
HTTP request sent, awaiting response...
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 18 Jul 2013 10:36:00 GMT
Content-Type: image/gif
Content-Length: 1394
Last-Modified: Fri, 07 Jun 2013 10:44:12 GMT
Connection: keep-alive
ETag: "51b1b97c-572"
Accept-Ranges: bytes
Length: 1394 (1.4K) [image/gif]
Remote file exists.

Nginx : exécution FastCGI Perl

Je vous joins ici la dernière version des scripts que j’utilise pour permettre l’exécution Perl en FastCGI avec Nginx (pour SmokePing, BackupPC, etc …)

Le script du démon Perl fcgi-perl.pl est à adapter à votre environnement système (utilisateur d’exécution, chemin de la socket UNIX). Le script de démarrage est à présent intégrable avec Heartbeat/Corosync …

Dépendances logicielles

root@muse:~# aptitude install libfcgi-perl libfile-pid-perl

Script FastCGI Perl

root@muse:~# cat /etc/nginx/fcgi-perl.pl
#!/usr/bin/perl
#
# FastCGI perl daemon
#
# Boris HUISGEN <bhuisgen@hbis.fr>
#

my ($pid_file) = "/var/run/fcgi-perl.pid";       # PID filename
my ($socket_file) = "/var/run/fcgi-perl.sock";   # UNIX socket filename
my ($socket_backlog) = 10;                       # socket backlog
my ($socket_uid) = 33;                           # socket UID
my ($socket_gid) = 33;                           # socket GID
my ($socket_perms) = 0600;                       # socket permissions

#
# script
#

use File::Pid;
use FCGI;
use Socket;
use POSIX qw(setsid);

require 'syscall.ph';

my ($pid_fd);

&daemonize;

*CORE::GLOBAL::exit = sub { die "fakeexit\nrc=".shift()."\n"; };
eval q{exit};
if ($@) {
   exit unless $@ =~ /^fakeexit/;
};

&main;

sub cleanup() {
   $pid_fd->remove if defined $pid_fd;
   unlink($socket_file);
}

sub daemonize() {
   chdir '/' or die "Failed to chdir to /: $!";
   defined(my $pid = fork) or die "Failed to fork: $!";
   exit if $pid;
   setsid or die "Failed to start a new session: $!";
   umask 0022;

   $pid_fd = File::Pid->new({
      file => $pid_file,
   });

   if ($pid_fd->running) { die "Instance already running" };

   $pid_fd->write;
}

sub main {
   $socket = FCGI::OpenSocket($socket_file, $socket_backlog);
   $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%req_params, $socket);

   chown($socket_uid, $socket_gid, $socket_file);
   chmod($socket_perms, $socket_file);

   if ($request) {
      request_loop()
   };

   FCGI::CloseSocket($socket);
}

sub request_loop {
   while($request->Accept() >= 0) {

      $stdin_passthrough ='';
      $req_len = 0 + $req_params{'CONTENT_LENGTH'};
      if (($req_params{'REQUEST_METHOD'} eq 'POST') && ($req_len != 0) ){
         my $bytes_read = 0;
         while ($bytes_read < $req_len) {
            my $data = '';
            my $bytes = read(STDIN, $data, ($req_len - $bytes_read));
            last if ($bytes == 0 || !defined($bytes));
            $stdin_passthrough .= $data;
            $bytes_read += $bytes;
         }
      }

      if ( (-x $req_params{SCRIPT_FILENAME}) &&
           (-s $req_params{SCRIPT_FILENAME}) &&
           (-r $req_params{SCRIPT_FILENAME}) ){
         pipe(CHILD_RD, PARENT_WR);
	 my $pid = open(KID_TO_READ, "-|");
         unless(defined($pid)) {
            print "Content-type: text/plain\r\n\r\n";
            print "Error: CGI app returned no output - Executing $req_params{SCRIPT_FILENAME} failed !\n";
            next;
         }

         if ($pid > 0) {
            close(CHILD_RD);
            print PARENT_WR $stdin_passthrough;
            close(PARENT_WR);

	    while(my $s = <KID_TO_READ>) { print $s; }
	    close KID_TO_READ;
	    waitpid($pid, 0);
	 } else {
            foreach $key ( keys %req_params){
               $ENV{$key} = $req_params{$key};
            }

            if ($req_params{SCRIPT_FILENAME} =~ /^(.*)\/[^\/]+$/) {
               chdir $1;
            }

	    close(PARENT_WR);
	    close(STDIN);
	    #fcntl(CHILD_RD, F_DUPFD, 0);
	    syscall(&SYS_dup2, fileno(CHILD_RD), 0);
	    #open(STDIN, "<&CHILD_RD");
	    exec($req_params{SCRIPT_FILENAME});
	    die("exec failed");
	}
     }
     else {
        print "Content-type: text/plain\r\n\r\n";
        print "Error: No such CGI app - $req_params{SCRIPT_FILENAME} may not exist or is not executable by this process.\n";
     }
  }
}

END {
   $pid_fd->remove if defined $pid_fd;
   unlink($socket_file);
}

Script de démarrage init.d

root@muse:~# cat /etc/init.d/fcgi-perl
#! /bin/sh
### BEGIN INIT INFO
# Provides:          fcgi-perl
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: fcgi-perl
# Description:       start the fcgi-perl daemon
### END INIT INFO

# Author: Boris HUISGEN <bhuisgen@hbis.fr>

PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC=fcgi-perl
NAME=fcgi-perl

DAEMON=/etc/nginx/$NAME.pl
PIDFILE=/var/run/fcgi-perl.pid
SOCKETFILE=/var/run/fcgi-perl.sock

[ -x "$DAEMON" ] || exit 0

[ -r /etc/default/$NAME ] && . /etc/default/$NAME

. /lib/init/vars.sh
. /lib/lsb/init-functions

do_start()
{
	[ -e $PIDFILE ] && return 1

	echo "Starting $PROVIDES..."
	$DAEMON &

	[ ! -e $PIDFILE ] && sleep 1
	[ ! -e $PIDFILE ] && return 2

	return 0
}

do_stop()
{
	[ ! -e $PIDFILE ] && return 1

	echo "Stopping $PROVIDES..."
	kill `cat $PIDFILE`

	rm -f $PIDFILE
	rm -f $SOCKETFILE

	return 0
}

case "$1" in
  start)
	[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
	do_start
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	esac
	;;
  stop)
	[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
	do_stop
	case "$?" in
		0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
		2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
	esac
	;;
  status)
       status_of_proc -p $PIDFILE "$DAEMON" "$NAME" && exit 0 || exit $?
       ;;
  restart)
	log_daemon_msg "Restarting $DESC" "$NAME"
	do_stop
	case "$?" in
	  0|1)
		do_start
		case "$?" in
			0) log_end_msg 0 ;;
			1) log_end_msg 1 ;;
			*) log_end_msg 1 ;;
		esac
		;;
	  *)
		log_end_msg 1
		;;
	esac
	;;
  *)
	echo "Usage: $SCRIPTNAME {start|stop|status|restart}" >&2
	exit 3
	;;
esac

:

Configuration Nginx

server {
   listen 80;
   server_name localhost;

   location / {
      root /var/www/default;
      index index.cgi index.html;
   }

   location ~ \.cgi$ {
      fastcgi_pass unix:/var/run/fcgi-perl.sock;
      fastcgi_index index.cgi;
      fastcgi_param HTTP_ACCEPT_ENCODING gzip,deflate;
      include fastcgi_params;
   }
}

gted : plugin Eclipse d’édition de fichiers Gettext

Gted est un éditeur de fichiers Gettext s’intégrant à l’IDE Eclipse.

Site web : http://www.gted.org/

PostgreSQL : afficher les requêtes SQL en cours d’exécution

L’objectif est de pouvoir afficher à tout instant les requêtes en cours d’exécution sur le serveur afin de diagnostiquer en temps réel son activité.

Em premier lieu, le monitoring des commandes SQL doit être activé dans le fichier de configuration :

root@pgsrv:~# nano /etc/postgresql/9.1/main/postgresql.conf
track_activities = on

Dès lors, il reste à exécuter cette requête pour afficher l’état actuel du serveur :

postgres@pgsrv:~/$ psql
postgres=# SELECT datname,usename,procpid,client_addr,waiting,query_start,current_query FROM pg_stat_activity;

Corosync : wrapper pour exécution conditionnelle en crontab

Ce script est utile pour lancer un script en crontab uniquement sur un node déclaré actif par Corosync / Heartbeat. Bref, une exécution conditionnelle «safe».

root@cluster-www1:~# nano /usr/local/bin/cronrun.pl
#!/usr/bin/perl
#
# This script is a wrapper for executing a cron only if a node is active.
#
# Boris HUISGEN <boris.huisgen@################>
#

use Sys::Hostname;

my $resource="res_Filesystem_1";        # resource name to check if active

#
# script
#

my $hostname = hostname();

if ($#ARGV+1 < 2) {
   print "Usage: cronrun.pl <CMD> [<ARG1> ...]\n";
   exit;
}

my $check = `crm_mon -1 | grep -q -e '$resource.*$hostname'`;
if ($? == 0) {
   my @cmd = @ARGV;

   open(CMD, "@cmd |") || die "Error: failed to execute command.";
   while (<CMD>) {
      print $_;
   }
}

Reste donc à modifier la crontab pour exécuter les scripts au travers de ce wrapper, comme par exemple :

0 3 * * * /usr/local/bin/cronrun.pl /bin/bash script.sh -arg1 -arg2
Haut de page