package com.sequenceiq.periscope.monitor.handler;
import static java.lang.Math.ceil;
import java.util.concurrent.ExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import com.sequenceiq.periscope.domain.BaseAlert;
import com.sequenceiq.periscope.domain.Cluster;
import com.sequenceiq.periscope.domain.ScalingPolicy;
import com.sequenceiq.periscope.log.MDCBuilder;
import com.sequenceiq.periscope.monitor.event.ScalingEvent;
import com.sequenceiq.periscope.service.ClusterService;
import com.sequenceiq.periscope.utils.AmbariClientProvider;
import com.sequenceiq.periscope.utils.ClusterUtils;
@Component
public class ScalingHandler implements ApplicationListener<ScalingEvent> {
private static final Logger LOGGER = LoggerFactory.getLogger(ScalingHandler.class);
@Autowired
private ExecutorService executorService;
@Autowired
private ClusterService clusterService;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private AmbariClientProvider ambariClientProvider;
@Override
public void onApplicationEvent(ScalingEvent event) {
BaseAlert alert = event.getAlert();
Cluster cluster = clusterService.find(alert.getCluster().getId());
MDCBuilder.buildMdcContext(cluster);
scale(cluster, alert.getScalingPolicy());
}
private void scale(Cluster cluster, ScalingPolicy policy) {
long remainingTime = getRemainingCooldownTime(cluster);
if (remainingTime <= 0) {
int totalNodes = ClusterUtils.getTotalNodes(ambariClientProvider.createAmbariClient(cluster));
int desiredNodeCount = getDesiredNodeCount(cluster, policy, totalNodes);
if (totalNodes != desiredNodeCount) {
ScalingRequest scalingRequest = (ScalingRequest)
applicationContext.getBean("ScalingRequest", cluster, policy, totalNodes, desiredNodeCount);
executorService.execute(scalingRequest);
cluster.setLastScalingActivityCurrent();
clusterService.save(cluster);
} else {
LOGGER.info("No scaling activity required");
}
} else {
LOGGER.info("Cluster cannot be scaled for {} min(s)",
ClusterUtils.TIME_FORMAT.format((double) remainingTime / ClusterUtils.MIN_IN_MS));
}
}
private long getRemainingCooldownTime(Cluster cluster) {
int coolDown = cluster.getCoolDown();
long lastScalingActivity = cluster.getLastScalingActivity();
return lastScalingActivity == 0 ? 0 : (coolDown * ClusterUtils.MIN_IN_MS) - (System.currentTimeMillis() - lastScalingActivity);
}
private int getDesiredNodeCount(Cluster cluster, ScalingPolicy policy, int totalNodes) {
int scalingAdjustment = policy.getScalingAdjustment();
int desiredNodeCount;
switch (policy.getAdjustmentType()) {
case NODE_COUNT:
desiredNodeCount = totalNodes + scalingAdjustment;
break;
case PERCENTAGE:
desiredNodeCount = totalNodes
+ (int) (ceil(totalNodes * ((double) scalingAdjustment / ClusterUtils.MAX_CAPACITY)));
break;
case EXACT:
desiredNodeCount = policy.getScalingAdjustment();
break;
default:
desiredNodeCount = totalNodes;
}
int minSize = cluster.getMinSize();
int maxSize = cluster.getMaxSize();
return desiredNodeCount < minSize ? minSize : desiredNodeCount > maxSize ? maxSize : desiredNodeCount;
}
}