package org.zstack.storage.primary.local;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.core.workflow.Flow;
import org.zstack.header.core.workflow.FlowTrigger;
import org.zstack.header.core.workflow.NoRollbackFlow;
import org.zstack.header.host.AddHostMessage;
import org.zstack.header.host.FailToAddHostExtensionPoint;
import org.zstack.header.host.HostInventory;
import org.zstack.header.message.MessageReply;
import org.zstack.header.storage.primary.PrimaryStorageConstant;
import org.zstack.header.storage.primary.PrimaryStorageVO;
import org.zstack.header.storage.primary.RecalculatePrimaryStorageCapacityMsg;
import org.zstack.kvm.KVMConstant;
import org.zstack.kvm.KVMHostConnectExtensionPoint;
import org.zstack.kvm.KVMHostConnectedContext;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
import javax.persistence.TypedQuery;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static org.zstack.core.Platform.operr;
/**
* Created by frank on 6/30/2015.
*/
public class LocalStorageKvmFactory implements LocalStorageHypervisorFactory, KVMHostConnectExtensionPoint,
FailToAddHostExtensionPoint {
private static final CLogger logger = Utils.getLogger(LocalStorageKvmFactory.class);
@Autowired
private DatabaseFacade dbf;
@Autowired
private CloudBus bus;
@Autowired
private ErrorFacade errf;
@Override
public String getHypervisorType() {
return KVMConstant.KVM_HYPERVISOR_TYPE;
}
@Override
public LocalStorageHypervisorBackend getHypervisorBackend(PrimaryStorageVO vo) {
return new LocalStorageKvmBackend(vo);
}
@Transactional(readOnly = true)
private List<String> findLocalStorageUuidByHostUuid(String clusterUuid) {
String sql = "select pri.uuid" +
" from PrimaryStorageVO pri, PrimaryStorageClusterRefVO ref" +
" where pri.uuid = ref.primaryStorageUuid" +
" and ref.clusterUuid = :cuuid" +
" and pri.type = :ptype";
TypedQuery<String> q = dbf.getEntityManager().createQuery(sql, String.class);
q.setParameter("cuuid", clusterUuid);
q.setParameter("ptype", LocalStorageConstants.LOCAL_STORAGE_TYPE);
return q.getResultList();
}
@Override
public Flow createKvmHostConnectingFlow(final KVMHostConnectedContext context) {
return new NoRollbackFlow() {
String __name__ = "init-local-storage";
@Override
public void run(final FlowTrigger trigger, Map data) {
final List<String> priUuids = findLocalStorageUuidByHostUuid(context.getInventory().getClusterUuid());
if (priUuids == null || priUuids.isEmpty()) {
trigger.next();
return;
}
Iterator<String> iterator = priUuids.iterator();
initLocalStorage(iterator, trigger, data, context);
}
};
}
private void initLocalStorage(final Iterator<String> iterator,
final FlowTrigger trigger,
Map data,
final KVMHostConnectedContext context) {
if (!iterator.hasNext()) {
trigger.next();
return;
}
final String priUuid = iterator.next();
InitPrimaryStorageOnHostConnectedMsg msg = new InitPrimaryStorageOnHostConnectedMsg();
msg.setPrimaryStorageUuid(priUuid);
msg.setHostUuid(context.getInventory().getUuid());
bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, priUuid);
bus.send(msg, new CloudBusCallBack(trigger) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
trigger.fail(operr("KVM host[uuid: %s] fails to be added into local primary storage[uuid: %s], %s",
context.getInventory().getUuid(), priUuid, reply.getError()));
} else {
initLocalStorage(iterator, trigger, data, context);
}
}
});
}
@Override
public void failedToAddHost(HostInventory host, AddHostMessage amsg) {
final List<String> priUuids = findLocalStorageUuidByHostUuid(host.getClusterUuid());
if (priUuids == null || priUuids.isEmpty()) {
return;
}
for (String priUUid : priUuids) {
RecalculatePrimaryStorageCapacityMsg msg = new RecalculatePrimaryStorageCapacityMsg();
msg.setPrimaryStorageUuid(priUUid);
bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, priUUid);
bus.send(msg, new CloudBusCallBack(null) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
logger.warn(String.format("failed to sync primary storage[uuid:%s] capacity, %s",
priUuids, reply.getError()));
}
}
});
}
}
}