package org.ovirt.engine.core.vdsbroker.gluster;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.common.businessentities.gluster.BrickDetails;
import org.ovirt.engine.core.common.businessentities.gluster.BrickProperties;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterClientInfo;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterServer;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterServerService;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterServiceStatus;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterStatus;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeAdvancedDetails;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity;
import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSizeInfo;
import org.ovirt.engine.core.common.businessentities.gluster.MallInfo;
import org.ovirt.engine.core.common.businessentities.gluster.MemoryStatus;
import org.ovirt.engine.core.common.businessentities.gluster.Mempool;
import org.ovirt.engine.core.common.businessentities.gluster.ServiceType;
import org.ovirt.engine.core.common.utils.gluster.GlusterCoreUtil;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dal.dbbroker.DbFacade;
import org.ovirt.engine.core.dao.gluster.GlusterDBUtils;
import org.ovirt.engine.core.dao.gluster.GlusterVolumeDao;
import org.ovirt.engine.core.di.Injector;
import org.ovirt.engine.core.vdsbroker.irsbroker.StatusReturn;
import org.ovirt.engine.core.vdsbroker.vdsbroker.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("unchecked")
public class GlusterVolumeStatusReturn extends StatusReturn {
private static final String STATUS = "status";
private static final String VOLUME_STATUS = "volumeStatus";
private static final String VOLUME_STATUS_INFO = "volumeStatsInfo";
private static final String VOLUME_NAME = "name";
private static final String PORT = "port";
private static final String RDMA_PORT = "rdma_port";
private static final String PID = "pid";
private static final String ONLINE = "ONLINE";
private static final String BRICKS = "bricks";
private static final String BRICK = "brick";
private static final String NFS_KEY = "nfs";
private static final String SHD_KEY = "shd";
private static final String HOSTNAME = "hostname";
private static final String HOST_UUID = "hostuuid";
private static final String DETAIL_SIZE_TOTAL = "sizeTotal";
private static final String DETAIL_SIZE_FREE = "sizeFree";
private static final String DETAIL_SIZE_USED = "sizeUsed";
private static final String DETAIL_DEVICE = "device";
private static final String DETAIL_BLOCK_SIZE = "blockSize";
private static final String DETAIL_MNT_OPTIONS = "mntOptions";
private static final String DETAIL_FS_NAME = "fsName";
private static final String CLIENTS_STATUS = "clientsStatus";
private static final String CLIENTS_HOST_NAME = "hostname";
private static final String CLIENTS_BYTES_READ = "bytesRead";
private static final String CLIENTS_BYTES_WRITE = "bytesWrite";
private static final String MEMORY_MALL_INFO = "mallinfo";
private static final String MEMORY_ARENA = "arena";
private static final String MEMORY_ORDBLKS = "ordblks";
private static final String MEMORY_SMBLKS = "smblks";
private static final String MEMORY_HBLKS = "hblks";
private static final String MEMORY_HBLKHD = "hblkhd";
private static final String MEMORY_USMBLKS = "usmblks";
private static final String MEMORY_FSMBLKS = "fsmblks";
private static final String MEMORY_UORDBLKS = "uordblks";
private static final String MEMORY_FORDBLKS = "fordblks";
private static final String MEMORY_KEEPCOST = "keepcost";
private static final String MEMORY_MEM_POOL = "mempool";
private static final String MEMORY_NAME = "name";
private static final String MEMORY_HOTCOUNT = "hotCount";
private static final String MEMORY_COLDCOUNT = "coldCount";
private static final String MEMORY_PADDDEDSIZEOF = "padddedSizeOf";
private static final String MEMORY_ALLOCCOUNT = "allocCount";
private static final String MEMORY_MAXALLOC = "maxAlloc";
private static final String MEMORY_POOLMISSES = "poolMisses";
private static final String MEMORY_MAXSTDALLOC = "maxStdAlloc";
private static final Logger log = LoggerFactory.getLogger(GlusterVolumeStatusReturn.class);
private Status status;
private final GlusterVolumeAdvancedDetails volumeAdvancedDetails = new GlusterVolumeAdvancedDetails();
public GlusterVolumeStatusReturn(Guid clusterId, Map<String, Object> innerMap) {
super(innerMap);
status = new Status((Map<String, Object>) innerMap.get(STATUS));
Map<String, Object> statusInfo = (Map<String, Object>) innerMap.get(VOLUME_STATUS);
if (statusInfo != null) {
String volumeName = (String) statusInfo.get(VOLUME_NAME);
GlusterVolumeEntity volume = getGlusterVolumeDao().getByName(clusterId, volumeName);
volumeAdvancedDetails.setVolumeId(volume.getId());
List<BrickDetails> brickDetails = prepareBrickDetails(volume, (Object[]) statusInfo.get(BRICKS));
volumeAdvancedDetails.setBrickDetails(brickDetails);
volumeAdvancedDetails.setServiceInfo(prepareServiceInfo(statusInfo));
GlusterVolumeSizeInfo capacityInfo = null;
// Fetch the volume capacity detail
if (statusInfo.containsKey(VOLUME_STATUS_INFO)) {
Map<String, Object> volumeStatusInfo = (Map<String, Object>) statusInfo.get("volumeStatsInfo");
capacityInfo = new GlusterVolumeSizeInfo();
capacityInfo.setVolumeId(volume.getId());
capacityInfo.setTotalSize(Long.parseLong((String) volumeStatusInfo.get(DETAIL_SIZE_TOTAL)));
capacityInfo.setUsedSize(Long.parseLong((String) volumeStatusInfo.get(DETAIL_SIZE_USED)));
capacityInfo.setFreeSize(Long.parseLong((String) volumeStatusInfo.get(DETAIL_SIZE_FREE)));
volumeAdvancedDetails.setCapacityInfo(capacityInfo);
}
}
}
private List<GlusterServerService> prepareServiceInfo(Map<String, Object> statusInfo) {
List<GlusterServerService> serviceInfoList = new ArrayList<>();
prepareServiceInfo(statusInfo, serviceInfoList, NFS_KEY);
prepareServiceInfo(statusInfo, serviceInfoList, SHD_KEY);
return serviceInfoList;
}
private void prepareServiceInfo(Map<String, Object> statusInfo, List<GlusterServerService> serviceInfoList, String service) {
if (statusInfo.containsKey(service)) {
Object[] serviceInfo = (Object[]) statusInfo.get(service);
for (Object serviceObj : serviceInfo) {
Map<String, Object> serviceMap = (Map<String, Object>) serviceObj;
GlusterServerService parsedServiceInfo = parseServiceInfo(serviceMap);
parsedServiceInfo.setServiceType(service.equals(NFS_KEY) ? ServiceType.NFS : ServiceType.SHD);
serviceInfoList.add(parsedServiceInfo);
}
}
}
private GlusterServerService parseServiceInfo(Map<String, Object> volumeServiceInfo) {
GlusterServerService serviceInfo = new GlusterServerService();
if (volumeServiceInfo.containsKey(HOSTNAME)) {
serviceInfo.setHostName((String) volumeServiceInfo.get(HOSTNAME));
}
if (volumeServiceInfo.containsKey(HOST_UUID)) {
serviceInfo.setGlusterHostUuid(Guid.createGuidFromString((String) volumeServiceInfo.get(HOST_UUID)));
}
if (volumeServiceInfo.containsKey(STATUS)) {
String brickStatus = (String) volumeServiceInfo.get(STATUS);
if (brickStatus.toUpperCase().equals(ONLINE)) {
serviceInfo.setStatus(GlusterServiceStatus.RUNNING);
// parse the port and pid only if the service is running.
if (volumeServiceInfo.containsKey(PORT) && StringUtils.isNumeric((String)volumeServiceInfo.get(PORT))) {
serviceInfo.setPort(Integer.parseInt((String) volumeServiceInfo.get(PORT)));
}
if (volumeServiceInfo.containsKey(RDMA_PORT) && StringUtils.isNumeric((String)volumeServiceInfo.get(RDMA_PORT))) {
serviceInfo.setRdmaPort(Integer.parseInt((String) volumeServiceInfo.get(RDMA_PORT)));
}
if (volumeServiceInfo.containsKey(PID) && StringUtils.isNumeric((String)volumeServiceInfo.get(PID))) {
serviceInfo.setPid(Integer.parseInt((String) volumeServiceInfo.get(PID)));
}
} else {
serviceInfo.setStatus(GlusterServiceStatus.STOPPED);
}
}
return serviceInfo;
}
private List<BrickDetails> prepareBrickDetails(GlusterVolumeEntity volume, Object[] bricksList) {
List<BrickDetails> brickDetailsList = new ArrayList<>();
for (Object brickObj : bricksList) {
BrickDetails brickDetails = new BrickDetails();
Map<String, Object> brick = (Map<String, Object>) brickObj;
brickDetails.setBrickProperties(getBrickProperties(volume, brick));
// Fetch Clients Details
if (brick.containsKey(CLIENTS_STATUS)) {
brickDetails.setClients(prepareClientInfo((Object[]) brick.get(CLIENTS_STATUS)));
}
// Fetch Memory Details
if (brick.containsKey(MEMORY_MALL_INFO) || brick.containsKey(MEMORY_MEM_POOL)) {
MemoryStatus memoryStatus = new MemoryStatus();
memoryStatus.setMallInfo(prepareMallInfo((Map<String, Object>) brick.get(MEMORY_MALL_INFO)));
memoryStatus.setMemPools(prepareMemPool((Object[]) brick.get(MEMORY_MEM_POOL)));
brickDetails.setMemoryStatus(memoryStatus);
}
brickDetailsList.add(brickDetails);
}
return brickDetailsList;
}
private BrickProperties getBrickProperties(GlusterVolumeEntity volume, Map<String, Object> brick) {
BrickProperties brickProperties = new BrickProperties();
GlusterBrickEntity brickEntity = getBrickEntity(volume, brick);
if (brickEntity != null) {
brickProperties.setBrickId(brickEntity.getId());
} else {
log.warn("Could not update brick '{}' as not found in db", brick.get(BRICK));
}
if (brick.containsKey(STATUS)) {
String brickStatus = (String) brick.get(STATUS);
if (brickStatus.toUpperCase().equals(ONLINE)) {
brickProperties.setStatus(GlusterStatus.UP);
boolean portPresent = false;
if (brick.containsKey(PORT) && StringUtils.isNumeric((String)brick.get(PORT))) {
brickProperties.setPort(Integer.parseInt((String) brick.get(PORT)));
portPresent = true;
}
if (brick.containsKey(RDMA_PORT) && StringUtils.isNumeric((String)brick.get(RDMA_PORT))) {
brickProperties.setRdmaPort(Integer.parseInt((String) brick.get(RDMA_PORT)));
portPresent = true;
}
if (!portPresent) {
//if there's no port registered, then the brick status is down.
brickProperties.setStatus(GlusterStatus.DOWN);
}
if (brick.containsKey(PID) && StringUtils.isNumeric((String)brick.get(PID))) {
brickProperties.setPid(Integer.parseInt((String) brick.get(PID)));
}
} else {
brickProperties.setStatus(GlusterStatus.DOWN);
}
}
// Fetch the volume status detail
if (brick.containsKey(DETAIL_SIZE_TOTAL)) {
brickProperties.setTotalSize(Double.parseDouble((String) brick.get(DETAIL_SIZE_TOTAL)));
}
if (brick.containsKey(DETAIL_SIZE_FREE)) {
brickProperties.setFreeSize(Double.parseDouble((String) brick.get(DETAIL_SIZE_FREE)));
}
if (brick.containsKey(DETAIL_DEVICE)) {
brickProperties.setDevice((String) brick.get(DETAIL_DEVICE));
}
if (brick.containsKey(DETAIL_BLOCK_SIZE)) {
brickProperties.setBlockSize(Integer.parseInt((String) brick.get(DETAIL_BLOCK_SIZE)));
}
if (brick.containsKey(DETAIL_MNT_OPTIONS)) {
brickProperties.setMntOptions((String) brick.get(DETAIL_MNT_OPTIONS));
}
if (brick.containsKey(DETAIL_FS_NAME)) {
brickProperties.setFsName((String) brick.get(DETAIL_FS_NAME));
}
return brickProperties;
}
private GlusterBrickEntity getBrickEntity(GlusterVolumeEntity volume, Map<String, Object> brick) {
String brickName = (String) brick.get(BRICK);
String glusterHostUuid = (String) brick.get(HOST_UUID);
if (!StringUtils.isEmpty(glusterHostUuid)) {
GlusterServer glusterServer =
Injector.get(GlusterDBUtils.class).getServerByUuid(Guid.createGuidFromString(glusterHostUuid));
if (glusterServer == null) {
log.warn("Could not update brick '{}' to volume '{}' - server uuid '{}' not found",
brickName, volume.getName(), glusterHostUuid);
return null;
}
String[] brickParts = brickName.split(":", -1);
if (brickParts.length != 2) {
log.warn("Invalid brick representation '{}'", brickName);
return null;
}
String brickDir = brickParts[1];
return DbFacade.getInstance().getGlusterBrickDao().getBrickByServerIdAndDirectory(glusterServer.getId(), brickDir);
}
return GlusterCoreUtil.getBrickByQualifiedName(volume.getBricks(), brickName);
}
private List<Mempool> prepareMemPool(Object[] memoryPool) {
List<Mempool> memPoolList = new ArrayList<>();
for (Object memPoolObj : memoryPool) {
Mempool glusterMemoryPool = new Mempool();
Map<String, Object> memPool = (Map<String, Object>) memPoolObj;
glusterMemoryPool.setName((String) memPool.get(MEMORY_NAME));
glusterMemoryPool.setHotCount(Integer.parseInt((String) memPool.get(MEMORY_HOTCOUNT)));
glusterMemoryPool.setColdCount(Integer.parseInt((String) memPool.get(MEMORY_COLDCOUNT)));
glusterMemoryPool.setPadddedSize(Integer.parseInt((String) memPool.get(MEMORY_PADDDEDSIZEOF)));
glusterMemoryPool.setAllocCount(Integer.parseInt((String) memPool.get(MEMORY_ALLOCCOUNT)));
glusterMemoryPool.setMaxAlloc(Integer.parseInt((String) memPool.get(MEMORY_MAXALLOC)));
glusterMemoryPool.setPoolMisses(Integer.parseInt((String) memPool.get(MEMORY_POOLMISSES)));
glusterMemoryPool.setMaxStdAlloc(Integer.parseInt((String) memPool.get(MEMORY_MAXSTDALLOC)));
memPoolList.add(glusterMemoryPool);
}
return memPoolList;
}
private MallInfo prepareMallInfo(Map<String, Object> mallInfo) {
MallInfo glusterMallInfo = new MallInfo();
glusterMallInfo.setArena(Integer.parseInt((String) mallInfo.get(MEMORY_ARENA)));
glusterMallInfo.setOrdblks(Integer.parseInt((String) mallInfo.get(MEMORY_ORDBLKS)));
glusterMallInfo.setSmblks(Integer.parseInt((String) mallInfo.get(MEMORY_SMBLKS)));
glusterMallInfo.setHblks(Integer.parseInt((String) mallInfo.get(MEMORY_HBLKS)));
glusterMallInfo.setHblkhd(Integer.parseInt((String) mallInfo.get(MEMORY_HBLKHD)));
glusterMallInfo.setUsmblks(Integer.parseInt((String) mallInfo.get(MEMORY_USMBLKS)));
glusterMallInfo.setFsmblks(Integer.parseInt((String) mallInfo.get(MEMORY_FSMBLKS)));
glusterMallInfo.setUordblks(Integer.parseInt((String) mallInfo.get(MEMORY_UORDBLKS)));
glusterMallInfo.setFordblks(Integer.parseInt((String) mallInfo.get(MEMORY_FORDBLKS)));
glusterMallInfo.setKeepcost(Integer.parseInt((String) mallInfo.get(MEMORY_KEEPCOST)));
return glusterMallInfo;
}
private List<GlusterClientInfo> prepareClientInfo(Object[] clientsStatus) {
List<GlusterClientInfo> clientInfoList = new ArrayList<>();
for (Object clientStatusObj : clientsStatus) {
GlusterClientInfo clientInfo = new GlusterClientInfo();
Map<String, Object> client = (Map<String, Object>) clientStatusObj;
String hostName = (String) client.get(CLIENTS_HOST_NAME);
String[] hostNameArr = hostName.split(":", -1);
clientInfo.setHostname(hostNameArr[0]);
clientInfo.setClientPort(Integer.parseInt(hostNameArr[1]));
clientInfo.setBytesRead(Long.parseLong((String) client.get(CLIENTS_BYTES_READ)));
clientInfo.setBytesWritten(Long.parseLong((String) client.get(CLIENTS_BYTES_WRITE)));
clientInfoList.add(clientInfo);
}
return clientInfoList;
}
protected GlusterVolumeDao getGlusterVolumeDao() {
return DbFacade.getInstance().getGlusterVolumeDao();
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public GlusterVolumeAdvancedDetails getVolumeAdvancedDetails() {
return volumeAdvancedDetails;
}
}