/*
* Copyright (c) 2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.systemservices.impl.healthmonitor;
import com.emc.storageos.coordinator.client.model.Constants;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.coordinator.client.service.DrUtil;
import com.emc.storageos.coordinator.common.Service;
import com.emc.storageos.coordinator.exceptions.RetryableCoordinatorException;
import com.emc.storageos.systemservices.impl.healthmonitor.models.Status;
import com.emc.vipr.model.sys.healthmonitor.ServiceHealth;
import com.emc.vipr.model.sys.healthmonitor.ServiceStats;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* Class that calculates node and its services health. Node health status: GOOD
* - when node is reachable and all its services are GOOD UNAVAILABLE - when
* node is not reachable DEGRADED - when node is reachable and any of its
* service is UNAVAILABLE/DEGRADED
* <p/>
* Service health status: GOOD - when a service is up and running UNAVAILABLE -
* when a service is not running but is registered in coordinator RESTARTED -
* when service is restarting
*/
public class NodeHealthExtractor implements StatConstants {
private static final Logger _log = LoggerFactory.getLogger(NodeHealthExtractor.class);
private static final String SA_SVC = "sasvc";
private static final String VASA_SVC = "vasasvc";
private static final String CTRL_SVC = "controllersvc";
/**
* Method that populates list of services with its health. List of available
* services are retrieved from coordinator while list of active services are
* taken from service statistics.
*
* @return Overall service status. This is used to calculate node status.
* GOOD if all services are GOOD. DEGRADED if any of the service is
* UNAVAILABLE.
* @throws Exception
*/
public static List<ServiceHealth> getServiceHealth(List<ServiceStats> serviceStatsList,
CoordinatorClient coordinator, String nodeId) {
// Get running services from stats service
if (serviceStatsList != null) {
List<ServiceHealth> serviceHealthList = new ArrayList<ServiceHealth>();
for (ServiceStats serviceStats : serviceStatsList) {
String sName = serviceStats.getServiceName();
if (sName == null || sName.isEmpty() || MONITOR_SVCNAME.equals(sName)) {
continue;
}
if (sName.equals(CTRL_SVC) || sName.equals(SA_SVC) || sName.equals(VASA_SVC)) {
DrUtil drUtil = new DrUtil(coordinator);
if (drUtil.isActiveSite()) {
serviceHealthList.add(new ServiceHealth(sName,
getServiceStatusFromStats(serviceStats, coordinator, nodeId).toString()));
}
} else {
serviceHealthList.add(new ServiceHealth(sName,
getServiceStatusFromStats(serviceStats, coordinator, nodeId).toString()));
}
}
return serviceHealthList;
} else {
return null;
}
}
/**
* Calculates service status from the service statistics. UNAVAILABLE if the
* service process cannot be found. RESTARTED if service uptime is less than
* or equal to 0. DEGRADED if the service process is fine by corresponding
* service beacon is not found in ZK. GOOD otherwise
*
* @param serviceStats
* service statistics
* @return service status
*/
private static Status getServiceStatusFromStats(ServiceStats serviceStats, CoordinatorClient coordinator,
String nodeId) {
String svcName = serviceStats.getServiceName();
// If service status is not available..
if (serviceStats.getProcessStatus() == null || serviceStats.getProcessStatus().getStartTime() == 0
|| serviceStats.getProcessStatus().getUpTime() == 0) {
return Status.UNAVAILABLE;
} else if (Constants.DBSVC_NAME.equals(svcName) || Constants.GEODBSVC_NAME.equals(svcName)) {
// Check service beacon to know service status. make it work for
// dbsvc/geodbsvc first, then rest of other
// after we unified beacon format
String svcVersion = coordinator.getTargetDbSchemaVersion();
List<Service> svcs;
try {
svcs = coordinator.locateAllServices(svcName, svcVersion, null, null);
} catch (RetryableCoordinatorException ex) {
_log.warn("Failed to look for Beacon for service {}, treat as status DEGRADED", svcName, ex);
return Status.DEGRADED;
}
// In case we cannot find the service in ZK, the service is
// DEGRADED. It's not UNAVAILABLE
// because we still see its process as GOOD
Status status = Status.DEGRADED;
if (nodeId != null) {
for (Service svc : svcs) {
if (nodeId.equals(svc.getNodeId())) {
status = Status.GOOD;
}
}
}
return status;
} else {
// Check service status based on process id
return serviceStats.getProcessStatus().getUpTime() <= 0 ? Status.RESTARTED : Status.GOOD;
}
}
}