7.6. Generando los ficheros de configuración y controlando el demonio.

Veamos como usar las plantillas mason para generar los ficheros de configuración de nuestro módulo ntp. Cuando estudiamos el servicio que ibamos a implementar vimos que todo el trabajo del demonio ntp se basa en el fichero de configuración /etc/ntp.conf. Usaremos el mismo sistema que genera HTML para generar este fichero.

Esta parte del módulo pertenece al backend, por lo que todos los métodos necesarios para implementarla se incluirán en EBox::NTP.

Lo primero que debemos hacer es implementar un método privado en nuestro módulo, que llamamos _setNTPConf, y será llamado cada vez que sea necesario generar el fichero de configuración del demonio. Su implementación es la siguiente:

Ejemplo 7.18. Generar el fichero de configuración /etc/ntp.conf

sub _setNTPConf
{
	my $self = shift;
	my @array = ();
	my @servers = $self->servers;
	my $synch = 'no';
	my $active = 'no';

	($self->synchronized) and $synch = 'yes';
	($self->service) and $active = 'yes';

	push(@array, 'active'   => $active);
	push(@array, 'synchronized'  => $synch);
	push(@array, 'servers'  => \@servers);

	$self->writeConfFile(NTPCONFFILE, "ntp/ntp.conf.mas", \@array);
}

Como podemos ver su implementación es sencilla, simplemente añadimos a la variable array los parámetros que queremos pasar a la plantilla mason, en nuestro caso le pasamos el parámetro active que indicará si el servicio de sincronización a clientes de nuestra red está activo o no, el parámetro synchronized que indicará si está activado el servicio de sincronización externa y un último parámetro servers que es un array con la lista de servidores externos a los que podemos tratar de sincronizarnos. Por último, llamamos al método writeConfFile que se encargará de generar el fichero de configuración con los permisos adecuados y al que le pasamos como parámetros:

Veamos ahora como implementar la plantilla. Hay ciertos parámetros del fichero de configuración que hemos creido conveniente dejar con un valor preestablecido ya que así lo decidimos en la fase de estudio del servicio. Por lo demás la implementación se realiza de la misma manera que cuando generamos las plantillas mason HTML.

Ejemplo 7.19. Plantilla mason para generar el fichero /etc/ntp.conf

<%args>
	$active
	$synchronized
	@servers
</%args>
# /etc/ntp.conf, configuration for ntpd
# Generated by EBox

driftfile /var/lib/ntp/ntp.drift
statsdir /var/log/ntpstats/

% if ($synchronized eq 'yes') {
%       if ($servers[0]) {
server <% $servers[0] %>
%       }
%       if ($servers[1]) {
server <% $servers[1] %>
%       }
%       if ($servers[2]) {
server <% $servers[2] %>
%       }
% }
% if ($active eq 'yes') {
server 127.127.1.0
% }
fudge 127.127.1.0 stratum 13

restrict default kod notrap nomodify nopeer noquery

restrict 127.0.0.1 nomodify

Ya tan solo nos queda ver cómo controlar el demonio del servicio. Debemos implementar varios métodos, el primero de ellos el método abstracto de la clase base Ebox::Module _regenConfig, llamado cuando se relanzan los servicios eBox o cuando se salvan datos del módulo. Su función generar los ficheros de configuración y es por ello que ha de realizar una llamada al método visto anteriormente _setNTPConf. Veamos como está implementado:

Ejemplo 7.20. Método _regenConfig

sub _regenConfig
{
	my $self = shift;

	$self->_setNTPConf;
	$self->_doDaemon();
}

Junto con la llamada al método que genera el fichero de configuración, realizamos una llamada al método _doDaemon. Éste y los métodos: _daemon, _stopService y isRunning realizarán todo el control sobre el demonio. Veamos uno a uno cómo están implementados, empezando por _doDaemon:

Ejemplo 7.21. Método para la gestión del demonio

sub _doDaemon
{
	my $self = shift;
	my $logger = EBox::Global->logger;

	if (($self->service or $self->synchronized) and $self->isRunning) {
		$self->_daemon('stop');
		sleep 2;
		if ($self->synchronized) {
			my $exserver = $self->get_string('server1');
			try {
				root("/usr/sbin/ntpdate $exserver");
			} catch EBox::Exceptions::Internal with {
				$logger->info("Error, ntpdate could" .
						" not be started.");
			};
		}
		$self->_daemon('start');
	} elsif ($self->service or $self->synchronized) {
		if ($self->synchronized) {
			my $exserver = $self->get_string('server1');
			try {
				root("/usr/sbin/ntpdate $exserver");
			} catch EBox::Exceptions::Internal with {
				$logger->info("Error ntpdate could" .
						" not be started.");
			};
		}
		$self->_daemon('start');
	} elsif ($self->isRunning) {
		$self->_daemon('stop');
		if ($self->synchronized) {
			$self->_daemon('start');
		}
	}
}

Este método será llamado para:

Según el caso en que nos encontremos realizaremos llamadas al método _daemon, cuya implementación veremos a continuación, con la acción que queramos realizar: start o stop. Lo único que debemos tener en cuenta es que si el servicio de sincronización mediante servidores externos está activado, debemos tratar de sincronizarnos con el primero de los servidores ntp mediante el comando /usr/sbin/ntpdate, antes de arrancar el servicio con la llamada a $self->_daemon('start') ésta es una práctica recomendada antes de lanzar un demonio de ntp.

Veamos ahora el método _daemon, encargado de trabajar directamente con el demonio y lanzarlo, pararlo o relanzarlo según la cadena que recibimos como parámetro. Su implementación es muy sencilla:

Ejemplo 7.22. Comandos para arrancar y parar el demonio ntp.

sub _daemon # (action)
{
	my ($self, $action) = @_;

	if ( $action eq 'start') {
		root("start-stop-daemon --start --quiet --pidfile" .
			" /var/run/ntpd.pid --exec /usr/sbin/ntpd " .
			" -- -g -p /var/run/ntpd.pid");
	} elsif ( $action eq 'stop') {
		root("start-stop-daemon --stop --quiet --pidfile" .
			" /var/run/ntpd.pid");
	} elsif ( $action eq 'force-reload') {
		root("start-stop-daemon --stop --quiet --pidfile"
			" /var/run/ntpd.pid");
		sleep 2;
		root("start-stop-daemon --start --quiet --exec /usr/sbin/ntpd -- -g -p /var/run/ntpd.pid");
	} else {
		throw EBox::Exceptions::Internal("Bad argument: $action");
	}
}

Por último nos queda por ver cómo dos métodos, por un lado el método abstracto de la clase base EBox::Module _stopService que simplemente parará el servicio, y el método isRunning que nos dirá si el servicio está en ejecución o no a través de su identificador de proceso o PID.

Ejemplo 7.23. Método _stopService.

sub _stopService
{
	my $self = shift;

	if ($self->isRunning) {
		$self->_daemon('stop');
	}
}
 

Ejemplo 7.24. Método para saber si el servicio está ejecutándose.

sub isRunning
{
	my $self = shift;
	return $self->pidFileRunning(PIDFILE);
}