/*************************************************************************
* Copyright 2009-2015 Eucalyptus Systems, Inc.
*
* 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 3 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, see http://www.gnu.org/licenses/.
*
* Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
* CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
* additional information or have any questions.
************************************************************************/
package com.eucalyptus.cluster.callback;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import com.eucalyptus.cluster.callback.reporting.AbsoluteMetricQueue;
import com.eucalyptus.cluster.callback.reporting.AbsoluteMetricQueueItem;
import com.eucalyptus.cluster.callback.reporting.CloudWatchHelper;
import com.eucalyptus.cluster.common.msgs.DescribeSensorsResponseType;
import com.eucalyptus.cluster.common.msgs.DescribeSensorsType;
import com.eucalyptus.cluster.common.msgs.MetricCounterType;
import com.eucalyptus.cluster.common.msgs.MetricDimensionsType;
import com.eucalyptus.cluster.common.msgs.MetricsResourceType;
import com.eucalyptus.cluster.common.msgs.SensorsResourceType;
import com.eucalyptus.cluster.common.msgs.MetricDimensionsValuesType;
import org.apache.log4j.Logger;
import com.eucalyptus.event.EventFailedException;
import com.eucalyptus.event.ListenerRegistry;
import com.eucalyptus.records.Logs;
import com.eucalyptus.reporting.event.InstanceUsageEvent;
import com.eucalyptus.util.LogUtil;
import com.eucalyptus.util.async.MessageCallback;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
public class DescribeSensorCallback extends
MessageCallback<DescribeSensorsType, DescribeSensorsResponseType> {
private static final Logger LOG = Logger.getLogger(DescribeSensorCallback.class);
private static final String RESOURCE_TYPE_INSTANCE = "instance";
private final ArrayList<String> instanceIds;
private final ListenerRegistry listener = ListenerRegistry.getInstance();
public DescribeSensorCallback(
final int historySize,
final int collectionIntervalTimeMS,
final ArrayList<String> instanceIds
) {
this.instanceIds = instanceIds;
final DescribeSensorsType msg =
new DescribeSensorsType( historySize, collectionIntervalTimeMS, this.instanceIds );
this.setRequest(msg);
}
@Override
public void initialize(final DescribeSensorsType msg) {
}
@Override
public void fireException(Throwable e) {
LOG.debug("Request failed: "
+ LogUtil.subheader(this.getRequest().toString(
"eucalyptus_ucsb_edu")));
Logs.extreme().error(e, e);
}
@Override
public void fire(final DescribeSensorsResponseType msg) {
LOG.trace("DescribeSensorCallback (fire) called at " + new Date());
try {
processCloudWatchStats(msg);
} catch (Exception ex) {
LOG.debug("Unable to fire describe sensors call back (cloudwatch)", ex);
}
try {
processReportingStats(msg);
} catch (Exception ex) {
LOG.debug("Unable to fire describe sensors call back (reporting)", ex);
}
}
private void processCloudWatchStats(final DescribeSensorsResponseType msg) throws Exception {
CloudWatchHelper cloudWatchHelper = new CloudWatchHelper(new CloudWatchHelper.DefaultInstanceInfoProvider());
List<AbsoluteMetricQueueItem> queueItems = cloudWatchHelper.collectMetricData(instanceIds, msg);
AbsoluteMetricQueue.getInstance().addQueueItems(queueItems);
}
private void processReportingStats(final DescribeSensorsResponseType msg) throws Exception {
for (final SensorsResourceType sensorData : msg.getSensorsResources()) {
if (!RESOURCE_TYPE_INSTANCE.equals(sensorData.getResourceType()) ||
!instanceIds.contains( sensorData.getResourceName( )) ||
sensorData.getResourceUuid( ) == null ||
sensorData.getResourceUuid( ).isEmpty() )
continue;
for (final MetricsResourceType metricType : sensorData.getMetrics()) {
for (final MetricCounterType counterType : metricType.getCounters()) {
for (final MetricDimensionsType dimensionType : counterType.getDimensions()) {
// find and fire most recent value for metric/dimension
final List<MetricDimensionsValuesType> values =
Lists.newArrayList(dimensionType.getValues());
//Reporting use case of metric data from the cc
Collections.sort(values, Ordering.natural().onResultOf(GetTimestamp.INSTANCE));
if (!values.isEmpty()) {
final MetricDimensionsValuesType latestValue = Iterables.getLast(values);
final Double usageValue = latestValue.getValue();
if (usageValue == null) {
LOG.debug("Event received with null 'value', skipping for reporting");
continue;
}
final Long usageTimestamp = latestValue.getTimestamp().getTime();
final long sequenceNumber = dimensionType.getSequenceNum() + (values.size() - 1);
fireUsageEvent( new Supplier<InstanceUsageEvent>(){
@Override
public InstanceUsageEvent get() {
return new InstanceUsageEvent(
sensorData.getResourceUuid(),
sensorData.getResourceName(),
metricType.getMetricName(),
sequenceNumber,
dimensionType.getDimensionName(),
usageValue,
usageTimestamp);
}
});
}
}
}
}
}
}
private void fireUsageEvent(Supplier<InstanceUsageEvent> instanceUsageEventSupplier) {
InstanceUsageEvent event = instanceUsageEventSupplier.get();
try {
listener.fireEvent(event);
} catch (EventFailedException e) {
LOG.debug("Failed to fire instance usage event"
+ (event != null ? event : ""), e);
}
}
public enum GetTimestamp implements Function<MetricDimensionsValuesType, Date> {
INSTANCE;
@Override
public Date apply(final MetricDimensionsValuesType metricDimensionsValuesType) {
return metricDimensionsValuesType.getTimestamp();
}
}
}