modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java | 211 ++++++---- modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionInfo.java | 92 ++++ modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java | 124 +++++ modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseComponent.java | 167 +++++++ modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseDiscoveryComponent.java | 65 +-- modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDiscoveryComponent.java | 99 ++-- modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPluginLifecycleListener.java | 28 - modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableComponent.java | 129 ++++++ modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableDiscoveryComponent.java | 85 ++++ modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserComponent.java | 128 ++++++ modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserDiscoveryComponent.java | 76 +++ modules/plugins/mysql/src/main/resources/META-INF/rhq-plugin.xml | 112 ++--- 12 files changed, 1080 insertions(+), 236 deletions(-)
New commits: commit 28ae734397d49586094f973c0db81f06fc394791 Author: Steve Millidge smillidge@c2b2.co.uk Date: Mon Oct 18 11:13:29 2010 +0200
Huge Improvement of the MySQL plugin.
This included autodiscovery of MySQL, databases and users.
diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java index 737634b..f38b944 100644 --- a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlComponent.java @@ -16,11 +16,15 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - package org.rhq.plugins.mysql;
-import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.rhq.core.domain.event.Event; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.measurement.DataType; import org.rhq.core.domain.measurement.MeasurementDataNumeric; @@ -33,129 +37,184 @@ import org.rhq.core.pluginapi.measurement.MeasurementFacet; import org.rhq.plugins.database.DatabaseComponent;
import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.DriverManager; import java.sql.ResultSet; -import java.sql.ResultSetMetaData; import java.sql.SQLException; +import java.sql.Statement; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.rhq.core.pluginapi.event.EventPoller; +import org.rhq.core.system.AggregateProcessInfo; +import org.rhq.core.system.ProcessInfo; +import org.rhq.plugins.database.DatabaseQueryUtility;
/** * @author Greg Hinkle + * @author Steve Millidge */ public class MySqlComponent implements DatabaseComponent, ResourceComponent, MeasurementFacet {
private ResourceContext resourceContext; - private Connection connection; - private static final Log log = LogFactory.getLog(MySqlComponent.class); + private AggregateProcessInfo aggregateProcessInfo; + private MySqlConnectionInfo info; + private Log log = LogFactory.getLog(this.getClass()); + private Map<String, String> globalStatusValues = new HashMap<String, String>(); + private Map<String, String> globalVariables = new HashMap<String, String>();
public void start(ResourceContext resourceContext) throws InvalidPluginConfigurationException, Exception { this.resourceContext = resourceContext; - getConnection(); + info = MySqlDiscoveryComponent.buildConnectionInfo(resourceContext.getPluginConfiguration()); + ProcessInfo processInfo = resourceContext.getNativeProcess(); + if (processInfo != null) { + aggregateProcessInfo = processInfo.getAggregateProcessTree(); + } else { + //findProcessInfo(); + //log.debug("Unable to locate native process information. Process level statistics will be unavailable."); + } }
public void stop() { - try { - this.connection.close(); - } catch (SQLException e) { - log.warn(e); - } + MySqlConnectionManager.getConnectionManager().closeConnection(info); }
public AvailabilityType getAvailability() { + if (log.isDebugEnabled()) { + log.debug("Doing an availability check on " + info.buildURL()); + }
- try { - getConnection().createStatement().executeQuery("select 1"); - return AvailabilityType.UP; - } catch (SQLException e) { - if (log.isDebugEnabled()) { - log.debug("getAvail failed: " + e.getMessage()); - } - return AvailabilityType.DOWN; + Connection conn = getConnection(); + AvailabilityType result = AvailabilityType.DOWN; + if (conn != null) { + // the connection must be OK as the validity check will have worked + result = AvailabilityType.UP; + } + if (log.isDebugEnabled()) { + log.debug("Availability check on " + info.buildURL() + " gives " + result); } + return result; + }
public void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> metrics) throws Exception { + Connection conn = getConnection(); + if (conn != null) { + ResultSet rs = null; + Statement stmt = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery("SHOW GLOBAL STATUS"); + while (rs.next()) { + globalStatusValues.put(rs.getString(1), rs.getString(2)); + }
- ResultSet rs = getConnection().createStatement().executeQuery("SHOW /*!50002 GLOBAL */ STATUS"); - - Map<String, String> values = new HashMap<String, String>(); - while (rs.next()) { - values.put(rs.getString(1), rs.getString(2)); + rs.close(); + rs = stmt.executeQuery("select * from information_schema.global_variables"); + while (rs.next()) { + globalVariables.put(rs.getString(1), rs.getString(2)); + } + } catch (SQLException sqle) { + } finally { + DatabaseQueryUtility.close(stmt, rs); + } }
- + // get process information + aggregateProcessInfo = findProcessInfo(); for (MeasurementScheduleRequest request : metrics) { - if (!request.getName().startsWith("Process")) { - + String requestName = request.getName(); + if (requestName.startsWith("Process") && aggregateProcessInfo != null) { + aggregateProcessInfo.refresh(); + if ("Process.aggregateMemory.resident".equals(requestName)) { + long mem = aggregateProcessInfo.getAggregateMemory().getResident(); + report.addData(new MeasurementDataNumeric(request, new Double((double) mem))); + } else if ("Process.aggregateMemory.size".equals(requestName)) { + long value = aggregateProcessInfo.getAggregateMemory().getSize(); + report.addData(new MeasurementDataNumeric(request, new Double((double) value))); + }else if ("Process.aggregateMemory.pageFaults".equals(requestName)) { + long value = aggregateProcessInfo.getAggregateMemory().getPageFaults(); + report.addData(new MeasurementDataNumeric(request, new Double((double) value))); + } else if ("Process.aggregateCpu.user".equals(requestName)) { + long value = aggregateProcessInfo.getAggregateCpu().getUser(); + report.addData(new MeasurementDataNumeric(request, new Double((double) value))); + } else if ("Process.aggregateCpu.sys".equals(requestName)) { + long value = aggregateProcessInfo.getAggregateCpu().getSys(); + report.addData(new MeasurementDataNumeric(request, new Double((double) value))); + } else if ("Process.aggregateCpu.percent".equals(requestName)) { + double value = aggregateProcessInfo.getAggregateCpu().getPercent(); + report.addData(new MeasurementDataNumeric(request, new Double(value))); + } else if ("Process.aggregateCpu.total".equals(requestName)) { + long value = aggregateProcessInfo.getAggregateCpu().getTotal(); + report.addData(new MeasurementDataNumeric(request, new Double((double)value))); + }else if ("Process.aggregateFileDescriptor.total".equals(requestName)) { + long value = aggregateProcessInfo.getAggregateFileDescriptor().getTotal(); + report.addData(new MeasurementDataNumeric(request, new Double((double)value))); + } + } else { if (request.getDataType() == DataType.MEASUREMENT) { try { - String strVal = values.get(request.getName()); + String strVal = globalStatusValues.get(request.getName()); double val = Double.parseDouble(strVal); report.addData(new MeasurementDataNumeric(request, val)); - } catch (Exception e) { } + } catch (Exception e) { + } } } } }
- - - - public Connection getConnection() { try { - this.connection = MySqlDiscoveryComponent.buildConnection(resourceContext.getPluginConfiguration()); - - } catch (SQLException e) { - if (log.isDebugEnabled()) { - log.debug("getAvail failed: " + e.getMessage()); - } + return MySqlConnectionManager.getConnectionManager().getConnection(info); + } catch (SQLException ex) { + log.warn("Unable to obtain database connection ", ex); + return null; } - return connection; }
+ @Override public void removeConnection() { - this.connection = null; + MySqlConnectionManager.getConnectionManager().closeConnection(info); }
- public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { - - try { - Class.forName("com.mysql.jdbc.Driver").newInstance(); - - Connection conn = - DriverManager.getConnection("jdbc:mysql://192.168.1.5?user=rhqadmin&password=rhqadmin"); - - DatabaseMetaData dmd = conn.getMetaData(); - System.out.println("Version: " + dmd.getDatabaseProductVersion()); - System.out.println("Product: " + dmd.getDatabaseProductName()); - - - - // The default changed in 5.0.2... the following gets globabl data for all versions -// ResultSet rs = conn.createStatement().executeQuery("SHOW /*!50002 GLOBAL *//* STATUS"); - ResultSet rs = conn.createStatement().executeQuery("SHOW TABLE STATUS FROM mysql"); -// ResultSet rs = dmd.getTables(null, null, null, null);//Catalogs();//Schemas(); - ResultSetMetaData md = rs.getMetaData(); - for (int i = 1; i <= md.getColumnCount();i++) { - System.out.print(md.getColumnName(i) + " "); + private AggregateProcessInfo findProcessInfo() { + AggregateProcessInfo result = null; + // is still running reuse + if (aggregateProcessInfo != null && aggregateProcessInfo.isRunning()) { + result = aggregateProcessInfo; + } else { + long pid = findPID(); + if (pid != -1) { + List<ProcessInfo> processes = resourceContext.getSystemInformation().getAllProcesses(); + for (ProcessInfo pi : processes) { + if (pid == pi.getPid()) { + result = pi.getAggregateProcessTree(); + break; + } + } } - System.out.println(""); - while (rs.next()) { + } + return result; + }
- for (int i = 1; i <= md.getColumnCount();i++) { - System.out.print(rs.getObject(i) + " "); - } - System.out.println(""); + private long findPID() { + long result = -1; + String pidFile = globalVariables.get("PID_FILE"); + File file = new File(pidFile); + if (file.canRead()) { + try { + FileReader pidFileReader = new FileReader(file); + char pidData[] = new char[(int)file.length()]; + pidFileReader.read(pidData); + String pidString = new String(pidData); + pidString = pidString.trim(); + result = Long.valueOf(pidString); + } catch (Exception ex) { + log.warn("Unable to read MySQL pid file " + pidFile); } - } catch (SQLException ex) { - // handle any errors - log.info("SQLException: " + ex.getMessage()); - log.info("SQLState: " + ex.getSQLState()); - log.info("VendorError: " + ex.getErrorCode()); } + return result; } } diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionInfo.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionInfo.java new file mode 100644 index 0000000..4fa0a4f --- /dev/null +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionInfo.java @@ -0,0 +1,92 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.plugins.mysql; + +/** + * A class to act as a key to a specific MySQL connection + * @author Steve Millidge (C2B2 Consulting Limited) + */ +class MySqlConnectionInfo { + + private String host; + private String port; + private String db; + private String user; + private String password; + private int hashCode; + + MySqlConnectionInfo(String host, String port, String db, String user, String password ) { + this.host = host; + this.port = port; + this.db = db; + this.user = user; + this.password = password; + this.hashCode = new StringBuilder().append(host). + append(port). + append(db). + append(user). + append(password).toString().hashCode(); + + } + + public String getDb() { + return db; + } + + @Override + public int hashCode() { + return hashCode; + } + + public String getHost() { + return host; + } + + public String getPassword() { + return password; + } + + public String getPort() { + return port; + } + + public String getUser() { + return user; + } + + public String buildURL() { + return new StringBuilder().append("jdbc:mysql://") + .append(host) + .append(":") + .append(port) + .append("/") + .append(db).toString(); + } + + @Override + public boolean equals(Object other) { + boolean result = false; + if ((other instanceof MySqlConnectionInfo) && (other.hashCode() == this.hashCode())) { + result = true; + } + return result; + } + +} diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java new file mode 100644 index 0000000..9dd60ee --- /dev/null +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlConnectionManager.java @@ -0,0 +1,124 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.plugins.mysql; + +import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.HashMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A class to manage the connections to MySQL + * This class keeps a cache of connections to MySQL and reuses them on demand + * We assume single threaded access to the Connection in the agent + * this will need to be reworked if that assumption is not correct + * @author Steve Millidge (C2B2 Consulting Limited) + */ +class MySqlConnectionManager { + + private HashMap<MySqlConnectionInfo, Connection> connections; + private static MySqlConnectionManager singleton; + private Log logger = LogFactory.getLog(MySqlConnectionManager.class); + + private MySqlConnectionManager() { + connections = new HashMap<MySqlConnectionInfo,Connection>(); + try { + Class.forName("com.mysql.jdbc.Driver").newInstance(); + } catch (Exception ex) { + logger.error("Unable to find com.mysql.jdbc.Driver"); + } + } + + static MySqlConnectionManager getConnectionManager() { + if (singleton == null) { + singleton = new MySqlConnectionManager(); + } + return singleton; + } + + public void shutdown() { + Driver driver = null; + for (Connection conn : connections.values()) { + try { + if (driver == null) { + String driverName = conn.getMetaData().getDriverName(); + driver = DriverManager.getDriver(driverName); + } + conn.close(); + }catch(SQLException e) { logger.info("Problem closing connection on Shutdown ignoring...");} + } + // deregister driver as well + if (driver != null) { + try { + DriverManager.deregisterDriver(driver); + } catch (SQLException ex) { + logger.warn("Unable to deregister MySQL Driver on shutdown"); + } + } + } + + void closeConnection(MySqlConnectionInfo info) { + Connection conn = connections.get(info); + if (conn != null) { + try { + if (logger.isDebugEnabled()) { + logger.debug("Closing Connection to " + info.buildURL()); + } + conn.close(); + } catch (SQLException e) { + logger.warn("Problem closing connection to " + info.buildURL() + " on close"); + } + } + connections.remove(info); + } + + Connection getConnection (MySqlConnectionInfo info) throws SQLException { + Connection conn = connections.get(info); + String url = info.buildURL(); + if (conn == null) { + if (logger.isInfoEnabled()) { + logger.info("Attemping connection to " + url); + } + conn = DriverManager.getConnection(url,info.getUser(), info.getPassword()); + if (logger.isInfoEnabled()) { + logger.info("Successfully connected to " + url); + } + connections.put(info, conn); + } else { + if (logger.isDebugEnabled()) { + logger.debug("Reusing existing connection to " + url); + } + } + + // check the validity of the connection + if (!conn.isValid(0)) { + // attempt a single reconnect here and now + conn.close(); + conn = DriverManager.getConnection(url,info.getUser(), info.getPassword()); + connections.put(info, conn); + logger.info("Refreshed a connection to " + url); + } + return conn; + } + +} diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseComponent.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseComponent.java new file mode 100644 index 0000000..43747bc --- /dev/null +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseComponent.java @@ -0,0 +1,167 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.plugins.mysql; + + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.pluginapi.availability.AvailabilityFacet; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import org.rhq.core.pluginapi.inventory.ResourceContext; +import org.rhq.core.pluginapi.operation.OperationFacet; +import org.rhq.core.pluginapi.operation.OperationResult; +import org.rhq.plugins.database.DatabaseComponent; +import org.rhq.plugins.database.DatabaseQueryUtility; +import org.rhq.core.domain.configuration.PropertySimple; +import org.rhq.core.domain.measurement.AvailabilityType; + +/** + * + * @author Steve Millidge (C2B2 Consulting Limited) + */ +public class MySqlDatabaseComponent implements DatabaseComponent, AvailabilityFacet, OperationFacet { + + private ResourceContext resourceContext; + private MySqlComponent parent; + private String databaseName; + private static Log log = LogFactory.getLog(MySqlDatabaseComponent.class); + + @Override + public Connection getConnection() { + return parent.getConnection(); + } + + @Override + public void removeConnection() { + parent.removeConnection(); + } + + @Override + public void start(ResourceContext rc) throws InvalidPluginConfigurationException, Exception { + resourceContext = rc; + databaseName = rc.getResourceKey(); + parent = (MySqlComponent)resourceContext.getParentResourceComponent(); + } + + public String getName() { return databaseName; } + + @Override + public void stop() { + } + + @Override + public AvailabilityType getAvailability() { + AvailabilityType result = AvailabilityType.DOWN; + + if (log.isDebugEnabled()) { + log.debug("Availability check for " + databaseName); + } + Connection conn = getConnection(); + if (conn != null) { + Statement statement = null; + ResultSet resultSet = null; + try { + statement = conn.createStatement(); + resultSet = statement.executeQuery("SHOW DATABASES LIKE '" + databaseName + "'"); + if (resultSet.next()) { + if (resultSet.getString(1).equalsIgnoreCase(databaseName)) { + result = AvailabilityType.UP; + } + } + }catch(SQLException e) { + if (log.isDebugEnabled()) { + log.debug("Got Exception when determining database availability",e); + } + } finally { + DatabaseQueryUtility.close(statement, resultSet); + } + } + return result; + } + + @Override + public OperationResult invokeOperation(String name, Configuration parameters) + throws InterruptedException, Exception { + + if ("invokeSql".equals(name)) { + Statement stmt = null; + ResultSet rs = null; + try { + stmt = getConnection().createStatement(); + String sql = parameters.getSimple("sql").getStringValue(); + OperationResult result = new OperationResult(); + + if (parameters.getSimple("type").getStringValue().equals("update")) { + int updateCount = stmt.executeUpdate(sql); + result.getComplexResults().put(new PropertySimple("result", "Query updated " + updateCount + " rows")); + + } else { + rs = stmt.executeQuery(parameters.getSimple("sql").getStringValue()); + + ResultSetMetaData md = rs.getMetaData(); + StringBuilder buf = new StringBuilder(); + int rowCount = 0; + + buf.append("<table>"); + buf.append("<th>"); + for (int i = 1; i <= md.getColumnCount(); i++) { + buf.append("<td>"); + buf.append(md.getColumnName(i) + " (" + md.getColumnTypeName(i) + ")"); + buf.append("</td>"); + } + buf.append("</th>"); + + + while (rs.next()) { + rowCount++; + buf.append("<tr>"); + for (int i = 1; i <= md.getColumnCount(); i++) { + buf.append("<td>"); + buf.append(rs.getString(i)); + buf.append("</td>"); + } + buf.append("</tr>"); + } + + buf.append("</table>"); + result.getComplexResults().put(new PropertySimple("result", "Query returned " + rowCount + " rows")); + result.getComplexResults().put(new PropertySimple("contents", buf.toString())); + } + return result; + } finally { + if (rs != null) { + rs.close(); + } + + if (stmt != null) { + stmt.close(); + } + } + } else { + throw new UnsupportedOperationException("Operation [" + name + "] is not supported yet."); + } + } +} + diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseDiscoveryComponent.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseDiscoveryComponent.java index e34f021..c8f8673 100644 --- a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseDiscoveryComponent.java +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDatabaseDiscoveryComponent.java @@ -16,7 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - package org.rhq.plugins.mysql;
import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; @@ -30,46 +29,62 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.LinkedHashSet; import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.PropertySimple;
/** * @author Greg Hinkle + * @author Steve Millidge */ public class MySqlDatabaseDiscoveryComponent implements ResourceDiscoveryComponent<MySqlComponent> {
+ private Log logger = LogFactory.getLog(this.getClass());
- + @Override public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext<MySqlComponent> context) { - Set<DiscoveredResourceDetails> tables = new LinkedHashSet<DiscoveredResourceDetails>(); -
+ if (logger.isDebugEnabled()) { + logger.debug("Database discovery started"); + } + Set<DiscoveredResourceDetails> databases = new LinkedHashSet<DiscoveredResourceDetails>(); Connection connection = context.getParentResourceComponent().getConnection();
Statement statement = null; ResultSet resultSet = null; - try { - statement = connection.createStatement(); - resultSet = statement.executeQuery("SHOW DATABASES"); + if (connection != null) { + try { + statement = connection.createStatement(); + resultSet = statement.executeQuery("SHOW DATABASES");
- while (resultSet.next()) { - String databaseName = resultSet.getString(1); - DiscoveredResourceDetails details = - new DiscoveredResourceDetails( - context.getResourceType(), - databaseName, - databaseName + " Database", - null, - "A MySql Database", - null, - null); - tables.add(details); - } + while (resultSet.next()) { + String databaseName = resultSet.getString(1); + Configuration config = new Configuration(); + config.put(new PropertySimple("databaseName",databaseName)); + DiscoveredResourceDetails details = + new DiscoveredResourceDetails( + context.getResourceType(), + databaseName, + databaseName + " Database", + null, + "A MySql Database", + config, + null); + databases.add(details); + }
- } catch (SQLException e) { - DatabaseQueryUtility.close(statement, resultSet); + } catch (SQLException e) { + } finally { + DatabaseQueryUtility.close(statement, resultSet); + } + } else { + if (logger.isInfoEnabled()) { + logger.info("No connection to MySQL obtained from connection manager"); + } }
- return tables; + return databases; } - -} \ No newline at end of file +} diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDiscoveryComponent.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDiscoveryComponent.java index 4f1045e..30b65f2 100644 --- a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDiscoveryComponent.java +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlDiscoveryComponent.java @@ -30,7 +30,6 @@ import org.rhq.core.pluginapi.inventory.ManualAddFacet; import org.rhq.core.system.ProcessInfo;
import java.sql.Connection; -import java.sql.DriverManager; import java.sql.SQLException; import java.util.LinkedHashSet; import java.util.List; @@ -39,20 +38,22 @@ import java.util.Set; /** * @author Greg Hinkle * @author Ian Springer + * @author Steve Millidge */ public class MySqlDiscoveryComponent implements ResourceDiscoveryComponent, ManualAddFacet { private static final Log log = LogFactory.getLog(MySqlDiscoveryComponent.class);
- public static final String DRIVER_CONFIGURATION_PROPERTY = "driverClass"; public static final String HOST_CONFIGURATION_PROPERTY = "host"; public static final String PORT_CONFIGURATION_PROPERTY = "port"; public static final String DB_CONFIGURATION_PROPERTY = "db"; public static final String PRINCIPAL_CONFIGURATION_PROPERTY = "principal"; public static final String CREDENTIALS_CONFIGURATION_PROPERTY = "credentials";
- private static final String DEFAULT_RESOURCE_DESCRIPTION = "Mysql relational database server"; - public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext context) { + + if (log.isDebugEnabled()) { + log.debug("Resource Discovery Started"); + } Set<DiscoveredResourceDetails> servers = new LinkedHashSet<DiscoveredResourceDetails>();
// Process any auto-discovered resources. @@ -62,10 +63,7 @@ public class MySqlDiscoveryComponent implements ResourceDiscoveryComponent, Manu
ProcessInfo procInfo = result.getProcessInfo();
- DiscoveredResourceDetails resourceDetails = createResourceDetails(context, context.getDefaultPluginConfiguration(), procInfo); - if (resourceDetails!=null) { - servers.add(resourceDetails); - } + servers.add(createResourceDetails(context,context.getDefaultPluginConfiguration(),procInfo)); }
return servers; @@ -81,56 +79,53 @@ public class MySqlDiscoveryComponent implements ResourceDiscoveryComponent, Manu }
protected static DiscoveredResourceDetails createResourceDetails(ResourceDiscoveryContext discoveryContext, - Configuration pluginConfiguration, ProcessInfo processInfo) { - - String key = buildUrl(pluginConfiguration); - String db = pluginConfiguration.getSimple(DB_CONFIGURATION_PROPERTY).getStringValue(); - String name = "MySql [" + db + "]"; - try { - String version = getVersion(pluginConfiguration); - return new DiscoveredResourceDetails(discoveryContext.getResourceType(), key, name, version, - DEFAULT_RESOURCE_DESCRIPTION, pluginConfiguration, processInfo); - } catch (Exception e) { - log.warn("Getting details failed: " + e.getMessage()); - if (e.getCause()!=null) { - log.warn(" caused by: " + e.getCause().getMessage()); - } - } - return null; - } + Configuration pluginConfiguration, + ProcessInfo processInfo) throws InvalidPluginConfigurationException {
- protected static String buildUrl(Configuration config) { - String host = config.getSimple(HOST_CONFIGURATION_PROPERTY).getStringValue(); - String port = config.getSimple(PORT_CONFIGURATION_PROPERTY).getStringValue(); - String user = config.getSimple(PRINCIPAL_CONFIGURATION_PROPERTY).getStringValue(); - String pass = config.getSimple(CREDENTIALS_CONFIGURATION_PROPERTY).getStringValue(); - String url = "jdbc:mysql://" + host + "?user=" + user + "&password=" + pass; - return url; - } - - protected static String getVersion(Configuration config) { - String version = null; + MySqlConnectionInfo ci = buildConnectionInfo(pluginConfiguration); + Connection conn; + String version = ""; try { - Connection conn = buildConnection(config); + conn = MySqlConnectionManager.getConnectionManager().getConnection(ci); version = conn.getMetaData().getDatabaseProductVersion(); - } catch (SQLException e) { - // TODO GH: How to put this back to the server while inventorying this resource in an unconfigured state - log.info("Exception detecting mysql instance version" + e.getMessage()); + } catch (SQLException ex) { + // ignore so we can still add to the inventory even though we can't currently connect } - return version; - } + String key = new StringBuilder().append("MySql:") + .append(ci.getDb()) + .append(":") + .append(ci.getHost()) + .append(":") + .append(ci.getPort()) + .append("-") + .append(ci.getUser()).toString(); + String name = new StringBuilder().append("MySql [") + .append(ci.getDb()) + .append("]").toString(); + + DiscoveredResourceDetails result = new DiscoveredResourceDetails( + discoveryContext.getResourceType(), + key, + name, + version, + "MySql Server", + pluginConfiguration, + processInfo);
- public static Connection buildConnection(Configuration configuration) throws SQLException { - String driverClass = configuration.getSimple(DRIVER_CONFIGURATION_PROPERTY).getStringValue(); - try { - Class.forName(driverClass); - } catch (ClassNotFoundException e) { - throw new InvalidPluginConfigurationException("Specified JDBC driver class (" + driverClass - + ") not found."); + if (log.isDebugEnabled()) { + log.debug("Discovered Database Server for MySQL Database " + ci.buildURL()); } + return result;
- String url = buildUrl(configuration); - - return DriverManager.getConnection(url); } + + static MySqlConnectionInfo buildConnectionInfo(Configuration configuration) { + // build the Discovered Resource from the configuration + String host = configuration.getSimple(HOST_CONFIGURATION_PROPERTY).getStringValue(); + String port = configuration.getSimple(PORT_CONFIGURATION_PROPERTY).getStringValue(); + String user = configuration.getSimple(PRINCIPAL_CONFIGURATION_PROPERTY).getStringValue(); + String pass = configuration.getSimple(CREDENTIALS_CONFIGURATION_PROPERTY).getStringValue(); + String db = configuration.getSimple(DB_CONFIGURATION_PROPERTY).getStringValue(); + return new MySqlConnectionInfo(host, port, db, user, pass); + } } \ No newline at end of file diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPluginLifecycleListener.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPluginLifecycleListener.java index 181a113..a731aed 100644 --- a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPluginLifecycleListener.java +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlPluginLifecycleListener.java @@ -18,39 +18,29 @@ */ package org.rhq.plugins.mysql;
-import java.sql.Driver; -import java.sql.DriverManager; -import java.util.Enumeration;
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory;
import org.rhq.core.pluginapi.plugin.PluginContext; import org.rhq.core.pluginapi.plugin.PluginLifecycleListener; -import org.rhq.core.util.exception.ThrowableUtil;
+/** + * + * @author Steve Millidge (C2B2 Consulting Limited) + */ public class MySqlPluginLifecycleListener implements PluginLifecycleListener { private final Log log = LogFactory.getLog(MySqlPluginLifecycleListener.class); + private String pluginName;
public void initialize(PluginContext context) throws Exception { - // no-op + pluginName = context.getPluginName(); }
public void shutdown() { - // so we do not cause our classloader to leak perm gen, we need to de-register - // any and all JDBC drivers this plugin registered - Enumeration<Driver> drivers = DriverManager.getDrivers(); - while (drivers.hasMoreElements()) { - try { - Driver driver = drivers.nextElement(); - DriverManager.deregisterDriver(driver); - log.debug("Deregistered JDBC driver: " + driver.getClass()); - } catch (Exception e) { - log.warn("Failed to deregister JDBC drivers - memory might leak" + ThrowableUtil.getAllMessages(e)); - } + if (log.isDebugEnabled()) { + log.debug(new StringBuilder().append(pluginName).append(" Plugin Shutdown").toString()); } - - log.debug(this.getClass().getSimpleName() + " completed shutdown."); - return; + MySqlConnectionManager.getConnectionManager().shutdown(); } } diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableComponent.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableComponent.java new file mode 100644 index 0000000..73354f9 --- /dev/null +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableComponent.java @@ -0,0 +1,129 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.plugins.mysql; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.rhq.core.domain.measurement.AvailabilityType; +import org.rhq.core.domain.measurement.MeasurementDataNumeric; +import org.rhq.core.domain.measurement.MeasurementDataTrait; +import org.rhq.core.domain.measurement.MeasurementReport; +import org.rhq.core.domain.measurement.MeasurementScheduleRequest; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import org.rhq.core.pluginapi.inventory.ResourceContext; +import org.rhq.core.pluginapi.measurement.MeasurementFacet; +import org.rhq.plugins.database.DatabaseComponent; +import org.rhq.plugins.database.DatabaseQueryUtility; + +/** + * + * @author Steve Millidge (C2B2 Consulting Limited) + */ +public class MySqlTableComponent implements DatabaseComponent, MeasurementFacet { + + private String tableName; + private MySqlDatabaseComponent parent; + private String databaseName; + private Log log = LogFactory.getLog(this.getClass()); + + @Override + public Connection getConnection() { + return parent.getConnection(); + } + + @Override + public void removeConnection() { + parent.removeConnection(); + } + + @Override + public void start(ResourceContext rc) throws InvalidPluginConfigurationException, Exception { + tableName = rc.getResourceKey(); + parent = (MySqlDatabaseComponent)rc.getParentResourceComponent(); + databaseName = parent.getName(); + } + + @Override + public void stop() { + } + + @Override + public AvailabilityType getAvailability() { + AvailabilityType result = AvailabilityType.DOWN; + Connection conn = parent.getConnection(); + if (conn != null) { + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery("show tables from " + databaseName + " like '" + tableName + "'"); + if (rs.first()) { + result = AvailabilityType.UP; + } + }catch (SQLException se) { + // ignore as unablailable if we can't execute the query + }finally { + DatabaseQueryUtility.close(stmt, rs); + } + } + return result; + } + + @Override + public void getValues(MeasurementReport mr, Set<MeasurementScheduleRequest> set) throws Exception { + Connection conn = parent.getConnection(); + if (conn != null ) { + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery("show table status from " + databaseName+ " like '" + tableName + "'"); + if (rs.next()) { + for (MeasurementScheduleRequest request : set) { + String value = rs.getString(request.getName()); + if (value == null) {value = "0";} + switch (request.getDataType()) { + case MEASUREMENT: { + mr.addData(new MeasurementDataNumeric(request, Double.valueOf(value))); + break; + } case TRAIT: { + mr.addData(new MeasurementDataTrait(request, value)); + break; + } default: { + break; + } + } + } + } + } catch(Exception se) { + if (log.isInfoEnabled()) { + log.info("Unable to measure table statistics", se); + } + }finally { + DatabaseQueryUtility.close(stmt, rs); + } + } + } + +} diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableDiscoveryComponent.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableDiscoveryComponent.java new file mode 100644 index 0000000..5b62118 --- /dev/null +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlTableDiscoveryComponent.java @@ -0,0 +1,85 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.plugins.mysql; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashSet; +import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.PropertySimple; +import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext; +import org.rhq.plugins.database.DatabaseQueryUtility; + +/** + * + * @author Steve Millidge (C2B2 Consulting Limited) + */ +public class MySqlTableDiscoveryComponent implements ResourceDiscoveryComponent { + + private Log log = LogFactory.getLog(this.getClass()); + + @Override + public Set discoverResources(ResourceDiscoveryContext rdc) throws InvalidPluginConfigurationException, Exception { + + HashSet<DiscoveredResourceDetails> set = new HashSet<DiscoveredResourceDetails>(); + MySqlDatabaseComponent parent = (MySqlDatabaseComponent)rdc.getParentResourceComponent(); + Connection conn = parent.getConnection(); + + if (conn != null) { + Statement stmt = null; + ResultSet rs = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery("show tables from " + parent.getName()); + while (rs.next()) { + String tableName = rs.getString(1); + if (log.isDebugEnabled()) { + log.debug("Discovered Table "+ tableName); + } + Configuration config = new Configuration(); + config.put(new PropertySimple("tableName",tableName)); + DiscoveredResourceDetails details = new DiscoveredResourceDetails( + rdc.getResourceType(), + tableName, + tableName + " Table", + null, + tableName + " MySql Table", config, null); + set.add(details); + } + } catch(SQLException se) { + if (log.isDebugEnabled()) { + log.debug("Unable to Discover Tables",se); + } + + }finally { + DatabaseQueryUtility.close(stmt, rs); + } + } + return set; + } + +} diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserComponent.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserComponent.java new file mode 100644 index 0000000..32525c2 --- /dev/null +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserComponent.java @@ -0,0 +1,128 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +package org.rhq.plugins.mysql; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Set; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.rhq.core.domain.measurement.AvailabilityType; +import org.rhq.core.domain.measurement.MeasurementDataNumeric; +import org.rhq.core.domain.measurement.MeasurementReport; +import org.rhq.core.domain.measurement.MeasurementScheduleRequest; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import org.rhq.core.pluginapi.inventory.ResourceContext; +import org.rhq.core.pluginapi.measurement.MeasurementFacet; +import org.rhq.plugins.database.DatabaseComponent; +import org.rhq.plugins.database.DatabaseQueryUtility; + +/** + * + * @author Steve Millidge (C2B2 Consulting Limited) + */ +public class MySqlUserComponent implements MeasurementFacet, DatabaseComponent { + + private String userName; + private String host; + private MySqlComponent parent; + private Log log = LogFactory.getLog(this.getClass()); + private ResourceContext context; + + @Override + public Connection getConnection() { + return parent.getConnection(); + } + + @Override + public void removeConnection() { + parent.removeConnection(); + } + + @Override + public void start(ResourceContext rc) throws InvalidPluginConfigurationException, Exception { + parent = (MySqlComponent)rc.getParentResourceComponent(); + context = rc; + userName = context.getPluginConfiguration().getSimple("userName").getStringValue(); + host = context.getPluginConfiguration().getSimple("host").getStringValue(); + } + + @Override + public void stop() { + } + + + public void getValues(MeasurementReport mr, Set<MeasurementScheduleRequest> requests) throws Exception { + Connection conn = getConnection(); + ResultSet rs = null; + Statement stmt = null; + int activeConnections = 0; + int totalConnections = 0; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery("select User,Host,State from information_schema.processlist where User='"+userName+"'"); + while(rs.next()) { + String hostVal = rs.getString(2); + String state = rs.getString(3); + if (hostVal.startsWith(host)) { + if (state.length() > 1) { + activeConnections ++; + } + totalConnections++; + } + } + }catch(SQLException sqle) { + + } finally { + DatabaseQueryUtility.close(stmt, rs); + } + + for (MeasurementScheduleRequest request : requests) { + if (request.getName().equals("TotalConnections")) { + mr.addData(new MeasurementDataNumeric(request, new Double((double)totalConnections))); + } else if (request.getName().equals("ActiveConnections")) { + mr.addData(new MeasurementDataNumeric(request, new Double((double)activeConnections))); + } + } + } + + public AvailabilityType getAvailability() { + AvailabilityType result = AvailabilityType.DOWN; + Connection conn = getConnection(); + ResultSet rs = null; + Statement stmt = null; + try { + stmt = conn.createStatement(); + rs = stmt.executeQuery("select User from mysql.user where User='"+userName+"' and Host='" + host +"'"); + if (rs.first()) { + result = AvailabilityType.UP; + } + }catch(SQLException sqle) { + + } finally { + DatabaseQueryUtility.close(stmt, rs); + } + return result; + } + +} diff --git a/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserDiscoveryComponent.java b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserDiscoveryComponent.java new file mode 100644 index 0000000..d05682a --- /dev/null +++ b/modules/plugins/mysql/src/main/java/org/rhq/plugins/mysql/MySqlUserDiscoveryComponent.java @@ -0,0 +1,76 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.plugins.mysql; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.HashSet; +import java.util.Set; +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.Property; +import org.rhq.core.domain.configuration.PropertySimple; +import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; +import org.rhq.core.pluginapi.inventory.InvalidPluginConfigurationException; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext; +import org.rhq.plugins.database.DatabaseQueryUtility; + +/** + * + * @author Steve Millidge (C2B2 Consulting Limited) + */ +public class MySqlUserDiscoveryComponent implements ResourceDiscoveryComponent { + + public Set discoverResources(ResourceDiscoveryContext rdc) throws InvalidPluginConfigurationException, Exception { + HashSet<DiscoveredResourceDetails> set = new HashSet<DiscoveredResourceDetails>(); + MySqlComponent parent = (MySqlComponent) rdc.getParentResourceComponent(); + Connection conn = parent.getConnection(); + if (conn != null) { + Statement statement = null; + ResultSet resultSet = null; + try { + statement = conn.createStatement(); + resultSet = statement.executeQuery("select User,Host from mysql.user"); + while (resultSet.next()) { + String user = resultSet.getString(1); + String host = resultSet.getString(2); + String userName = user + "@" + host; + Configuration config = new Configuration(); + config.put(new PropertySimple("userName",user)); + config.put(new PropertySimple("host",host)); + DiscoveredResourceDetails discoveredUser = + new DiscoveredResourceDetails( + rdc.getResourceType(), + userName, + userName, + null, + "A MySql User", + config, + null); + set.add(discoveredUser); + } + } catch (Exception e) { + } finally { + DatabaseQueryUtility.close(statement, resultSet); + } + } + return set; + } +} diff --git a/modules/plugins/mysql/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/mysql/src/main/resources/META-INF/rhq-plugin.xml index d94a60f..6a96c19 100644 --- a/modules/plugins/mysql/src/main/resources/META-INF/rhq-plugin.xml +++ b/modules/plugins/mysql/src/main/resources/META-INF/rhq-plugin.xml @@ -15,8 +15,6 @@ description="MySql Server" supportsManualAdd="true">
- <version match="8.0"/> - <!-- Properties are connection/lookup configurations. They are values that the plugin components need to connect and interact with the resource. --> <plugin-configuration> @@ -31,45 +29,31 @@ <c:integer-constraint minimum="1" maximum="65535"/> </c:constraint> </c:simple-property> - <c:simple-property name="db" default="MySql" displayName="database name" description="the name of the database to connect to"/> - - <c:simple-property name="driverClass" default="com.mysql.jdbc.Driver" displayName="JDBC driver class" - description="the fully-qualified classname of the JDBC driver class" required="false"/> - <c:simple-property name="principal" default="MySql" displayName="role name" description="the database role to connect as"/> - <c:simple-property name="credentials" default="MySql" type="password" displayName="role password" + <c:simple-property name="db" default="mysql" displayName="database name" description="the name of the database to connect to"/> + <c:simple-property name="principal" default="root" displayName="role name" description="the database role to connect as"/> + <c:simple-property name="credentials" default="root" type="password" displayName="role password" description="the password for the database role being used to connect"/> </plugin-configuration>
<process-scan name="windows" query="process|basename|match=^(?i)mysqld\.exe$,process|basename|nomatch|parent=^(?i)mysqld\.exe$" /> <process-scan name="unix" query="process|basename|match=^mysqld$,process|basename|nomatch|parent=^mysqld$" />
- <operation name="listProcessStatistics" description="List statistics about the currently executing MySql backends"> - <results> - <c:list-property name="processList"> - <c:map-property name="process"> - <c:simple-property name="Id" type="integer"/> - <c:simple-property name="User"/> - <c:simple-property name="Host"/> - <c:simple-property name="db"/> - <c:simple-property name="Command"/> - <c:simple-property name="Time"/> - <c:simple-property name="State"/> - <c:simple-property name="Info"/> - </c:map-property> - </c:list-property> - </results> - </operation> - - - - <metric displayName="User Time" property="Process.aggregateCpu.user" measurementType="trendsup" units="milliseconds" displayType="summary"/> - <metric displayName="Kernel Time" property="Process.aggregateCpu.sys" measurementType="trendsup" units="milliseconds" displayType="summary"/> - <metric displayName="CPU Percentage" property="Process.aggregateCpu.percent" measurementType="dynamic" units="percentage" displayType="summary"/> - <metric displayName="Physical Memory" property="Process.aggregateMemory.resident" measurementType="dynamic" units="bytes" displayType="summary"/> - <metric displayName="Virtual Memory" property="Process.aggregateMemory.size" measurementType="dynamic" units="bytes" displayType="summary"/> - <metric displayName="Open File Descriptors" property="Process.aggregateFileDescriptor.total" measurementType="dynamic" displayType="summary"/> - - + <metric displayName="Physical Memory" property="Process.aggregateMemory.resident" measurementType="dynamic" units="bytes" displayType="summary" + description="The aggregate amount of resident memory used by all mysql processes"/> + <metric displayName="Virtual Memory" property="Process.aggregateMemory.size" measurementType="dynamic" units="bytes" displayType="summary" + description="The aggregate amount of virtual memory used by all mysql processes"/> + <metric displayName="Page Faults" property="Process.aggregateMemory.pageFaults" measurementType="trendsup" displayType="summary" + description="The Number of memory page faults by all mysql processes"/> + <metric displayName="User Time" property="Process.aggregateCpu.user" measurementType="trendsup" units="milliseconds" displayType="summary" + description="The aggregate amount of CPU user time spent by all mysql processes"/> + <metric displayName="Kernel Time" property="Process.aggregateCpu.sys" measurementType="trendsup" units="milliseconds" displayType="summary" + description="The aggregate amount of CPU kernel time spent by all mysql processes"/> + <metric displayName="CPU Percentage" property="Process.aggregateCpu.percent" measurementType="dynamic" units="percentage" displayType="summary" + description="The percentage of CPU currently being used by all mysql processes"/> + <metric displayName="Total CPU Time" property="Process.aggregateCpu.total" measurementType="trendsup" units="milliseconds" displayType="summary" + description="The aggregate amount of CPU time spent by all mysql processes"/> + <metric displayName="Open File Descriptors" property="Process.aggregateFileDescriptor.total" measurementType="dynamic" displayType="summary" + description="The aggregate number of file descriptors open by all mysql processes"/>
<metric property="Aborted_clients" measurementType="trendsup" description="Connections that aborted because the client did not close the connection"/> @@ -353,10 +337,10 @@ <c:simple-property name="databaseName" displayName="Database Name" readOnly="true" /> </plugin-configuration>
- <operation name="resetStatistics" displayName="Reset Statistics" description="Resets the statistics in this database"/> <operation name="invokeSql" description="Execute arbitrary SQL"> <parameters> - <c:simple-property name="type" default="query"> + <c:simple-property name="sql"/> + <c:simple-property name="type" default="query"> <c:property-options> <c:option value="query" name="query"/> <c:option value="update" name="update"/> @@ -370,39 +354,39 @@ </results> </operation>
- - <metric displayName="Backends" property="numbackends" displayType="summary"/> - <metric displayName="Transactions Committed" property="xact_commit" measurementType="trendsup" displayType="summary"/> - <metric displayName="Transactions Rolled Back" property="xact_rollback" measurementType="trendsup" displayType="summary"/> - <metric displayName="Blocks Read" property="blks_read" measurementType="trendsup"/> - <metric displayName="Blocks Hit" property="blks_hit" measurementType="trendsup"/> - <metric displayName="Size" property="size" description="Size of the database" units="bytes" displayType="summary"/> - - - - <service name="Table" class="MySqlTableComponent" discovery="MySqlTableDiscoveryComponent" - description="Database table" createDeletePolicy="both" creationDataType="configuration"> + <service name="Table" class="MySqlTableComponent" discovery="MySqlTableDiscoveryComponent" + description="Database table">
<plugin-configuration> <c:simple-property name="tableName" readOnly="true" /> </plugin-configuration> - - - + <!-- Summary Traits --> + <metric property="Engine" displayType="summary" dataType="trait" description="Database Engine that created the Table" defaultOn="true"/> + <metric property="Version" displayType="summary" dataType="trait" description="Version of the Table" defaultOn="true"/> + <metric property="Row_format" displayType="summary" dataType="trait" description="Row Format" defaultOn="true"/> + <metric property="Collation" displayType="summary" dataType="trait" description="Collation Character Set" defaultOn="true"/> + <metric property="Comment" displayType="summary" dataType="trait" description="Table Creation Comment" defaultOn="true"/> + <metric property="Create_options" displayType="summary" dataType="trait" description="Table Creation Options" defaultOn="true"/> + <metric property="Create_time" displayType="summary" dataType="trait" description="Table Creation Time" defaultOn="true"/> + + <!-- Dynamic Metrics --> + <metric property="Rows" displayType="summary" measurementType="dynamic" description="Number of Rows in the Table" defaultOn="true"/> + <metric property="Avg_row_length" displayType="summary" measurementType="dynamic" units="bytes" description="Average Row Length(bytes)" defaultOn="true"/> + <metric property="Data_length" displayType="summary" measurementType="dynamic" units="bytes" description="Table Data Size(bytes)" defaultOn="true"/> + <metric property="Max_data_length" displayType="summary" measurementType="dynamic" units="bytes" description="Max Table Data Size(bytes)" defaultOn="true"/> + <metric property="Index_length" displayType="summary" measurementType="dynamic" units="bytes" description="Table Index Size(bytes)" defaultOn="true"/> + <metric property="Data_free" displayType="summary" measurementType="dynamic" units="bytes" description="Table Free Space(bytes)" defaultOn="true"/> </service> - - </service> - - <service name="User" discovery="MySqlUserDiscoveryComponent" class="MySqlUserComponent" - createDeletePolicy="both" creationDataType="configuration" - description="A User in the MySql System"> - <plugin-configuration> - <c:simple-property name="userName" required="true"/> - </plugin-configuration> - - - </service> + <service name="User" class="MySqlUserComponent" discovery="MySqlUserDiscoveryComponent" + description="A MySQL User"> + <plugin-configuration> + <c:simple-property name="userName" readOnly="true" /> + <c:simple-property name="host" readOnly="true" /> + </plugin-configuration> + <metric property="TotalConnections" displayType="summary" description="Total number of connections to the server"/> + <metric property="ActiveConnections" displayType="summary" description="Active Connections to the server"/> + </service> </server>
</plugin> \ No newline at end of file
rhq-commits@lists.fedorahosted.org