/* * * * RHQ Management Platform * * Copyright (C) 2005-2012 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, version 2, as * * published by the Free Software Foundation, and/or the GNU Lesser * * General Public License, version 2.1, also as published by the Free * * Software Foundation. * * * * 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 and the GNU Lesser General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License * * and the GNU Lesser General Public License along with this program; * * if not, write to the Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package org.rhq.plugins.cassandra; import java.io.File; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mc4j.ems.connection.EmsConnection; import org.mc4j.ems.connection.bean.EmsBean; import org.mc4j.ems.connection.bean.attribute.EmsAttribute; import org.mc4j.ems.connection.bean.operation.EmsOperation; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.ConfigurationUpdateStatus; import org.rhq.core.domain.configuration.PropertyList; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.pluginapi.configuration.ConfigurationFacet; import org.rhq.core.pluginapi.configuration.ConfigurationUpdateReport; import org.rhq.core.pluginapi.inventory.ResourceComponent; 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.cassandra.util.KeyspaceService; import org.rhq.plugins.jmx.JMXComponent; /** * @author John Sanda */ public class KeyspaceComponent implements ResourceComponent<ResourceComponent<?>>, ConfigurationFacet, JMXComponent<ResourceComponent<?>>, OperationFacet { private final Log log = LogFactory.getLog(KeyspaceComponent.class); private ResourceContext<ResourceComponent<?>> context; @Override public void start(ResourceContext<ResourceComponent<?>> context) throws Exception { this.context = context; } @Override public void stop() { } @Override public AvailabilityType getAvailability() { return context.getParentResourceComponent().getAvailability(); } @Override public EmsConnection getEmsConnection() { JMXComponent<?> parent = (JMXComponent<?>) context.getParentResourceComponent(); return parent.getEmsConnection(); } @Override public Configuration loadResourceConfiguration() throws Exception { Configuration config = new Configuration(); config.put(new PropertySimple("name", context.getResourceKey())); config.put(this.getKeySpaceDataFileLocations()); return config; } @Override public void updateResourceConfiguration(ConfigurationUpdateReport report) { report.setStatus(ConfigurationUpdateStatus.NOCHANGE); } @Override public OperationResult invokeOperation(String name, Configuration parameters) throws Exception { if (name.equals("repair")) { return repairKeyspace(); } else if (name.equals("repairPrimaryRange")) { return repairPrimaryRange(); } else if (name.equals("compact")) { return compactKeyspace(); } else if (name.equals("takeSnapshot")) { return takeSnapshot(parameters); } else if (name.equals("cleanup")) { return cleanup(); } OperationResult failedOperation = new OperationResult(); failedOperation.setErrorMessage("Operation not implemented."); return failedOperation; } public OperationResult repairKeyspace(String... columnFamilies) { KeyspaceService keyspaceService = new KeyspaceService(getEmsConnection()); String keyspace = context.getResourceKey(); if (columnFamilies == null) { columnFamilies = new String[] {}; } log.info("Executing repair on keyspace [" + keyspace + "]"); long start = System.currentTimeMillis(); keyspaceService.repair(keyspace, columnFamilies); long end = System.currentTimeMillis(); log.info("Finished repair on keyspace [" + keyspace + "] in " + (end - start) + " ms"); return new OperationResult(); } public OperationResult repairPrimaryRange() { KeyspaceService keyspaceService = new KeyspaceService(getEmsConnection()); String keyspace = context.getResourceKey(); log.info("Executing primary range repair on keyspace [" + keyspace + "]"); long start = System.currentTimeMillis(); keyspaceService.repairPrimaryRange(keyspace); long end = System.currentTimeMillis(); log.info("Finished primary range repair on keyspace [" + keyspace + " in (" + (end - start) + " ms"); return new OperationResult(); } public OperationResult cleanup() { KeyspaceService keyspaceService = new KeyspaceService(getEmsConnection()); String keyspace = context.getResourceKey(); log.info("Executing cleanup on keyspace [" + keyspace + "]"); long start = System.currentTimeMillis(); keyspaceService.cleanup(keyspace); long end = System.currentTimeMillis(); log.info("Finished cleanup on keyspace [" + keyspace + "] in " + (end - start) + " ms"); return new OperationResult(); } public OperationResult compactKeyspace(String... columnFamilies) { KeyspaceService keyspaceService = new KeyspaceService(getEmsConnection()); String keyspace = context.getResourceKey(); if (columnFamilies == null) { columnFamilies = new String[] {}; } log.info("Executing compaction on keyspace [" + keyspace + "]"); long start = System.currentTimeMillis(); keyspaceService.compact(keyspace, columnFamilies); long end = System.currentTimeMillis(); log.info("Finished compaction on keysapce [" + keyspace + "] in " + (end - start) + " ms"); return new OperationResult(); } public OperationResult takeSnapshot(Configuration parameters, String... columnFamilies) { String keyspace = context.getResourceKey(); String snapshotName = parameters.getSimpleValue("snapshotName"); if (snapshotName == null || snapshotName.trim().isEmpty()) { snapshotName = System.currentTimeMillis() + ""; } log.info("Taking snapshot of keyspace [" + keyspace + "]"); log.info("Snapshot name set to [" + snapshotName + "]"); long start = System.currentTimeMillis(); EmsBean emsBean = loadBean(KeyspaceService.STORAGE_SERVICE_BEAN); if (columnFamilies == null || columnFamilies.length == 0) { EmsOperation operation = emsBean.getOperation("takeSnapshot", String.class, String[].class); operation.invoke(snapshotName, new String[]{keyspace}); } else { EmsOperation operation = emsBean.getOperation("takeColumnFamilySnapshot", String.class, String.class, String.class); for (String columnFamily : columnFamilies) { if (log.isDebugEnabled()) { log.debug("Taking snapshot of column family [" + columnFamily + "]"); } operation.invoke(keyspace, columnFamily, snapshotName); } } long end = System.currentTimeMillis(); log.info("Finished taking snapshot of keyspace [" + keyspace + "] in " + (end - start) + " ms"); return new OperationResult(); } public PropertyList getKeySpaceDataFileLocations() { EmsBean emsBean = loadBean(KeyspaceService.STORAGE_SERVICE_BEAN); EmsAttribute attribute = emsBean.getAttribute("AllDataFileLocations"); PropertyList list = new PropertyList("keyspaceFileLocations"); String[] dirs = (String[]) attribute.getValue(); for (String dir : dirs) { if (!dir.endsWith("/")) { dir = dir + "/"; } list.add(new PropertySimple("directory", dir + context.getResourceKey())); } return list; } public PropertySimple getCommitLogProperty() { EmsBean emsBean = loadBean(KeyspaceService.STORAGE_SERVICE_BEAN); EmsAttribute attribute = emsBean.getAttribute("CommitLogLocation"); return new PropertySimple("CommitLogLocation", attribute.refresh()); } public boolean clearCommitLog() { PropertySimple commitLogProperty = this.getCommitLogProperty(); File commitLogFolder = new File(commitLogProperty.getStringValue()); File[] commitLogFiles = commitLogFolder.listFiles(); for (File file : commitLogFiles) { file.delete(); } return true; } public CassandraNodeComponent getCassandraNodeComponent() { return (CassandraNodeComponent) this.context.getParentResourceComponent(); } /** * Loads the bean with the given object name. * * Subclasses are free to override this method in order to load the bean. * * @param objectName the name of the bean to load * @return the bean that is loaded */ protected EmsBean loadBean(String objectName) { EmsConnection emsConnection = getEmsConnection(); if (emsConnection != null) { EmsBean bean = emsConnection.getBean(objectName); if (bean == null) { // In some cases, this resource component may have been discovered by some means other than querying its // parent's EMSConnection (e.g. ApplicationDiscoveryComponent uses a filesystem to discover EARs and // WARs that are not yet deployed). In such cases, getBean() will return null, since EMS won't have the // bean in its cache. To cover such cases, make an attempt to query the underlying MBeanServer for the // bean before giving up. emsConnection.queryBeans(objectName); bean = emsConnection.getBean(objectName); } return bean; } return null; } /** * @return keyspace name */ public String getKeyspaceName() { return this.context.getResourceKey(); } }