PROJET AUTOBLOG


Planet-Libre

source: Planet-Libre

⇐ retour index

crowd42 : Astuce : désactiver la mise en cache des copies de paquets par APT

jeudi 20 février 2014 à 06:22

Quand vous installez ou désinstaller un paquet avec apt-get ou aptitude sur Debian et Ubuntu (ou toute autre distribution basée sur Debian), une copie est faite du paquet et sauvegardé dans /var/cache/apt/archive. Au bout de quelques mois vous risquez de vous retrouver avec un répertoire qui contient plusieurs Go de .deb.

Il existe plusieurs commandes pour vider le répertoire cache de tous ces paquets, de la plus bourrin à la plus “élégante“. Commençons par la dernière :

sudo apt-get autoclean

Cette ligne de commande supprimera toutes copies des anciennes versions des paquets dans /var/cache/apt/archives et qui ne sont plus présents dans les dépôts  et ne gardera que celles qui sont à jour.

sudo apt-get clean

Contrairement à autoclean, clean va supprimer tous les paquets du répertoire /var/cache/apt/archives. Personnellement c’est celle-là que je préfère et que j’utilise.

sudo rm -rf /var/cache/apt/archives

Sans doute la plus bourrin. Même si elle fonctionne. je la déconseille surtout aux gens un peu distraits, on est jamais à l’abri avec rm.

Si vous souhaitez empêcher APT de faire des copies des paquets dans var/cache/apt/archives, créez ce nouveau fichier :

sudo vim /etc/apt/apt.conf.d/02nocache

Ensuite, ajoutez ces deux lignes :

Dir::Cache "";
Dir::Cache::archives "";

Et c’est tout. Enjoy it ;)

Cet article Astuce : désactiver la mise en cache des copies de paquets par APT est apparu en premier sur crowd42.

Related posts:

  1. Désactiver un dépôt PPA et rétrograder les paquets qu’il contient avec PPA-Purge
  2. Astuce : désactiver le tap clic du touchapd
  3. Apt-fast : accélérez le téléchargement des paquets et des paquets et des mises à jour

Gravatar de crowd42
Original post of crowd42.Votez pour ce billet sur Planet Libre.

Nicolargo : Les idées et les logiciels libres

mercredi 19 février 2014 à 23:15

Si la nature a rendu une chose moins propre que toutes les autres à la propriété exclusive, c’est l’action de la puissance pensante appelée une idée, qu’un individu possède seulement tant qu’il la garde pour soi; dès l’instant où elle est divulguée, elle s’impose à la possession de tous et celui qui la reçoit ne peut s’en défaire. Ce qui en fait aussi sa particularité est que personne ne la possède moins, car chacun la possède en entier. Celui qui reçoit une idée de moi, l’ajoute à son savoir sans diminuer le mien; de même que celui qui allume sa torche au feu de la mienne, reçoit la lumière sans me plonger dans les ténèbres.

Thomas Jefferson

capture_164

Découvert lors du visionnage du TEDx 2012 de Cédric Villani.

Cet article Les idées et les logiciels libres est apparu en premier sur Le blog de NicoLargo.

Gravatar de Nicolargo
Original post of Nicolargo.Votez pour ce billet sur Planet Libre.

mael : Java agent & Javassist pour monitorer du code

mercredi 19 février 2014 à 20:38

java-agent.tar.gz

Un agent java, qu’est ce que c’est ?

Un agent java est un élément permettant d’instrumenter du code java. Il est lancé au chargement de la JVM, grâce à l’option : -javaagent:/chemin/vers/un/jar.
Le jar d’un agent doit contenir au moins une classe déclarant une méthode dont la signature est :

public static void premain(String agentArgs, Instrumentation inst)

Il doit également contenir un Manifest indiquant l’emplacement de cette classe, grâce à l’instruction « Premain-Class ». Par exemple :
Premain-Class: fr.mael.examples.agent.MyAgent

Au chargement de la JVM, c’est à dire avant que l’application ne s’exécute, la méthode premain de l’agent est appelée. L’objet Instrumentation passé en paramètre de la méthode premain présente plusieurs fonctions, dont une qui va nous intéresser ici : la méthode ayant la signature void addTransformer(ClassFileTransformer transformer). Cette méthode accepte en paramètre un objet implémentant l’interface ClassFileTransformer. Cette interface ne déclare qu’une méthode : byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) . Cette méthode est très intéressante. Elle est appelée une fois pour chaque classe chargée par le (ou les) classloader(s) de la JVM. Elle permet de modifier à la volée le bytecode de n’importe quelle classe avant que celle-ci ne soit mise à disposition de l’application. Le bytecode original de la classe est passé en paramètre: classfileBuffer, et la fonction renvoie le bytecode modifié (ou pas).

Pourquoi Javassist ?

Grâce à des librairies manipulant du bytecode, on peut donc faire à peu près ce qu’on veut : ajouter des méthodes à des interfaces, à des classes, ajouter des paramètres à des méthodes existantes, modifier les corps de méthodes, etc. bref, on a quasiment autant de possibilité que si on avait accès au code source des classes.
Il existe plusieurs librairies manipulant du bytecode. Parmi les plus connues, on trouve par exemple ASM et Javassist. La première est plus « low level », et requiert visiblement de bonnes connaissances en bytecode (ce qui n’est pas mon cas), et la seconde est plus « high level », permettant de s’affranchir de manipulation directe de bytecode.
Comme mes connaissances en bytecode sont actuellement limitées (c’est dans ma « TO LEARN » liste), j’ai choisi d’utiliser Javassist.

Pour quoi faire ?

Avec un peu d’imagination, on peut penser à beaucoup d’utilisations des agents java : logging dans du code pour lequel on n’a pas les sources, gestion des exceptions, monitoring etc. Attention toutefois à ne pas faire n’importe quoi, la manipulation du bytecode n’est pas une chose anodine, et peut introduire des bugs difficiles à corriger, ou encore avoir un impact sur les performances. Il faut donc l’utiliser avec parcimonie.
Ici, l’exercice va consister à intercepter toutes les requêtes sur une base de données effectuées via un PreparedStatement, pour logger la requête, son temps d’exécution et la stacktrace pour savoir le code qui a mené à l’exécution de la requête. Je ne garantis pas du tout les performances, il s’agit avant tout de découvrir l’utilisation des agents

Agent de base

Avoir un projet de base pour développer un agent est très simple, surtout avec Maven. Tout ce dont on a besoin, c’est d’une classe déclarant la méthode premain :

package fr.mael.examples.javaagent;

import java.lang.instrument.Instrumentation;

public class MyAgent {
        
        public static void premain(String agentArgs, Instrumentation inst) {    
        }

}

Et d’une instruction dans le pom permettant de construire le fichier Manifest:


        
                
                        org.apache.maven.plugins
                        maven-jar-plugin
                        
                                
                                        
                                                fr.mael.examples.javaagent.MyAgent
                                        
                                
                        
                
        

Voilà. On a tout ce qu’il faut : au build, maven construira un jar avec le Manifest qui va bien, permettant d’utiliser l’agent.

Conception du logger

Reprenons donc les spécifications que je me suis fixées :

package fr.mael.examples.javaagent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SQLProbe {

        private static Logger LOG = LoggerFactory.getLogger(SQLProbe.class);

        private String sql;

        private Long startTime;

        public SQLProbe(String sql) {
                this.sql = sql;
        }

        public void start() {
                startTime = System.currentTimeMillis();
        }

        public void stop() {
                LOG.info(String.format("\\"%s\\" query took %d ms to execute. Stacktrace:", sql, (System.currentTimeMillis() - startTime)), new Throwable());
        }

        public String getSql() {
                return sql;
        }

        public void setSql(String sql) {
                this.sql = sql;
        }

}

On crée ensuite notre classe héritant de ClassFileTransformer :

public class JDBCClassTransformer implements ClassFileTransformer {

        @Override
        public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
                byte[] classfileBufferToReturn = classfileBuffer;
                //le ClassPool contient l'ensemble des classes du classpath
                ClassPool pool = ClassPool.getDefault();
                //cet objet sera la classe passée en paramètre
                CtClass currentClass = null;
                //les classes de connexion et de statement de java.sql
                CtClass connection = null, statement = null;
                try {
                        //on crée une classe javassist à partir des bytes passés en paramètre
                        currentClass = pool.makeClass(new java.io.ByteArrayInputStream(classfileBuffer));
                        //on récupère les 2 interfaces qui nous intéresse
                        connection = pool.get("java.sql.Connection");
                        statement = pool.get("java.sql.PreparedStatement");
                        //on teste si la classe actuelle hérite d'une des deux interfaces. Si c'est
                        //le cas, on l'instrumente
                        if (currentClass.subtypeOf(connection) && !currentClass.isInterface()) {
                                probeConnection(currentClass);
                        } else if (currentClass.subtypeOf(statement) && !currentClass.isInterface()) {
                                probeStatement(currentClass);
                        }
                        //on récupère le bytecode modifié (ou pas) de la classe
                        classfileBufferToReturn = currentClass.toBytecode();
                } catch (Exception e) {
                        e.printStackTrace();

                } finally {
                        if (currentClass != null) {
                                currentClass.detach();
                        }
                }
                return classfileBufferToReturn;

        }

        private void probeStatement(CtClass currentClass) throws NotFoundException, CannotCompileException {

                CtMethod executeQuery = null;

                try {
                        //ici on utilise getDeclaredMethod pour n'instrumentaliser que les classes qui déclarent effectivement
                        //cette méthode (et pas les classes qui héritent d'une classe qui déclare cette méthode)
                        //c'est un peu moche mais je n'ai pas trouvé mieux...
                        executeQuery = currentClass.getDeclaredMethod("executeQuery");
                } catch (NotFoundException e) {
                        return;
                }
                //on crée un champ de type SQLProbe qu'on injecte comme propriété dans le Statement
                CtField field = CtField.make("private fr.mael.examples.javaagent.SQLProbe $$probe;", currentClass);
                currentClass.addField(field);
                //on crée un setter un setter pour ce champ
                CtMethod setter = CtNewMethod.make("public void set$$probe(fr.mael.examples.javaagent.SQLProbe probe){ this.$$probe = probe;}", currentClass);
                currentClass.addMethod(setter);

                //on démarre la sonde au début de l'exécution de la méthode executeQuery()
                executeQuery.insertBefore("this.$$probe.start();");
                //on stopppe la sonde à la fin de l'exécution de la méthode executeQuery()
                executeQuery.insertAfter("this.$$probe.stop();");
        }

        private void probeConnection(CtClass currentClass) throws NotFoundException, CannotCompileException {
                //on récupère la méthode prepareStatement de base
                CtMethod old = currentClass.getMethod("prepareStatement", "(Ljava/lang/String;)Ljava/sql/PreparedStatement;");
                //on crée une nouvelle méthode prepareStatement à partir de l'ancienne
                CtMethod newC = CtNewMethod.copy(old, "prepareStatement", currentClass, null);
                //on attribute un nouveau nom à la méthode prepareStatement de base
                String newName = "__prepareStatement";
                old.setName(newName);

                //on crée le corps de notre nouvelle méthode
                //cette méthode doit créer une probe, puis appeler la méthode prepareStatement de base, et 
                //attribuer la probe au Statement récupéré à partir de cette appel.
                StringBuffer body = new StringBuffer();
                body.append("{");
                body.append("   fr.mael.examples.javaagent.SQLProbe probe = new fr.mael.examples.javaagent.SQLProbe($1);");
                body.append("   java.sql.PreparedStatement statement = ").append(newName).append("($$);");
                body.append("   fr.mael.examples.javaagent.Util.setProbe(statement, probe);");
                body.append("   return statement;");
                body.append("}");

                //on attribue son corps à notre nouvelle méthode
                newC.setBody(body.toString());
                //on ajoute notre nouvelle méthode
                currentClass.addMethod(newC);
        }

}

Toutes les explications sont dans le code, je ne pense pas qu’il y ait besoin de plus d’explications. On peut maintenant modifier notre agent pour ajouter ce ClassFileTransformer :

package fr.mael.examples.javaagent;

import java.lang.instrument.Instrumentation;

public class MyAgent {
        
        public static void premain(String agentArgs, Instrumentation inst) {    
            inst.addTransformer(new JDBCClassTransformer());
        }

}

Et c’est tout. Plus qu’à exécuter un mvn package pour créer le jar de l’agent. Et ensuite, il suffit de créer un petit bout de code qui fait une requête en base. Un truc de ce genre :

        public static void main(String[] args) {
                try {
                        Class.forName("com.mysql.jdbc.Driver");

                        String url = "jdbc:mysql://localhost:3306/une_base";
                        String user = "root";
                        String passwd = "root";

                        Connection conn = DriverManager.getConnection(url, user, passwd);
                        PreparedStatement preparedStatement = conn.prepareStatement("select * from ma_grosse_table");
                        preparedStatement.executeQuery();

                } catch (Exception e) {
                        e.printStackTrace();
                }
        }

exécuter ce main avec l’option JVM :

-javaagent:/chemin/vers/le/jar/de/mon/agent.jar

Et on devrait obtenir une sortie de ce genre :

18:42:21.094 [main] INFO  fr.mael.examples.javaagent.SQLProbe - "select * from ma_grosse_table" query took 20075 ms to execute. Stacktrace:
java.lang.Throwable: null
        at fr.mael.examples.javaagent.SQLProbe.stop(SQLProbe.java:23) [java-agent-0.0.1-SNAPSHOT.jar:na]
        at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2335) [mysql-connector-java-5.1.29.jar:na]
        at fr.mael.examples.agentsql.App.main(App.java:22) [classes/:na]

On a toutes les infos : la requête exécutée, son temps d’exécution, et la stacktrace.

Conclusion

Comme je l’ai indiqué plus tôt dans l’article, le code que je donne risque sans doute d’avoir un impact non négligeable sur les performances. Il ne s’agit pas ici d’avoir un code prêt à être utilisé en production, mais un code permettant de découvrir l’instrumentation de bytecode grâce à un agent.
Ces techniques offrent des possibilités infinies d’instrumentation d’une application existante sans en modifier une seule ligne de code. Pour ceux qui connaissent, on peut penser à AppDynamics qui pousse ce concept assez loin, en proposant un monitoring d’applications java assez poussé (je n’ai aucun lien de quelque sorte que ce soit avec AppDynamics, c’est juste que je connais un peu leur application).

Fichiers

Le projet maven de l’agent : http://blog.le-guevel.com/wp-content/uploads/2014/02/java-agent.tar.gz

Gravatar de mael
Original post of mael.Votez pour ce billet sur Planet Libre.

Admin-Linux : Rundeck – ordonnanceur centralisé opensource – vient de sortir sa v2.0

mercredi 19 février 2014 à 14:35

Rundeck est un ordonnanceur centralisé sous licence libre (Apache v2.0) et ils viennent de sortir (1er février 2014) une nouvelle version majeure qui est la 2.0.

La toute dernière version est d’ailleurs la 2.0.1 qui est sortie le 12 février pour corriger quelques bugs.

On entends souvent parler d’orchestration centralisée, Rundeck est à ranger dans cette catégorie.

Rundeck dispose d’une interface permettant de gérer les différents jobs à exécuter sur les différents serveurs, mais fournit également des outils en ligne de commande et une API Web

Voici la liste de ses principales fonctionnalités :

Voici la liste des principales nouveautés :

Voici un screenshot de la nouvelle interface :

Rundeck Screenshot

 

Liens utiles :

Site officiel de Rundeck

Page Github de Rundeck

L'article Rundeck – ordonnanceur centralisé opensource – vient de sortir sa v2.0 est apparu en premier sur L'admin sous GNU / Linux - Blog Libre.

Gravatar de Admin-Linux
Original post of Admin-Linux.Votez pour ce billet sur Planet Libre.

Articles similaires

Romaine Lubrique : Chronique « Domaine public » #4 du 56Kast #14

mercredi 19 février 2014 à 12:59

Où il est question de la problématique complexe du jeu vidéo et du domaine public, ainsi que de Max Linder, première star international du cinéma français (en l'occurrence muet)

- Libération / ,

Gravatar de Romaine Lubrique
Original post of Romaine Lubrique.Votez pour ce billet sur Planet Libre.

Articles similaires