/*
*
* * 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 static org.rhq.core.domain.measurement.AvailabilityType.DOWN;
import static org.rhq.core.domain.measurement.AvailabilityType.UNKNOWN;
import static org.rhq.core.domain.measurement.AvailabilityType.UP;
import java.net.InetAddress;
import java.util.ArrayList;
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.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.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.ResourceContext;
import org.rhq.core.pluginapi.operation.OperationResult;
import org.rhq.core.system.FileSystemInfo;
/**
* @author John Sanda
*/
public class StorageServiceComponent extends ComplexConfigurationResourceComponent {
private static final String OWNERSHIP_METRIC_NAME = "Ownership";
private static final String DATA_DISK_USED_PERCENTAGE_METRIC_NAME = "Calculated.DataDiskUsedPercentage";
private static final String TOTAL_DISK_USED_PERCENTAGE_METRIC_NAME = "Calculated.TotalDiskUsedPercentage";
private static final String FREE_DISK_TO_DATA_SIZE_RATIO_METRIC_NAME = "Calculated.FreeDiskToDataSizeRatio";
private static final String DATA_FILE_LOCATIONS_NAME = "AllDataFileLocations";
private static final String LOAD_NAME = "Load";
private Log log = LogFactory.getLog(StorageServiceComponent.class);
@Override
public AvailabilityType getAvailability() {
ResourceContext<?> context = getResourceContext();
try {
EmsBean emsBean = loadBean();
if (emsBean == null) {
log.warn("Unable to establish JMX connection to " + context.getResourceKey());
return DOWN;
}
AvailabilityType availability = UP;
EmsAttribute nativeTransportEnabledAttr = emsBean.getAttribute("NativeTransportRunning");
Boolean nativeTransportEnabled = (Boolean) nativeTransportEnabledAttr.getValue();
if (!nativeTransportEnabled) {
if (log.isWarnEnabled()) {
log.warn("Native transport is disabled for " + context.getResourceKey());
}
availability = DOWN;
}
EmsAttribute initializedAttr = emsBean.getAttribute("Initialized");
Boolean initialized = (Boolean) initializedAttr.getValue();
if (!initialized) {
if (log.isWarnEnabled()) {
log.warn(context.getResourceKey() + " is not initialized");
}
availability = DOWN;
}
return availability;
} catch (Exception e) {
log.error("Unable to determine availability for " + context.getResourceKey(), e);
return UNKNOWN;
}
}
@Override
public OperationResult invokeOperation(String name, Configuration parameters) throws Exception {
if (name.equals("takeSnapshot")) {
return takeSnapshot(parameters);
} else if (name.equals("setLog4jLevel")) {
return setLog4jLevel(parameters);
} else if (name.equals("TokenToEndpointMap")) {
return invokeReadAttributeOperationComplexResult(name, "token", "endpoint");
}
return super.invokeOperation(name, parameters);
}
private OperationResult takeSnapshot(Configuration parameters) {
EmsBean emsBean = getEmsBean();
EmsOperation operation = emsBean.getOperation("takeSnapshot", String.class, String[].class);
String snapshotName = parameters.getSimpleValue("snapshotName");
if (snapshotName == null || snapshotName.trim().isEmpty()) {
snapshotName = System.currentTimeMillis() + "";
}
operation.invoke(snapshotName, new String[] {});
return new OperationResult();
}
private OperationResult setLog4jLevel(Configuration parameters) {
EmsBean emsBean = getEmsBean();
EmsOperation operation = emsBean.getOperation("setLog4jLevel", String.class, String.class);
String classQualifier = parameters.getSimpleValue("classQualifier");
String level = parameters.getSimpleValue("level");
operation.invoke(classQualifier, level);
return new OperationResult();
}
@Override
protected void getValues(MeasurementReport report, Set<MeasurementScheduleRequest> requests, EmsBean bean) {
super.getValues(report, requests, bean);
EmsAttribute loadAttribute = bean.getAttribute(LOAD_NAME);
Object loadValue = loadAttribute.refresh();
EmsAttribute dataFileLocationAttribute = bean.getAttribute(DATA_FILE_LOCATIONS_NAME);
Object dataFileLocationValue = dataFileLocationAttribute.refresh();
double load = 0;
if (loadValue != null && dataFileLocationValue != null && dataFileLocationValue instanceof String[]) {
//Please visit for details: https://issues.apache.org/jira/browse/CASSANDRA-2749
//The average usage of all partitions with the data will be reported.
//Cassandra selects the partition with most free space for SStable flush and compaction.
load = Double.parseDouble(loadValue.toString());
load = load / 1024d; //transform in MB
}
InetAddress host = getCassandraComponent().getHostAddress();
for (MeasurementScheduleRequest request : requests) {
if (OWNERSHIP_METRIC_NAME.equals(request.getName()) && host != null) {
// this code would not be necessary and we could use "host:" prefix
// but we keep it for compatibility reasons (metric name is not changed)
EmsAttribute attribute = bean.getAttribute(OWNERSHIP_METRIC_NAME);
Object valueObject = attribute.refresh();
if (valueObject instanceof Map<?, ?>) {
@SuppressWarnings("unchecked")
Map<InetAddress, Float> ownership = (Map<InetAddress, Float>) valueObject;
Float value = ownership.get(host);
if (value == null) {
// the inet address wasn't probably resolved, scan the map
for (Map.Entry<InetAddress, Float> entry : ownership.entrySet()) {
if (entry.getKey().getHostAddress().equals(host.getHostAddress())) {
value = entry.getValue();
break;
}
}
}
if (value > 1) {
value = 1f;
}
report.addData(new MeasurementDataNumeric(request, value.doubleValue()));
}
break;
} else if (DATA_DISK_USED_PERCENTAGE_METRIC_NAME.equals(request.getName())
|| TOTAL_DISK_USED_PERCENTAGE_METRIC_NAME.equals(request.getName())
|| FREE_DISK_TO_DATA_SIZE_RATIO_METRIC_NAME.equals(request.getName())) {
double metricValue = getDiskUsageMetric(request, load, (String[]) dataFileLocationValue);
report.addData(new MeasurementDataNumeric(request, metricValue));
}
}
}
private double getDiskUsageMetric(MeasurementScheduleRequest request, double dataSize, String[] paths) {
List<String> visitedMountPoints = new ArrayList<String>();
long totalDiskSpace = 0;
long totalFreeDiskSpace = 0;
long totalUsedDiskSpace = 0;
for (String path : paths) {
try {
FileSystemInfo fileSystemInfo = this.getResourceContext().getSystemInformation().getFileSystem(path);
if (!visitedMountPoints.contains(fileSystemInfo.getMountPoint())) {
visitedMountPoints.add(fileSystemInfo.getMountPoint());
//contrary to Sigar documentation this values are reported in MB and not bytes
totalDiskSpace += fileSystemInfo.getFileSystemUsage().getTotal();
totalFreeDiskSpace += fileSystemInfo.getFileSystemUsage().getFree();
totalUsedDiskSpace += fileSystemInfo.getFileSystemUsage().getUsed();
}
} catch (Exception e) {
log.error("Unable to determine file system usage information for data file location " + path, e);
}
}
double metricValue = 0;
if (totalDiskSpace != 0) {
double rawPercentage = 0;
if (DATA_DISK_USED_PERCENTAGE_METRIC_NAME.equals(request.getName())) {
rawPercentage = dataSize / ((double) totalDiskSpace);
} else if (TOTAL_DISK_USED_PERCENTAGE_METRIC_NAME.equals(request.getName())) {
rawPercentage = ((double) totalUsedDiskSpace) / ((double) totalDiskSpace);
} else if (FREE_DISK_TO_DATA_SIZE_RATIO_METRIC_NAME.equals(request.getName())) {
rawPercentage = ((double) totalFreeDiskSpace) / (double) dataSize;
}
metricValue = Math.round(rawPercentage * 100d) / 100d;
}
return metricValue;
}
}