27 décembre 2008

Pont HTTP pour FTP vers Dedibackup

Souci de backup : je ne peux plus récupérer mes archives stockées sur un Dedibackup directement par FTP pour en avoir une copie locale, et accessoirement les valider. Sur ce dernier sujet voir l'article Validation de backups daté d'avril 2008.

Les serveurs Dedibackup sont des espaces FTP accessibles depuis les serveurs dédiés Dedibox, et jusqu'à il y a quelques mois ils étaient également accessibles en download par l'extérieur. Il suffisait de sécuriser ça en n'acceptant que certaines IP appelantes.

J'utilisais donc ce système pour avoir une machine locale « bkp » qui allait chercher régulièrement ce que déposaient tout aussi régulièrement sur mon espace Dedibackup deux Dedibox « ref1 » et « ref2 ».



Pas de bol, donc, Dedibox a coupé l'accès extérieur :




Comment résoudre ça au plus vite ? J'ai fait un service web ad hoc qui délègue ensuite au FTP,  pour « contourner » le problème comme on le voit :



Le gros du boulot a consisté à bétonner le fonctionnement du client FTP embarqué dans la webapp J2EE, elle-même bien bridée (une seule exécution à la fois, etc.). Les choix d'architecture n'étant pas vraiment conformes à la norme et donc n'apportant aucune garantie, « bétonner » signifie ici développer des tests d'intégration sur des chaînes un peu trapues. Au total avant d'être déployé, le système a été validé sur 3 environnements différents, dont un d'intégration continue.

Le tout a été conçu en une journée (elapse) et développé en une journée (load). Le développement a été concentré (focus), donc en tout on a un elapse de deux jours, et c'est tant mieux puisqu'après c'étaient les fêtes. Comme les backups sont un point crucial de la chaîne du SI, et sont en même temps totalement éloignés du métier, il était important de se sortir de cette charge le plus vite possible. Il ne reste qu'à mener des tests de performances et avoir des chiffres pour le futur suivi des évolutions.

Je dégage de cette histoire deux enseignements :
  1. c'est justement parce que certaines choses importantes ne font pas partie à proprement parler du métier qu'il faut absolument s'en occuper sérieusement, éliminer toutes les frictions et perdre le moins de temps et d'argent possible sur elles.
  2. une architecture technique pourrave est parfaitement acceptable (en fait je m'attends même à ce qu'elle tienne la durée) si par ailleurs les cas d'utilisation sont encadrés : en l'occurrence ceinture et bretelle par des tests en continu.
Le premier point incite au discernement quant à notre cœur de métier et pousse logiquement aux actions-force quand il y a besoin plutôt que d'accepter des demi-mesures qui laissent ouverts les problèmes périphériques. Pour atteindre le centre est nécessaire que la périphérie ne soit plus un problème |-)

Le deuxième point incite à un dilettantisme de bon aloi ; et en même temps qui sait rendre des comptes.

Let it go.

Déclaration d'une DataSource dans Tomcat 5.5

Testé sous Windows XP et Debian, avec MySQL et PostgreSQL.

La webapp a les lignes suivantes dans WEB-INF/web.xml :   
<resource-ref>
<res-ref-name>jdbc/janitorDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Et dans META-INF/context.xml (important) :
<Context
path="/avpoc-webapp-datasource"
reloadable="true"
antiJARLocking="true"
antiResourceLocking="true">
</Context>  
La déclaration de la DataSource jdbc/myJndiName dans Tomcat 5.5 peut se faire de la façon suivante.

D'abord dans conf/server.xml, pour par exemple MySQL : 
<Resource  
name="jdbc/myJndiName"
type="javax.sql.DataSource"
password="myPassword"
driverClassName="com.mysql.jdbc.Driver"
maxIdle="2"
maxWait="5000"
username="myUsername"
url="jdbc:mysql://localhost:3306/myDbName?autoReconnect=true"
maxActive="4"/>
Pour PostgreSQL ça donne quelque chose comme ça :
<Resource  
name="jdbc/myJndiName"
auth="Container"
type="javax.sql.DataSource"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://127.0.0.1:5432/myDatabaseName"
username="myUsername" 
password="myPassword"
maxActive="20" 
maxIdle="10" 
maxWait="-1"/>
Ensuite dans conf/context.xml :
<ResourceLink
global="jdbc/myJndiName"
name="jdbc/myJndiName"
type="javax.sql.DataSource"/>
On peut également mettre directement dans conf/context.xml la configuration de la <Resource> mais c'est moins propre.

En tout cas si on ne met rien du tout dans  conf/context.xml on obtient : 
org.apache.commons.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'
        at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:780)
        at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:540)
        at com.avcompris.avpoc.webapp.PocDataSourceServlet.executePoc(PocDataSourceServlet.java:86)
        at com.avcompris.avpoc.webapp.PocDataSourceServlet.service(PocDataSourceServlet.java:42)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
        atA org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
        at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
        at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
        at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
        at java.lang.Thread.run(Thread.java:595)
Caused by: java.sql.SQLException: No suitable driver
        at java.sql.DriverManager.getDriver(DriverManager.java:243)
        at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:773)
        ... 18 more

25 décembre 2008

22 décembre 2008

Wanted: Code reviewers

Je suis à la recherche de personnes qui pourraient regarder avec un œil critique du code Java que j'écris, et me faire des remarques.

Code libre d'accès (http://svn.avcompris.com/), liberté de bloguer le résultat des revues, échanges par messagerie instantanée ou e-mail.

La critique est attendue à tous les niveaux : licensing, architecture, choix techniques, cohérence fonctionnelle, cohérence technique, conception, algorithmique, bonnes pratiques, outillage, conventions et le reste.

C'est une activité non rémunérée : je ne sais pas qui des deux parties a le plus à y gagner... :-)

Et en échange... ben faites vos propositions.

17 décembre 2008

Pour se remettre au LOGO

Histoire de permettre à de très jeunots de s'initier à la programmation, j'ai implémenté un interpréteur des commandes basiques du LOGO par ici : http://www.half-serious.com/logo/


Le langage LOGO permet en gros de faire des dessins à l'aide d'une tortue qui sait tracer des traits et pivoter sur elle-même.

Les commandes reconnues dans mon implémentation sont :
  • FORWARD xxx, ou FD xxx : avancer la tortue de xxx points
  • BACK xxx, ou BK xxx : reculer la tortue de xxx points
  • RIGHT xxx, ou RT xxx : pivoter la tortue d'un angle xxx à droite
  • LEFT xxx, ou LT xxx : pivoter la tortue d'un angle xxx à gauche
  • PENUP, ou PU : lever le crayon
  • PENDOWN, ou PD : rebaisser le crayon
  • HIDETURTLE, ou HT : cacher la tortue
  • SHOWTURTLE, ou ST : montrer la tortue
  • REPEAT xxx [ ... ] : répète xxx fois les commandes entre crochets
Voilà. Pas de procédures, pas de variables, pas de calculs. Du bon basique pour débuter.

L'exemple ci-dessous dessine un carré :

FORWARD 100
RIGHT 90
FORWARD 100
RIGHT 90
FORWARD 100
RIGHT 90
FORWARD 100



Cet exemple peut aussi s'écrire FD 100 RT 90 FD 100 RT 90 FD 100 RT 90 FD 100, et un dessin équivalent est REPEAT 4 [FD 100 RT 90].

Quant à l'exemple ci-dessous, il dessine une espèce de rosace :

HIDETURTLE
REPEAT 100
[
FD 300 RT 45
FD 50 RT 125
]




13 décembre 2008

Surveillance de la santé des machines

Soit un parc de machines et services hétérogène : machines locales, distantes, serveurs web, Subversion, divers sites, divers hébergeurs, divers noms de domaines et registrars, bref, tout et n'importe quoi.

Comment assurer une surveillance de tout ceci ?

J'avais bien quelques outils de surveillance web, mais ils n'analysent pas forcément tous les critères, ni ne versionnent les règles de surveillance.

J'ai bien quelques tests JUnit, mais ils dépendent d'un environnement d'exécution (Continuum) assez lourd, qui lui-même peut être soumis à plantage, en particulier parce qu'un serveur J2EE demande beaucoup de ressources.

Je me décide donc à rationaliser tout cela :
  • une seule technologie d'écriture des tests : Java, sous la forme de tests JUnit.
  • une version minimale du service de surveillance, qui assure le découplage des traitements et de l'affichage : 
    • un daemon Java le plus léger possible pour l'exécution des tests, 
    • une application PHP pour afficher les résultats de façon simplifiée,
    • une communication entre Java et PHP qui passe par une base de données.
  • et une réplication de ce système sur deux machines différentes, au cas où l'une d'entre elles tomberait en panne.
Le système avec Continuum est conservé sur une (grosse) machine, en lui faisant en prime exécuter les mêmes tests JUnit que la version daemon Java + PHP.



Reste à faire en sorte qu'un e-mail soit envoyé automatiquement quand un service est détecté comme tombé. Possibilité de configuration en Java : déclarer la gravité du test dans une annotation de même niveau que @Test.
Et évidemment tester par le système lui-même les fonctionnalités d'envoi et de réception d'e-mail.

Quelques états de santé à agréger :
  • bonne santé de toutes les applications web déployées,
  • Twitter,
  • envoi et réception d'e-mails,
  • âge du ou des derniers backups inférieur à 24 h,
  • espaces disques libres supérieurs à 50 %...
Des idées ?

Merci d'avance.

Projet Les Fûts

Mmh, alors que les associations peuvent relativement facilement et à moindre coût se doter elles-mêmes d'un site web (voir par exemple le site officiel de Graine d'école : http://graine-ecole.com/ réalisé avec Joomla!), voilà-t-y pas qu'on me relance pour la réalisation de sites associatifs.

Si l'aventure doit être retentée j'abandonnerai la structure associative, sans beaucoup de valeur ajoutée. Et j'augmenterai un peu les tarifs, pour être plus proche du marché.

En l'occurrence il s'agirait d'une association qui a également un produit à présenter sur le web, à dissocier éventuellement du site associatif lui-même.