package org.zstack.compute.cluster;
import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.Platform;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.MessageSafe;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.DbEntityLister;
import org.zstack.core.defer.Deferred;
import org.zstack.header.AbstractService;
import org.zstack.header.cluster.*;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.message.APIMessage;
import org.zstack.header.message.Message;
import org.zstack.search.GetQuery;
import org.zstack.search.SearchQuery;
import org.zstack.tag.TagManager;
import org.zstack.utils.ObjectUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.data.FieldPrinter;
import org.zstack.utils.logging.CLogger;
import java.util.*;
public class ClusterManagerImpl extends AbstractService implements ClusterManager {
private static final CLogger logger = Utils.getLogger(ClusterManager.class);
private static final FieldPrinter printer = Utils.getFieldPrinter();
@Autowired
private CloudBus bus;
@Autowired
private DatabaseFacade dbf;
@Autowired
private PluginRegistry pluginRgty;
@Autowired
private DbEntityLister dl;
@Autowired
private TagManager tagMgr;
private Map<String, ClusterFactory> clusterFactories = Collections.synchronizedMap(new HashMap<String, ClusterFactory>());
private static final Set<Class> allowedMessageAfterSoftDeletion = new HashSet<Class>();
static {
allowedMessageAfterSoftDeletion.add(ClusterDeletionMsg.class);
}
private void handleApiMessage(APIMessage msg) {
if (msg instanceof APICreateClusterMsg) {
handle((APICreateClusterMsg) msg);
} else if (msg instanceof APIListClusterMsg) {
handle((APIListClusterMsg) msg);
} else if (msg instanceof APISearchClusterMsg) {
handle((APISearchClusterMsg) msg);
} else if (msg instanceof APIGetClusterMsg) {
handle((APIGetClusterMsg) msg);
} else if (msg instanceof ClusterMessage) {
passThrough((ClusterMessage) msg);
}
}
private void handle(APIGetClusterMsg msg) {
GetQuery q = new GetQuery();
String res = q.getAsString(msg, ClusterInventory.class);
APIGetClusterReply reply = new APIGetClusterReply();
reply.setInventory(res);
bus.reply(msg, reply);
}
private void handle(APISearchClusterMsg msg) {
SearchQuery<ClusterInventory> query = SearchQuery.create(msg, ClusterInventory.class);
String ret = query.listAsString();
APISearchClusterReply reply = new APISearchClusterReply();
reply.setContent(ret);
bus.reply(msg, reply);
}
private void passThrough(ClusterMessage msg) {
ClusterVO vo = dbf.findByUuid(msg.getClusterUuid(), ClusterVO.class);
if (vo == null && allowedMessageAfterSoftDeletion.contains(msg.getClass())) {
ClusterEO eo = dbf.findByUuid(msg.getClusterUuid(), ClusterEO.class);
vo = ObjectUtils.newAndCopy(eo, ClusterVO.class);
}
if (vo == null) {
String err = String.format("Cannot find cluster: %s, it may have been deleted", msg.getClusterUuid());
bus.replyErrorByMessageType((Message) msg, err);
return;
}
ClusterFactory factory = this.getClusterFactory(ClusterType.valueOf(vo.getType()));
Cluster cluster = factory.getCluster(vo);
cluster.handleMessage((Message) msg);
}
private void handle(APIListClusterMsg msg) {
APIListClusterReply reply = new APIListClusterReply();
List<ClusterVO> vos = dl.listByApiMessage(msg, ClusterVO.class);
List<ClusterInventory> invs = ClusterInventory.valueOf(vos);
reply.setInventories(invs);
bus.reply(msg, reply);
}
@Deferred
private void handle(APICreateClusterMsg msg) {
String clusterType = msg.getType();
if (clusterType == null) {
clusterType = BaseClusterFactory.type.toString();
}
APICreateClusterEvent evt = new APICreateClusterEvent(msg.getId());
ClusterFactory factory = this.getClusterFactory(ClusterType.valueOf(clusterType));
ClusterVO vo = new ClusterVO();
if (msg.getResourceUuid() != null) {
vo.setUuid(msg.getResourceUuid());
} else {
vo.setUuid(Platform.getUuid());
}
vo.setDescription(msg.getDescription());
vo.setHypervisorType(msg.getHypervisorType());
vo.setManagementNodeId(Platform.getManagementServerId());
vo.setZoneUuid(msg.getZoneUuid());
vo.setState(ClusterState.Enabled);
vo.setName(msg.getClusterName());
vo = factory.createCluster(vo, msg);
tagMgr.createTagsFromAPICreateMessage(msg, vo.getUuid(), ClusterVO.class.getSimpleName());
ClusterInventory inv = ClusterInventory.valueOf(vo);
evt.setInventory(inv);
logger.debug(String.format("Created new cluster: %s", printer.print(inv)));
bus.publish(evt);
}
@Override
@MessageSafe
public void handleMessage(Message msg) {
if (msg instanceof APIMessage) {
handleApiMessage((APIMessage) msg);
} else if (msg instanceof ClusterMessage) {
passThrough((ClusterMessage) msg);
} else {
bus.dealWithUnknownMessage(msg);
}
}
@Override
public String getId() {
return bus.makeLocalServiceId(ClusterConstant.SERVICE_ID);
}
private void populateClusterFactories() {
for (ClusterFactory ext : pluginRgty.getExtensionList(ClusterFactory.class)) {
ClusterFactory old = clusterFactories.get(ext.getType().toString());
if (old != null) {
throw new CloudRuntimeException(String.format("duplicate ClusterFactory[%s, %s] for type[%s]",
old.getClass().getName(), ext.getClass().getName(), ext.getType()));
}
clusterFactories.put(ext.getType().toString(), ext);
}
}
@Override
public boolean start() {
populateClusterFactories();
return true;
}
@Override
public boolean stop() {
return true;
}
private ClusterFactory getClusterFactory(ClusterType type) {
ClusterFactory factory = clusterFactories.get(type.toString());
if (factory == null) {
throw new CloudRuntimeException(String.format("No ClusterFactory of type[%s] found", type));
}
return factory;
}
}