package org.zstack.storage.primary; import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.zstack.core.db.DatabaseFacade; import org.zstack.core.db.EntityEvent; import org.zstack.core.db.EntityLifeCycleCallback; import org.zstack.header.Component; import org.zstack.header.core.workflow.*; import org.zstack.header.storage.primary.ImageCacheVO; import org.zstack.header.storage.primary.PrimaryStorageAllocationSpec; import org.zstack.header.storage.primary.PrimaryStorageCapacityVO; import org.zstack.header.storage.primary.PrimaryStorageConstant.AllocatorParams; import org.zstack.header.storage.primary.PrimaryStorageVO; import org.zstack.header.storage.snapshot.VolumeSnapshotEO; import org.zstack.header.storage.snapshot.VolumeSnapshotVO; import org.zstack.header.volume.VolumeAO; import org.zstack.header.volume.VolumeEO; import org.zstack.header.volume.VolumeVO; import org.zstack.utils.CollectionDSL; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Created by xing5 on 2016/5/10. */ public class DiskCapacityTracer implements Component { private static Logger logger = LogManager.getLogger("org.zstack.storage.primary.DiskCapacityTracer"); private static Logger loggerd = LogManager.getLogger("org.zstack.storage.primary.DiskCapacityTracerDetails"); private static CLogger clogger = Utils.getLogger(DiskCapacityTracer.class); @Autowired private DatabaseFacade dbf; public void trackAllocatorChain(FlowChain chain) { if (!PrimaryStorageGlobalProperty.CAPACITY_TRACKER_ON) { return; } chain.setProcessors(CollectionDSL.<FlowChainProcessor>list(new FlowChainProcessor() { @Override public void processFlowChain(FlowChainMutable chain) { List<Flow> flows = new ArrayList<Flow>(); for (Flow f : chain.getFlows()) { flows.add(f); flows.add(new NoRollbackFlow() { String __name__ = "disk-capacity-tracker"; @Override public void run(FlowTrigger trigger, Map data) { PrimaryStorageAllocationSpec spec = (PrimaryStorageAllocationSpec) data.get(AllocatorParams.SPEC); List<PrimaryStorageVO> candidates = (List<PrimaryStorageVO>) data.get(AllocatorParams.CANDIDATES); List<PrimaryStorageVO> all = dbf.listAll(PrimaryStorageVO.class); StringBuilder sb = new StringBuilder("\n=== Primary Storage Allocation Tracker ====\n"); sb.append(String.format("REQUIRED SIZE: %s\n", spec.getSize())); sb.append("CANDIDATES:\n"); for (PrimaryStorageVO p : candidates) { sb.append(String.format("[name]:%s [uuid]:%s [status]:%s [state]:%s [available]:%s [total]:%s", p.getName(), p.getUuid(), p.getStatus(), p.getState(), p.getCapacity().getAvailableCapacity(), p.getCapacity().getTotalCapacity())); } sb.append("\n\n"); sb.append("ALL:\n"); for (PrimaryStorageVO p : all) { sb.append(String.format("[name]:%s [uuid]:%s [status]:%s [state]:%s [available]:%s [total]:%s", p.getName(), p.getUuid(), p.getStatus(), p.getState(), p.getCapacity().getAvailableCapacity(), p.getCapacity().getTotalCapacity())); } sb.append("\n===========================================\n"); clogger.debug(sb.toString()); trigger.next(); } }); } chain.setFlows(flows); } })); } private void printCallTrace() { StackTraceElement[] elements = Thread.currentThread().getStackTrace(); List<String> lst = new ArrayList<String>(); for (StackTraceElement el : elements) { if (el.getClassName().contains("org.zstack")) { lst.add(el.toString()); } } loggerd.debug(StringUtils.join(lst, "\n")); } @Override public boolean start() { if (!PrimaryStorageGlobalProperty.CAPACITY_TRACKER_ON) { return true; } dbf.installEntityLifeCycleCallback(VolumeVO.class, EntityEvent.POST_PERSIST, new EntityLifeCycleCallback() { @Override public void entityLifeCycleEvent(EntityEvent evt, Object o) { VolumeVO vol = (VolumeVO) o; if (vol.getSize() != 0) { String info = String.format("[Volume:Create][name=%s, uuid=%s, type=%s]: %s", vol.getName(), vol.getUuid(), vol.getType(), vol.getSize()); logger.debug(info); loggerd.debug(info); printCallTrace(); } } }); dbf.installEntityLifeCycleCallback(VolumeVO.class, EntityEvent.POST_UPDATE, new EntityLifeCycleCallback() { @Override public void entityLifeCycleEvent(EntityEvent evt, Object o) { VolumeVO vol = (VolumeVO) o; VolumeAO pre = vol.getShadow(); if (pre.getSize() != vol.getSize()) { String info = String.format("[Volume:Update][name=%s, uuid=%s, type=%s]: %s --> %s", vol.getName(), vol.getUuid(), vol.getType(), pre.getSize(), vol.getSize()); logger.debug(info); loggerd.debug(info); printCallTrace(); } } }); dbf.installEntityLifeCycleCallback(VolumeEO.class, EntityEvent.POST_UPDATE, new EntityLifeCycleCallback() { @Override public void entityLifeCycleEvent(EntityEvent evt, Object o) { VolumeEO vol = (VolumeEO) o; VolumeEO pre = (VolumeEO) vol.getShadow(); if (pre.getDeleted() == null && vol.getDeleted() != null && vol.getSize() != 0) { String info = String.format("[Volume:Delete][name=%s, uuid=%s, type=%s]: -%s", vol.getName(), vol.getUuid(), vol.getType(), vol.getSize()); logger.debug(info); loggerd.debug(info); printCallTrace(); } } }); dbf.installEntityLifeCycleCallback(ImageCacheVO.class, EntityEvent.POST_PERSIST, new EntityLifeCycleCallback() { @Override public void entityLifeCycleEvent(EntityEvent evt, Object o) { ImageCacheVO img = (ImageCacheVO) o; String info = String.format("[ImageCache:Create][uuid=%s]: %s", img.getImageUuid(), img.getSize()); logger.debug(info); loggerd.debug(info); printCallTrace(); } }); dbf.installEntityLifeCycleCallback(ImageCacheVO.class, EntityEvent.POST_REMOVE, new EntityLifeCycleCallback() { @Override public void entityLifeCycleEvent(EntityEvent evt, Object o) { ImageCacheVO img = (ImageCacheVO) o; String info = String.format("[ImageCache:Delete][uuid=%s]: -%s", img.getImageUuid(), img.getSize()); logger.debug(info); loggerd.debug(info); printCallTrace(); } }); dbf.installEntityLifeCycleCallback(VolumeSnapshotVO.class, EntityEvent.POST_PERSIST, new EntityLifeCycleCallback() { @Override public void entityLifeCycleEvent(EntityEvent evt, Object o) { VolumeSnapshotVO s = (VolumeSnapshotVO) o; String info = String.format("[VolumeSnapshot:Create][name=%s, uuid=%s]: %s", s.getName(), s.getUuid(), s.getSize()); logger.debug(info); loggerd.debug(info); printCallTrace(); } }); dbf.installEntityLifeCycleCallback(VolumeSnapshotEO.class, EntityEvent.POST_UPDATE, new EntityLifeCycleCallback() { @Override public void entityLifeCycleEvent(EntityEvent evt, Object o) { VolumeSnapshotEO s = (VolumeSnapshotEO) o; VolumeSnapshotEO pre = (VolumeSnapshotEO) s.getShadow(); if (pre.getDeleted() == null && s.getDeleted() != null) { String info = String.format("[VolumeSnapshot:Delete][name=%s, uuid=%s]: -%s", s.getName(), s.getUuid(), s.getSize()); logger.debug(info); loggerd.debug(info); printCallTrace(); } } }); dbf.installEntityLifeCycleCallback(PrimaryStorageCapacityVO.class, EntityEvent.POST_UPDATE, new EntityLifeCycleCallback() { @Override public void entityLifeCycleEvent(EntityEvent evt, Object o) { PrimaryStorageCapacityVO c = (PrimaryStorageCapacityVO) o; PrimaryStorageCapacityVO pre = c.getShadow(); if (c.getAvailableCapacity() != pre.getAvailableCapacity()) { String info = String.format( "[PrimaryStorageCapacity:Change][uuid=%s]: %s --> %s (%s)", pre.getUuid(), pre.getAvailableCapacity(), c.getAvailableCapacity(), c.getAvailableCapacity() - pre.getAvailableCapacity()); logger.debug(info); loggerd.debug(info); printCallTrace(); } } }); return true; } @Override public boolean stop() { return true; } }