Appel de la méthode JMX MBean à partir d'un script shell

98

Existe-t-il des bibliothèques qui me permettraient d'appeler une méthode JMX MBean à partir d'un script shell. Nous exposons certaines opérations / commandes d'administration via JMX, et nous pourrions demander à nos administrateurs d'utiliser JConsole ou VisualVM, mais certaines tâches sont mieux laissées à l'automatisation. Dans cette automatisation, nous aimerions pouvoir appeler une méthode JMX MBean sur notre serveur en cours d'exécution, de préférence à partir d'un script shell.

Dougnukem
la source

Réponses:

106

Les utilitaires JMX de ligne de commande suivants sont disponibles:

  1. jmxterm - semble être l'utilitaire le plus complet.
  2. cmdline-jmxclient - utilisé dans le projet WebArchive semble très simple (et aucun développement depuis 2006 il ressemble)
  3. Groovy script et JMX - fournit des fonctionnalités JMX vraiment puissantes mais nécessite une configuration de bibliothèque groovy et autre.
  4. Fonctionnalité de ligne de commande JManage - (l'inconvénient est qu'il nécessite un serveur JManage en cours d'exécution pour les commandes proxy)

Exemple Groovy JMX:

import java.lang.management.*
import javax.management.ObjectName
import javax.management.remote.JMXConnectorFactory as JmxFactory
import javax.management.remote.JMXServiceURL as JmxUrl

def serverUrl = 'service:jmx:rmi:///jndi/rmi://localhost:9003/jmxrmi'
String beanName = "com.webwars.gameplatform.data:type=udmdataloadsystem,id=0"
def server = JmxFactory.connect(new JmxUrl(serverUrl)).MBeanServerConnection
def dataSystem = new GroovyMBean(server, beanName)

println "Connected to:\n$dataSystem\n"

println "Executing jmxForceRefresh()"
dataSystem.jmxForceRefresh();

Exemple de cmdline-jmxclient:

Si vous avez un

  • MBean: com.company.data:type=datasystem,id=0

Avec une opération appelée:

  • jmxForceRefresh ()

Ensuite, vous pouvez écrire un simple script bash (en supposant que vous téléchargez cmdline-jmxclient-0.10.3.jar et mettez-le dans le même répertoire que votre script):

#!/bin/bash

cmdLineJMXJar=./cmdline-jmxclient-0.10.3.jar
user=yourUser
password=yourPassword
jmxHost=localhost
port=9003

#No User and password so pass '-'
echo "Available Operations for com.company.data:type=datasystem,id=0"
java -jar ${cmdLineJMXJar} ${user}:${password} ${jmxHost}:${port} com.company.data:type=datasystem,id=0

echo "Executing XML update..."
java -jar ${cmdLineJMXJar} - ${jmxHost}:${port} com.company.data:type=datasystem,id=0 jmxForceRefresh
Dougnukem
la source
jmxterm ne semble pas fonctionner sur les bogues
artbristol
19

J'ai développé jmxfuse qui expose JMX Mbeans en tant que système de fichiers Linux FUSE avec des fonctionnalités similaires à celles de / proc fs. Il s'appuie sur Jolokia comme pont vers JMX. Les attributs et les opérations sont exposés pour la lecture et l'écriture.

http://code.google.com/p/jmxfuse/

Par exemple, pour lire un attribut:

me@oddjob:jmx$ cd log4j/root/attributes
me@oddjob:jmx$ cat priority

pour écrire un attribut:

me@oddjob:jmx$ echo "WARN" > priority

pour appeler une opération:

me@oddjob:jmx$ cd Catalina/none/none/WebModule/localhost/helloworld/operations/addParameter
me@oddjob:jmx$ echo "myParam myValue" > invoke
Alastair McCormack
la source
12

Le plugin Syabru Nagios JMX est destiné à être utilisé depuis Nagios, mais ne nécessite pas Nagios et est très pratique pour une utilisation en ligne de commande:

~$ ./check_jmx -U service:jmx:rmi:///jndi/rmi://localhost:1099/JMXConnector --username myuser --password mypass -O java.lang:type=Memory -A HeapMemoryUsage -K used 
JMX OK - HeapMemoryUsage.used = 445012360 | 'HeapMemoryUsage used'=445012360;;;;
Austin Mills
la source
C'est génial et très rapide. Environ 0,3 sec pour renvoyer une valeur contre 3 secondes pour jmxterm
sivann
9

Potentiellement, il est plus facile d'écrire ceci en Java

import javax.management.*;
import javax.management.remote.*;

public class JmxInvoke {

    public static void main(String... args) throws Exception {

        JMXConnectorFactory.connect(new JMXServiceURL(args[0]))
            .getMBeanServerConnection().invoke(new ObjectName(args[1]), args[2], new Object[]{}, new String[]{})


    }

}

Cela compilerait en une seule .class et ne nécessiterait aucune dépendance dans le serveur ni aucun package maven compliqué.

appelle-le avec

javac JmxInvoke.java
java -cp . JmxInvoke [url] [beanName] [method]
teknopaul
la source
4

Un peu risqué, mais vous pouvez exécuter une commande curl POST avec les valeurs du formulaire de la console JMX, son URL et l'authentification http (si nécessaire):

curl -s -X POST --user 'myuser:mypass'
  --data "action=invokeOp&name=App:service=ThisServiceOp&methodIndex=3&arg0=value1&arg1=value1&submit=Invoke"
  http://yourhost.domain.com/jmx-console/HtmlAdaptor

Attention: l'index des méthodes peut changer avec les modifications du logiciel. Et la mise en œuvre du formulaire Web pourrait changer.

Ce qui précède est basé sur la source de la page de service JMX pour l'opération que vous souhaitez effectuer:

http://yourhost.domain.com/jmx-console/HtmlAdaptor?action=inspectMBean&name=YourJMXServiceName

Source du formulaire:

form method="post" action="HtmlAdaptor">
   <input type="hidden" name="action" value="invokeOp">
   <input type="hidden" name="name" value="App:service=ThisServiceOp">
   <input type="hidden" name="methodIndex" value="3">
   <hr align='left' width='80'>
   <h4>void ThisOperation()</h4>
   <p>Operation exposed for management</p>
    <table cellspacing="2" cellpadding="2" border="1">
        <tr class="OperationHeader">
            <th>Param</th>
            <th>ParamType</th>
            <th>ParamValue</th>
            <th>ParamDescription</th>
        </tr>
        <tr>
            <td>p1</td>
           <td>java.lang.String</td>
         <td> 
            <input type="text" name="arg0">
         </td>
         <td>(no description)</td>
        </tr>
        <tr>
            <td>p2</td>
           <td>arg1Type</td>
         <td> 
            <input type="text" name="arg1">
         </td>
         <td>(no description)</td>
        </tr>
    </table>
    <input type="submit" value="Invoke">
</form>
BBay
la source
Je l'ai implémenté de cette façon à partir de Java en utilisant un HttpURLConnectionet je peux confirmer que cela fonctionne. (btw. submit=Invoken'est pas nécessaire)
tom
est-il possible de décrire comment cela fonctionne? Je veux dire, par défaut, jmx utilise rmi, et là je vois http. Cela signifie-t-il que le serveur doit être configuré pour prendre en charge les requêtes jmx http?
Psychozoic
3

Jetez un œil à JManage . Il est capable d'exécuter des méthodes MBean et d'obtenir / définir des attributs à partir de la ligne de commande .

ChssPly76
la source
Le seul inconvénient est d'utiliser l'utilitaire de ligne de commande, il nécessite que JManage soit exécuté pour les commandes proxy vers vos serveurs JMX. Je préfère une approche plus légère directement sur le serveur JMX lui-même.
Dougnukem
3

Vous voudrez peut-être aussi jeter un œil à jmx4perl . Il fournit un accès sans Java aux MBeans d'un serveur Java EE distant. Cependant, un petit servlet d'agent doit être installé sur la plate-forme cible, ce qui fournit un accès JMX reposant via HTTP avec une charge utile JSON. (La version 0.50 ajoutera un mode sans agent en implémentant un proxy JSR-160).

Les avantages sont des temps de démarrage rapides par rapport au lancement d'une JVM Java locale et une facilité d'utilisation. jmx4perl est livré avec un ensemble complet de modules Perl qui peuvent être facilement utilisés dans vos propres scripts:

use JMX::Jmx4Perl;
use JMX::Jmx4Perl::Alias;   # Import certains aliases for MBeans

print "Memory Used: ",
      JMX::Jmx4Perl
          ->new(url => "http://localhost:8080/j4p")
          ->get_attribute(MEMORY_HEAP_USED);

Vous pouvez également utiliser un alias pour les combos MBean / Attribut / Opération (par exemple pour la plupart des MXBeans). Pour des fonctionnalités supplémentaires (Nagios-Plugin, accès de type XPath à des types d'attributs complexes, ...), veuillez vous référer à la documentation de jmx4perl.

Roland Huß
la source
1

La réponse @Dougnukem m'a beaucoup aidé. J'ai adopté l'approche Groovy (en utilisant groovy 2.3.3).

J'ai fait quelques changements sur le code Dougnukem. Cela fonctionnera avec Java 7 et imprimera deux attributs sur stdout toutes les 10 secondes.

        package com.my.company.jmx
        import groovy.util.GroovyMBean;
        import javax.management.remote.JMXServiceURL
        import javax.management.remote.JMXConnectorFactory
        import java.lang.management.*

            class Monitor {
                static main(args) {
                    def serverUrl = 'service:jmx:rmi:///jndi/rmi://localhost:5019/jmxrmi'
                    String beanName = "Catalina:type=DataSource,class=javax.sql.DataSource,name=\"jdbc/CommonDB\""
                    println  "numIdle,numActive"

                    while(1){
                        def server = JMXConnectorFactory.connect(new JMXServiceURL(serverUrl))
                       //make sure to reconnect in case the jvm was restrated 
                        server.connect()
                        GroovyMBean mbean = new GroovyMBean(server.MBeanServerConnection, beanName)
                        println  "${mbean.numIdle},${mbean.numActive}"
                        server.close()
                        sleep(10000)
                    }

                }
            }

Compilez ce code dans un fichier jar en utilisant maven-compiler-plugin afin de ne pas avoir besoin d'installation groovy uniquement le groovy-all.jar. Vous trouverez ci-dessous la définition et les dépendances pertinentes du plugin.

   <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <compilerId>groovy-eclipse-compiler</compilerId>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-compiler</artifactId>
                        <version>2.8.0-01</version>
                    </dependency>
                    <dependency>
                        <groupId>org.codehaus.groovy</groupId>
                        <artifactId>groovy-eclipse-batch</artifactId>
                        <version>2.3.4-01</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.3</version>
        </dependency>
    </dependencies>

Enveloppez-le avec une batte ou un shell et il imprimera les données sur stdout.

Haim Raman
la source
0

Je ne suis pas sûr de l'environnement de type bash. Vous pouvez essayer quelques programmes wrapper simples en Java (avec des arguments de programme) qui invoquent vos MBeans sur le serveur distant. Vous pouvez ensuite appeler ces wrappers à partir du script shell

Si vous pouvez utiliser quelque chose comme Python ou Perl, vous pourriez être intéressé par JSR-262 qui vous permet d'exposer des opérations JMX sur des services Web. Ceci est prévu pour être inclus dans Java 7, mais vous pourrez peut-être utiliser une version candidate de l' implémentation de référence

Kevin
la source