Richiamo del metodo MBean JMX da uno script di shell


98

Esistono librerie che mi consentono di chiamare un metodo MBean JMX da uno script di shell. Esponiamo alcune operazioni / comandi di amministrazione tramite JMX e potremmo fare in modo che i nostri amministratori utilizzino JConsole o VisualVM, ma è meglio lasciare alcune attività all'automazione. In tale automazione vorremmo essere in grado di chiamare un metodo MBean JMX sul nostro server in esecuzione, preferibilmente da uno script di shell.

Risposte:


106

Sono disponibili le seguenti utilità JMX della riga di comando:

  1. jmxterm : sembra essere l'utilità più completa.
  2. cmdline-jmxclient - utilizzato nel progetto WebArchive sembra molto semplice (e nessuno sviluppo dal 2006 sembra)
  3. Groovy script e JMX : fornisce alcune funzionalità JMX davvero potenti ma richiede groovy e altre impostazioni di libreria.
  4. Funzionalità della riga di comando JManage - (lo svantaggio è che richiede un server JManage in esecuzione per eseguire il proxy dei comandi)

Esempio di 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();

esempio cmdline-jmxclient:

Se hai un file

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

Con un'operazione chiamata:

  • jmxForceRefresh ()

Quindi puoi scrivere un semplice script bash (supponendo che scarichi cmdline-jmxclient-0.10.3.jar e lo metta nella stessa directory del tuo 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

jmxterm non sembra funzionare su Java 7 bugs.launchpad.net/jmxterm/+bug/942693
artbristol

19

Ho sviluppato jmxfuse che espone JMX Mbeans come filesystem FUSE Linux con funzionalità simili a / proc fs. Si basa su Jolokia come ponte per JMX. Gli attributi e le operazioni sono esposti per la lettura e la scrittura.

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

Ad esempio, per leggere un attributo:

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

per scrivere un attributo:

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

per invocare un'operazione:

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

12

Il plugin Syabru Nagios JMX è pensato per essere utilizzato da Nagios, ma non richiede Nagios ed è molto comodo per l'uso da riga di comando:

~$ ./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;;;;

Questo è fantastico e molto veloce. Circa 0,3 sec per restituire un valore contro 3 secondi per jmxterm
sivann

9

Potenzialmente è più semplice scriverlo in 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[]{})


    }

}

Questo verrebbe compilato in una singola .class e non necessita di dipendenze nel server o di complicati pacchetti di esperti.

chiamalo con

javac JmxInvoke.java
java -cp . JmxInvoke [url] [beanName] [method]

4

Un po 'rischioso, ma potresti eseguire un comando POST curl con i valori del modulo dalla console JMX, il suo URL e l'autenticazione http (se richiesta):

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

Attenzione: l'indice del metodo può cambiare con le modifiche al software. E l'implementazione del modulo web potrebbe cambiare.

Quanto sopra si basa sull'origine della pagina del servizio JMX per l'operazione che si desidera eseguire:

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

Fonte del modulo:

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>

L'ho implementato in questo modo da Java utilizzando a HttpURLConnectione posso confermare che funziona. (btw. submit=Invokenon è necessario)
tom

è possibile descrivere come funziona? Voglio dire, per impostazione predefinita usa jmx rmi, e lì vedo http. Significa che il server deve essere configurato per supportare le richieste jmx http?
Psychozoic

3

Dai un'occhiata a JManage . È in grado di eseguire metodi MBean e ottenere / impostare attributi dalla riga di comando .


L'unico svantaggio è l'utilizzo dell'utilità della riga di comando che richiede l'esecuzione di JManage per eseguire il proxy dei comandi sui server JMX. Preferisco un approccio più leggero direttamente al server JMX stesso.
Dougnukem

3

Potresti anche dare un'occhiata a jmx4perl . Fornisce accesso senza java agli MBean di un server Java EE remoto. Tuttavia, è necessario installare un piccolo servlet agente sulla piattaforma di destinazione, che fornisce un accesso JMX riposante tramite HTTP con un payload JSON. (La versione 0.50 aggiungerà una modalità senza agente implementando un proxy JSR-160).

I vantaggi sono tempi di avvio rapidi rispetto al lancio di una JVM Java locale e facilità d'uso. jmx4perl viene fornito con un set completo di moduli Perl che possono essere facilmente utilizzati nei tuoi script:

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);

È inoltre possibile utilizzare alias per combo MBean / Attributo / Operazione comuni (ad esempio per la maggior parte degli MXBean). Per funzionalità aggiuntive (Nagios-Plugin, accesso simile a XPath a tipi di attributi complessi, ...), fare riferimento alla documentazione di jmx4perl.


1

La risposta di @Dougnukem mi ha aiutato molto. Ho adottato l'approccio Groovy (utilizzando Groovy 2.3.3).

Ho apportato alcune modifiche al codice Dougnukem. Funzionerà con Java 7 e stamperà due attributi su stdout ogni 10 secondi.

        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)
                    }

                }
            }

Compila questo codice in un jar usando maven-compiler-plugin in modo da non richiedere l'installazione groovy solo groovy-all.jar. Di seguito è riportata la definizione e la dipendenza del plug-in pertinente.

   <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>

Avvolgilo con una mazza o una conchiglia e stamperà i dati su stdout.


0

Non sono sicuro di un ambiente simile a bash. Potresti provare alcuni semplici programmi wrapper in Java (con argomenti del programma) che invocano i tuoi MBean sul server remoto. È quindi possibile chiamare questi wrapper dallo script della shell

Se puoi usare qualcosa come Python o Perl, potresti essere interessato a JSR-262 che ti consente di esporre le operazioni JMX sui servizi web. È programmato per essere incluso in Java 7, ma potresti essere in grado di utilizzare una release candidate dell'implementazione di riferimento

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.