package org.zstack.storage.volume;
import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.cloudbus.EventCallback;
import org.zstack.core.cloudbus.EventFacade;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.SimpleQuery;
import org.zstack.core.db.SimpleQuery.Op;
import org.zstack.header.Component;
import org.zstack.header.message.MessageReply;
import org.zstack.header.storage.primary.*;
import org.zstack.header.storage.primary.PrimaryStorageCanonicalEvent.PrimaryStorageStatusChangedData;
import org.zstack.header.volume.*;
import org.zstack.utils.CollectionUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.function.Function;
import org.zstack.utils.logging.CLogger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.Arrays.asList;
/**
* Created by xing5 on 2016/5/25.
*/
public class VolumeUpgradeExtension implements Component {
private static final CLogger logger = Utils.getLogger(VolumeUpgradeExtension.class);
@Autowired
private DatabaseFacade dbf;
@Autowired
private EventFacade evtf;
@Autowired
private CloudBus bus;
@Override
public boolean start() {
if (VolumeGlobalProperty.SYNC_VOLUME_SIZE) {
syncVolumeSize();
}
if (VolumeGlobalProperty.ROOT_VOLUME_FIND_MISSING_IMAGE_UUID) {
rootVolumeFindMissingUuid();
}
return true;
}
private void rootVolumeFindMissingUuid() {
SimpleQuery<VolumeVO> q = dbf.createQuery(VolumeVO.class);
q.add(VolumeVO_.type, Op.EQ, VolumeType.Root);
q.add(VolumeVO_.rootImageUuid, Op.NULL);
List<VolumeVO> volumes = q.list();
if (volumes.isEmpty()) {
return;
}
final Map<String, List<VolumeVO>> groupByPrimaryStorageUuid = new HashMap();
for (VolumeVO vo : volumes) {
List<VolumeVO> vos = groupByPrimaryStorageUuid.get(vo.getPrimaryStorageUuid());
if (vos == null) {
vos = new ArrayList();
groupByPrimaryStorageUuid.put(vo.getPrimaryStorageUuid(), vos);
}
vos.add(vo);
}
evtf.on(PrimaryStorageCanonicalEvent.PRIMARY_STORAGE_STATUS_CHANGED_PATH, new EventCallback() {
List<String> supportPsTypes = asList("NFS", "LocalStorage");
@Override
public void run(Map tokens, Object data) {
PrimaryStorageStatusChangedData d = (PrimaryStorageStatusChangedData) data;
if (!PrimaryStorageStatus.Connected.toString().equals(d.getNewStatus())) {
return;
}
final List<VolumeVO> vos = groupByPrimaryStorageUuid.get(d.getPrimaryStorageUuid());
if (vos == null) {
return;
}
if (!supportPsTypes.contains(d.getInventory().getType())) {
return;
}
List<GetVolumeRootImageUuidFromPrimaryStorageMsg> msgs = CollectionUtils.transformToList(vos, new Function<GetVolumeRootImageUuidFromPrimaryStorageMsg, VolumeVO>() {
@Override
public GetVolumeRootImageUuidFromPrimaryStorageMsg call(VolumeVO arg) {
GetVolumeRootImageUuidFromPrimaryStorageMsg msg = new GetVolumeRootImageUuidFromPrimaryStorageMsg();
msg.setVolume(VolumeInventory.valueOf(arg));
bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, arg.getPrimaryStorageUuid());
return msg;
}
});
for (final GetVolumeRootImageUuidFromPrimaryStorageMsg msg : msgs) {
bus.send(msg, new CloudBusCallBack(null) {
@Override
public void run(MessageReply reply) {
if (reply.isSuccess()) {
GetVolumeRootImageUuidFromPrimaryStorageReply r = reply.castReply();
VolumeVO vol = CollectionUtils.find(vos, new Function<VolumeVO, VolumeVO>() {
@Override
public VolumeVO call(VolumeVO arg) {
return arg.getUuid().equals(msg.getVolume().getUuid()) ? arg : null;
}
});
vol.setRootImageUuid(r.getImageUuid());
dbf.update(vol);
vos.remove(vol);
} else {
logger.warn(String.format("unable to get the rootImageUuid for the volume[uuid:%s], %s",
msg.getVolume().getUuid(), reply.getError()));
}
}
});
}
}
});
}
private void syncVolumeSize() {
evtf.on(PrimaryStorageCanonicalEvent.PRIMARY_STORAGE_STATUS_CHANGED_PATH, new EventCallback() {
@Override
public void run(Map tokens, Object data) {
if (!evtf.isFromThisManagementNode(tokens)) {
return;
}
PrimaryStorageStatusChangedData d = (PrimaryStorageStatusChangedData) data;
if (!PrimaryStorageStatus.Connected.toString().equals(d.getNewStatus())) {
return;
}
SimpleQuery<VolumeVO> q = dbf.createQuery(VolumeVO.class);
q.add(VolumeVO_.primaryStorageUuid, Op.EQ, d.getPrimaryStorageUuid());
q.add(VolumeVO_.status, Op.EQ, VolumeStatus.Ready);
q.add(VolumeVO_.actualSize, Op.NULL);
List<VolumeVO> vols = q.list();
if (vols.isEmpty()) {
return;
}
List<SyncVolumeSizeMsg> msgs = CollectionUtils.transformToList(vols, new Function<SyncVolumeSizeMsg, VolumeVO>() {
@Override
public SyncVolumeSizeMsg call(VolumeVO arg) {
SyncVolumeSizeMsg msg = new SyncVolumeSizeMsg();
msg.setVolumeUuid(arg.getUuid());
bus.makeTargetServiceIdByResourceUuid(msg, VolumeConstant.SERVICE_ID, arg.getUuid());
return msg;
}
});
bus.send(msgs);
}
});
}
@Override
public boolean stop() {
return true;
}
}