Cues del postfix i informacions relacionades
Per defecte les cues que té el postfix són:
- hold: missatges que no s’intenten entregar mai
- incoming: cua d’entrada de missatges
- active: cua en la que es decideix amb quin delivery agent s’itenta entregar un missatge
- defer/deferred: missatges que no s’han pogut entregar per un error temporal es posen en aquesta cua
- bounce: on es generen els missatges d’error cap al remitent dels missatges que no s’han pogut entregar
- corrupt: cua que conté missatges danyats amb els que no es pot fer res
Accions que podem fer amb els missatges d’una cua:
- Listing messages
- Deleting messages
- Holding messages
- Requeuing messages
- Displaying messages
- Flushing messages
Gestió de les cues:
- GUI per gestionar les cues de postfix
- Mostra l’estat de totes les cues.
mailq
- Mostrar els 10 dominis amb més missatges pendents d’enviar, sovint va bé per controlar quan ens han usat per fer un email i hi ha molts correus enganxats per enviar.
qshape -s deferred|head -n 10
- Borrar un missatge de les cues.
postsuper -d ID_MSG
- Borrar tots els missatges de les cues.
postsuper -d ALL
- Script per borrar missatges de les cues segons origen o destí:
#!/usr/bin/perl -w # # pfdel - deletes message containing specified address from # Postfix queue. Matches either sender or recipient address. # # Usage: pfdel # use strict; # Change these paths if necessary. my $LISTQ = "/usr/sbin/postqueue -p"; my $POSTSUPER = "/usr/sbin/postsuper"; my $email_addr = ""; my $qid = ""; my $euid =
gt;; if ( @ARGV != 1 ) { die "Usage: pfdel \n"; } else { $email_addr = $ARGV[0]; } if ( $euid != 0 ) { die "You must be root to delete queue files.\n"; } open(QUEUE, "$LISTQ |") || die "Can't get pipe to $LISTQ: $!\n"; my $entry = ; # skip single header line $/ = ""; # Rest of queue entries print on # multiple lines. while ( $entry = ) { if ( $entry =~ / $email_addr$/m ) { ($qid) = split(/\s+/, $entry, 2); $qid =~ s/[\*\!]//; next unless ($qid); # # Execute postsuper -d with the queue id. # postsuper provides feedback when it deletes # messages. Let its output go through. # if ( system($POSTSUPER, "-d", $qid) != 0 ) { # If postsuper has a problem, bail. die "Error executing $POSTSUPER: error " . "code " . ($?/256) . "\n"; } } } close(QUEUE); if (! $qid ) { die "No messages with the address <$email_addr> " . "found in queue.\n"; } exit 0;
- Borrar missatges segons email origen o destí.
/root/bin/pfdel email
- Hold a message / Retenir missatges, no intentar servir-los. Posar-los a una cua congelats.
postsuper -d ID_MSG
- Hold all messages
postsuper -d ALL
- Moure un missatge de la cua ‘hold’ a la cua ‘active’.
postsuper -H ID_MSG
- Moure tots els missatges de la cua ‘hold’ a la cua ‘active’.
postsuper -H ALL
- Re-encuar missatges, per exemple si el postfix tenia un erro de configuració després de corregir-los podem re-encuar els missatges perquè es corregeixin els possibles errors de classificació que hagin patit. Per exemple, canvi de ‘delivery agent’.
postsuper -r ID_MSG o postsuper -r ALL
- Veure el contingut d’un missatge que esta a la cua:
postcat -q ID_MSG
- Per forçar el re-enviament de missatges a la cua.
postqueue -s o postfix flush
- Per forçar l’enviament de missatges a la cua per un domini.
postqueue -s domini.com
Python: afegir suport de plug-ins al nostre codi
A vegades quan estem fent un programa ens interessa que el nostre codi pugui ser extés sense haver de tocar la seva estructra, fins hi tot el que ens pot interessar és que aquest codi sigui extés en algunes ocasions i en d’altres no. Un altre requeriment que podem tenir també seria que qui l’extengui no siguem nosaltres. Sovint tot això i molt més s’acostuma a fer amb el que anomenem Plug-ins, per cert, sempre m’ha fet molta gràcia la traducció al català de la paraula: ‘afegitons’.
Doncs bé, com que jo de programació no hi entenc gaire li vaig demanar al Pau que m’ajudés a entendre els models de plug-ins que implementaven alguns programes fets amb Python, ja que m’ineressava integrar aquesta funcionalitat en una serie de codis que estic desenvolupament. En aquest post intentaré explicar com funciona el paradigma dels plug-ins que usa Trac.
Primer de tot cal tenir en compte que Trac usa un patró de desplegament d’objectes anomenat Singleton, o sigui que totes les instàncies d’un objecte es refereixes a la mateixa instància. De fet, no sé dir fins a quin punt és necessari que el codi segueixi aquest patró per usar el sistema de plug-ins; tot i que jo diria que almenys les parts del codi que vulguin ser exteses pel model de plug-ins de Trac l’han de seguir.
Els plug-ins de Trac tenen les següents característiques:
- Un Plug-in és un component que extent la funcionalitat d’un altre component
- Un Plug-in pot extendre un altre Plug-in
Per tal d’incorporar la filosofia que té Trac per suportar Plug-ins al nostre codi cal importar el component ‘trac.core’, d’aquest component usarem el següent:
- trac.core.Interface (classe) s’usa per definir quin és el contracte que hauran de seguir els plug-ins.
- trac.core.ExtensionPoint (funció) quan volem que un component sigui extés usarà aquesta funció per recuperar les implementacions del contracte. Deifineix els punts de hook que té el nostre codi.
- trac.core.implements (funció) quan un component usa aquesta funció és per implementar un contracte, o sigui, que els plug-ins que es construeixin l’han d’usar.
Abans de seguir explicaré que s’enten per contracte. Un contracte és en escència una classe de tipus interficie (python no té aquest model com a tal) que defineix quins mètodes (o altres classes) poden ser extesos dins el component original. O sigui, que cal no només definir quin és el contracte que s’ofereix sinó també documentar-lo el millor possible, explicant quines són les entrades i sortides que s’esperen de cada un dels mètodes/classes.
Perquè tot plegat s’entengui millor el Pau em va posar el següent exemple:
Imaginem que tenim una classe del tipus DNI que implementa una base de dades de DNIs, on té un metode que ens permet entrar DNIs a la base de dades:
class DNI(trac.core.Component):
dni_checks = trac.core.ExtensionPoint(IDNIInput)
def __init__(self):
self._dnis = []
def add(self, dni):
assert not dni in self._dnis, "DNI ja existeix"for dni_check in self.dni_checks:
if dni_check.check(dni) is False:
print "El dni %s sembla no ser correcte" % ( dni )
return
self._dnis.append(dni)
def llista(self):
print self._dnis
Cal fixar-se que la línia:
dni_checks = trac.core.ExtensionPoint(IDNIInput)
el que fa és carregar els plug-ins que extenen la funcionalitat del codi original. A més cal que ens fixem que el paràmetre que usa la funció és la classe que defineix el contracte sobre el que es fan els plug-ins:
class IDNIInput(trac.core.Interface):
def check(dni):
""" Es cridada cada cop que s'entra un nou dni, espera que es retorni un valor boleà"""
Com es pot veure el contracte només defineix un mètode: ‘check’ que ha de tenir un paràmetre d’entrada i espera un valor boleà de sortida.
Cal fixar-se en que la classe DNI cada vegada que afegeixi un element a la base de dades (en aquest cas una simple llista), cridarà a tots els plug-ins que compleixin el contracte per l’ordre en que s’han instanciat (s’han importat al codi original) mitjançant el següent codi.
for dni_check in self.dni_checks:
if dni_check.check(dni) is False:
print "El dni %s sembla no ser correcte" % ( dni )
return
Un exemple de plug-in sobre el codi anterior i que compleix el contracte especificat podria ser aquest:
import trac.core
import dni
class ValidDNI(trac.core.Component):
trac.core.implements(dni.IDNIInput)
def check(self, dni):
if type(dni) is not type("str"):
return False
if len(dni) != 9:
return False
return True
Es pot veure com la classe és una instància de ‘trac.core.Component’ (model Singleton) i implementa la interfice ‘dni.IDNIInput’. A nivell funcional el que es fa és ben simple, comprovem que sigui una cadena de texte i que tingui una mida de 9 caràcters, si això es dona retorna un ‘True’ o sinó un ‘False’.
Un exemple de com quedaria el codi principal seria:
import trac.core
class IDNIInput(trac.core.Interface):
def check(nom):
""" Es cridada cada cop que s'entra un nou dni"""
class DNI(trac.core.Component):
dni_checks = trac.core.ExtensionPoint(IDNIInput)
def __init__(self):
self._dnis = []
def add(self, dni):
assert not dni in self._dnis, "DNI ja existeix"
for dni_check in self.dni_checks:
if dni_check.check(dni) is False:
print "El dni %s sembla no ser correcte" % ( dni )
return
self._dnis.append(dni)
def llista(self):
print self._dnis
Exemples d’ús:
>>> import trac.core
>>> from dni import DNI
>>>
>>> dni_bd = DNI(comp_mgr)
>>> dni_bd.add("38135009C")
>>> dni_bd.add("38135009")
>>> dni_bd.llista()
['38135009C', '38135009']
# importem el plug-in check_dni
>>> import check_dni
>>> dni_bd.add("11111111")
El dni 11111111 sembla no ser correcte
>>> dni_bd.add("11111111A")
>>> dni_bd.llista()
['38135009C', '38135009', '11111111A']
Definim el codi ‘log_dni’ que serà un altre plug-in:
import trac.core
import dni
class LogDNI(trac.core.Component):
trac.core.implements(dni.IDNIInput)
def check(self, dni):
print "Nou dni entrat %s" % (dni)
Seguim amb l’exemple anterior:
# importem ara el plug-in 'log_dni'
>>> import log_dni
>>> dni_bd.add("22222222B")
Nou dni entrat 22222222B
A aquestes altures ja s’han carregat dos plug-ins que treballen un després de l’altre i s’ha pogut apreciar la simplicitat i potència del model. Obviament es poden trobar coses a faltar com per exemple algún element que defineixi el llistat de plug-ins disponibles i que permeti alterar l’ordre en que aquests s’executen però això ja s’hauria de desenvolupar a part.
Espero haver-ho descrit de forma entenedora i sent el més fidel possible a les explicacions del Pau, al que he d’agrair-li l’esforç i dedicació per explicar-me aquest model de Plug-ins de Python.
- Paquet amb exemples: plugins.tar
llibre d’XMPP – notes a peu de pàgina
Després de llegir-me el llibre:
He pres les següents notes al moleskine que guardo aquí per poder consultar en el futur:
- pg.39: IQ or Message
- RFC 3920: stanza errors list
- SleekXMPP llibreria python interessant
- Apendix F: llistat de llibreries XMPP
- pg.50: Subscription
- Presence priority: -127 +128
- XEP 0191: bloquejar JID o dominis
- Podria ser interessant per bloquejar clients que no paguen
- XEP 0079: ideal delivery a pantalles, reliable delivery
- oblidar-nos de problemes si les pantalles estan offline
- expiration time dels missatges
- control delivering
- XEP 0009: JabberRPC
- XEP 0072: SOAP over XMPP
- XEP 0060: PubSub
- XEP 0163: permet que JID sigui un ‘collection node’ que agrupi serveis PubSub això es pot publicar junt amb les capabilities
- Pg. 132/150: ICE, molt bona explicació
- Pg. 145/163: VNC over XMPP es pot fer usant socks5 com a proxy segons XEP
- XEP 0050: remote commands
- BOSH: 180/198
- Pg. 189/207: Serverless Messaging
- Pg. 267/285: DNS SRV
Nagios external commands
Tan de temps usant nagios i mai havia tingut la necessita de recorrer als Nagios External Commands. Escencialment es tracta d’una named-pipe que usa Nagios per rebre comandes via shell.
- Sintaxis per injectar les comandes. Per suportar aquesta funcionalitat previament cal haver-la habilitat al fitxer de configuració de nagios, això també ho trobareu a l’anterior enllaç.
- Comandes suportades, la llista és força gran i hi podem trobar coses com ara forçar un check per host o fins hi tot deshabilitar els checks sobre un servei o un host.
A continuació adjunto la comanda que podeu llençar desdel prompt per llençar una ordre al nagios al cap de deu segons. En aquest cas forcem que es verifiquin tots els serveis d’un host.
# des del directori on hi ha la 'named-pipe' sovint anomenada 'nagios.cmd' now=$(date +%s); next=$(expr $now + 10); echo "[$now] SCHEDULE_FORCED_HOST_SVC_CHECKS;nom_host;$next" > nagios.cmd
Per veure el resultat de la comanda i si aquesta ha estat rebuda pel nagios només cal que mirem el fitxer nagios.log. La sortida del log serà algo així:
data host_server nagios: EXTERNAL COMMAND: SCHEDULE_FORCED_HOST_SVC_CHECKS;nom_host;unix_ts
Què vol dir Creative Commons?
Fa molt temps que tinc aquesta animació en flash donant tombs pel disc dur i avui m’he decidit a penjar-ho per aquí abans de que no li perdi la pista:
Fitxers kmz/kml i htc footprints
Aquestes últimes vacances a madeira he aprofitat per utitlizar una eina que fins ara incorporaven els mòbils que tenia però que fins ara que m’he passat a Android no m’he decidit a expremer, estic parlant d’htc footprints. És una eina que a partir d’un simple formulari permet registrar llocs emblemàtics, bonics, interessants, curiosos o que simplement volem recordar. Aquest formulari guarda coses com una fotografia del lloc, un títol, la posició del GPS, la direcció, pots afegir-hi comentaris de text i fins hi tot de veu; potser hem deixo algún detallet del que pots afegir-hi per cada entrada a footprints però escencialment això és tot el que fa. Obviament el bo del tema és que gràcies a les tecnologies que incorpora el telèfon omplir el formulari és ben senzill, ja que la foto, posició del GPS o gravació de veu es fan amb simples clics, com sempre el més molest és escriure text.
L’interessant del tema és que després això es pot exportar a un fitxer .kmz (tot el contingut del footprints) o un fitxer .kml (només una entrada del footprints). El .kmz conté en escència un paquet amb un fitxer kml i els arxius externs del footprints, per exemple, les fotografies o l’audio. Pel que fa al format del fitxer .kml es tracta d’un fitxer XML amb el contingut del formulari que he comentat anteriorment. Aquests fitxers són directament importables al Google Earth i a moltes altres eines de la saga de Google. Però el que a mi m’interessa comentar en aquest article és la llibereria libkml, també de google, la que vaig usar per parsejar el fitxer kmz de les vacances a Madeira.
A través d’un simple codi amb python vaig generar el codi en format dokuwiki necessari per montar-me l’esquelet de la web de les vacances a Madeira. De fet, el codi no esta gens polit i esta extret d’snippets d’exemple que he trobat per la web, però pel que jo volia era més que suficient. Al final del post hi teniu un enllaç.
Fa dies que en aquesta línia dono voltes a la idea de montar-me un servei que després de fer una entrada al footprints amb el mòbil enviï automàticament el fitxer .kmz/.kml per email a una direcció reservada que parsegi el correu i que automàticament doni d’alta aquest contingut a alguna de les seccions d’oriolrius.cat, de fet, encara no tinc clar si la millor idea és injectar-ho com a post o com a entrada del wiki, el que si que tinc clar és que això després s’haurà de referenciar al meu lifestream perquè així quedi constància de llocs interessants que coneixo i que sempre que vols recordar ja has oblidat. Si algú té idees de com millorar aquesta idea, ja ho sap, que m’avisi.
Referències:
- Tutorial de KML
- Referència de fitxers KML
- Codi del meu parser de KML fet en Python i que dona una sortida en codi directament enganxable al Dokuwiki
NOTA: el codi del dokuwiki usa el plugin de google maps.