[gestion/trigger] Début du remplaçant de generate.

* Trigger permet de régénérer tous les services d'un hôte, ou
 des services spécifiques.
 * trigger.py -h permet de voir les services disponibles.
 * Trigger surcharge cmb pour créer un écouteur d'événements qui
 peut régénérer des services à la volée.
 * Trigger mériterait d'être un peu documenté.
This commit is contained in:
Pierre-Elliott Bécue 2014-04-30 21:37:21 +02:00
parent a907a747af
commit c79599ba9d
2 changed files with 136 additions and 0 deletions

112
gestion/trigger/trigger.py Executable file
View file

@ -0,0 +1,112 @@
#!/bin/bash /usr/scripts/python.sh
# -*- coding: utf-8 -*-
#
# Trigger library, designed to be called on any host, it will
# retreive its appropriate modules based on the hostname. Based
# on the Crans Message Broker stuff, it adds specific methods designed
# to be used as a replacement for generate
#
# Author : Pierre-Elliott Bécue <becue@crans.org>
# License : GPLv3
# Date : 29/04/2014
import argparse
import cranslib.clogger as clogger
import cmb
import cPickle
import socket
import gestion.config.trigger as trigger_config
import gestion.affichage as affichage
import sys
hostname = socket.gethostname().split(".")[0]
import importlib
triggerhost = importlib.import_module("gestion.trigger.hosts.%s" % (hostname,))
logger = clogger.CLogger("trigger", "info")
class EvenementListener(cmb.AsynchronousConsumer):
"""
Gestionnaire d'événement
"""
def on_message(self, channel, basic_deliver, properties, body):
"""Invoked by pika when a message is delivered from RabbitMQ. The
channel is passed for your convenience. The basic_deliver object that
is passed in carries the exchange, routing key, delivery tag and
a redelivered flag for the message. The properties passed in is an
instance of BasicProperties with the message properties and the body
is the message that was sent.
:param pika.channel.Channel channel: The channel object
:param pika.Spec.Basic.Deliver: basic_deliver method
:param pika.Spec.BasicProperties: properties
:param str|unicode body: The message body
"""
about = basic_deliver.routing_key.split(".")[1]
origin = properties.app_id
message_id = properties.message_id
logger.info('Received message # %s from %s: %s',
basic_deliver.delivery_tag, properties.app_id, body)
body = cPickle.loads(body)
try:
triggerhost.trigger(about)(body)
except AttributeError:
logger.warning('No suitable trigger found for message # %s from %s: %s on host %s. Discarding it.',
basic_deliver.delivery_tag, properties.app_id, body, hostname)
self.acknowledge_message(basic_deliver.delivery_tag)
def run(self):
"""Run the example consumer by connecting to RabbitMQ and then
starting the IOLoop to block and allow the SelectConnection to operate.
"""
logger.info("""Crans Message Broker
+--------------------------------------------+
| Welcome on CMB |
+--------------------------------------------+""")
self._connection = self.connect()
for service in trigger_config.services[hostname]:
self.add_queue("trigger-%s-%s" % (hostname, service), "trigger.%s" % (service,))
self._connection.ioloop.start()
def daemonize():
listener = EvenementListener(trigger_config.master, "trigger", "topic")
try:
listener.run()
except KeyboardInterrupt:
logger.warning("Caught SIGINT, will now go for shutdown.")
listener.stop()
if __name__ == '__main__':
# We use a parser to capture all possible arguments designed for one host
parser = argparse.ArgumentParser(description="Initier une régénération de services.", add_help=False)
parser.add_argument('-a', '--all', help="Régénération complète des services sur l'hôte %s." % (hostname,), action="store_true")
parser.add_argument('-d', '--daemon', help="Écouter sur civet en arrière plan.", action="store_true")
parser.add_argument('-h', '--help', help="Affiche ce message et quitte.", action="store_true")
# For each service supposingly managed by host, generate one parser option
for service in trigger_config.services[hostname]:
parser.add_argument('--%s' % (service,), help="Force la régénération du service %s." % (service,), action="store_true")
args = parser.parse_args()
if args.help:
parser.print_help()
sys.exit(0)
elif args.all:
# Regenerates all services availables, don't crash on nonexistant ones
for service in trigger_config.services[hostname]:
try:
print affichage.style(" (Ré)Génération du service %s" % (service,), "cyan")
triggerhost.trigger(service)(True)
except AttributeError:
print "No suitable trigger handle found for service %s on host %s" % (service, hostname)
elif args.daemon:
# Daemonize the trigger app, in order to listen and execute commands from civet.
daemonize()
else:
# If not all and not daemon, try all services one by one.
for service in trigger_config.services[hostname]:
if getattr(args, service, False) == True:
print affichage.style(" (Ré)Génération du service %s" % (service,), "cyan")
triggerhost.trigger(service)(True)