package org.zstack.network.l2; import org.springframework.beans.factory.annotation.Autowired; import org.zstack.core.Platform; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.cloudbus.CloudBusListCallBack; 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.db.SimpleQuery; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.header.errorcode.SysErrors; import org.zstack.header.AbstractService; import org.zstack.header.core.Completion; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.host.HostAddExtensionPoint; import org.zstack.header.host.HostInventory; import org.zstack.header.host.HypervisorType; import org.zstack.header.message.APIEvent; import org.zstack.header.message.APIMessage; import org.zstack.header.message.Message; import org.zstack.header.message.MessageReply; import org.zstack.header.network.*; import org.zstack.header.network.l2.*; import org.zstack.header.notification.ApiNotification; import org.zstack.header.notification.ApiNotificationFactory; import org.zstack.header.notification.ApiNotificationFactoryExtensionPoint; 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.logging.CLogger; import java.util.*; public class L2NetworkManagerImpl extends AbstractService implements L2NetworkManager { private static final CLogger logger = Utils.getLogger(L2NetworkManagerImpl.class); @Autowired private CloudBus bus; @Autowired private DatabaseFacade dbf; @Autowired private PluginRegistry pluginRgty; @Autowired private DbEntityLister dl; @Autowired private TagManager tagMgr; @Autowired private ErrorFacade errf; private Map<String, L2NetworkFactory> l2NetworkFactories = Collections.synchronizedMap(new HashMap<String, L2NetworkFactory>()); private Map<L2NetworkType, Map<HypervisorType, L2NetworkRealizationExtensionPoint>> realizationExts = new HashMap<L2NetworkType, Map<HypervisorType, L2NetworkRealizationExtensionPoint>>(); private List<L2NetworkCreateExtensionPoint> createExtensions = new ArrayList<L2NetworkCreateExtensionPoint>(); private static final Set<Class> allowedMessageAfterSoftDeletion = new HashSet<Class>(); static { allowedMessageAfterSoftDeletion.add(L2NetworkDeletionMsg.class); } @Override @MessageSafe public void handleMessage(Message msg) { if (msg instanceof APIMessage) { handleApiMessage((APIMessage)msg); } else { handleLocalMessage(msg); } } private void handleLocalMessage(Message msg) { if (msg instanceof L2NetworkMessage) { passThrough((L2NetworkMessage)msg); } else { bus.dealWithUnknownMessage(msg); } } private void handleApiMessage(APIMessage msg) { if (msg instanceof APICreateL2NetworkMsg) { handle((APICreateL2NetworkMsg)msg); } else if (msg instanceof APIListL2NetworkMsg) { handle((APIListL2NetworkMsg) msg); } else if (msg instanceof APISearchL2NetworkMsg) { handle((APISearchL2NetworkMsg)msg); } else if (msg instanceof APISearchL2VlanNetworkMsg) { handle((APISearchL2VlanNetworkMsg)msg); } else if (msg instanceof APIGetL2NetworkMsg) { handle((APIGetL2NetworkMsg) msg); } else if (msg instanceof APIGetL2VlanNetworkMsg) { handle((APIGetL2VlanNetworkMsg)msg); } else if (msg instanceof APIGetL2NetworkTypesMsg) { handle((APIGetL2NetworkTypesMsg) msg); } else if (msg instanceof L2NetworkMessage) { passThrough((L2NetworkMessage) msg); } else { bus.dealWithUnknownMessage(msg); } } private void handle(APIGetL2NetworkTypesMsg msg) { List<String> types = new ArrayList<String>(); types.addAll(L2NetworkType.getAllTypeNames()); APIGetL2NetworkTypesReply reply = new APIGetL2NetworkTypesReply(); reply.setL2NetworkTypes(types); bus.reply(msg, reply); } private void handle(APIGetL2VlanNetworkMsg msg) { GetQuery q = new GetQuery(); String res = q.getAsString(msg, L2VlanNetworkInventory.class); APIGetL2VlanNetworkReply reply = new APIGetL2VlanNetworkReply(); reply.setInventory(res); bus.reply(msg, reply); } private void handle(APISearchL2VlanNetworkMsg msg) { SearchQuery<L2VlanNetworkInventory> sq = SearchQuery.create(msg, L2VlanNetworkInventory.class); String content = sq.listAsString(); APISearchL2VlanNetworkReply reply = new APISearchL2VlanNetworkReply(); reply.setContent(content); bus.reply(msg, reply); } private void handle(APIGetL2NetworkMsg msg) { GetQuery q = new GetQuery(); String res = q.getAsString(msg, L2NetworkInventory.class); APIGetL2NetworkReply reply = new APIGetL2NetworkReply(); reply.setInventory(res); bus.reply(msg, reply); } private void handle(APISearchL2NetworkMsg msg) { SearchQuery<L2NetworkInventory> sq = SearchQuery.create(msg, L2NetworkInventory.class); String content = sq.listAsString(); APISearchL2NetworkReply reply = new APISearchL2NetworkReply(); reply.setContent(content); bus.reply(msg, reply); } private void passThrough(L2NetworkMessage msg) { Message amsg = (Message) msg; L2NetworkVO vo = dbf.findByUuid(msg.getL2NetworkUuid(), L2NetworkVO.class); if (vo == null && allowedMessageAfterSoftDeletion.contains(msg.getClass())) { L2NetworkEO eo = dbf.findByUuid(msg.getL2NetworkUuid(), L2NetworkEO.class); vo = ObjectUtils.newAndCopy(eo, L2NetworkVO.class); } if (vo == null) { ErrorCode errCode = errf.instantiateErrorCode(SysErrors.RESOURCE_NOT_FOUND, String.format("unable to find L2Network[uuid:%s], it may have been deleted", msg.getL2NetworkUuid())); bus.replyErrorByMessageType((Message)msg, errCode); return; } L2NetworkFactory factory = getL2NetworkFactory(L2NetworkType.valueOf(vo.getType())); L2Network nw = factory.getL2Network(vo); nw.handleMessage(amsg); } private void handle(APIListL2NetworkMsg msg) { List<L2NetworkVO> vos = dl.listByApiMessage(msg, L2NetworkVO.class); List<L2NetworkInventory> invs = L2NetworkInventory.valueOf(vos); APIListL2NetworkReply reply = new APIListL2NetworkReply(); reply.setInventories(invs); bus.reply(msg, reply); } private void handle(APICreateL2NetworkMsg msg) { for (L2NetworkCreateExtensionPoint extp : createExtensions) { try { extp.beforeCreateL2Network(msg); } catch (NetworkException e) { String err = String.format("unable to create l2network[name:%s, type:%s], %s", msg.getName(), msg.getType(), e.getMessage()); logger.warn(err, e); APICreateL2NetworkEvent evt = new APICreateL2NetworkEvent(msg.getId()); evt.setError(errf.instantiateErrorCode(SysErrors.CREATE_RESOURCE_ERROR, err)); bus.publish(evt); return; } } L2NetworkType type = L2NetworkType.valueOf(msg.getType()); L2NetworkFactory factory = getL2NetworkFactory(type); L2NetworkVO vo = new L2NetworkVO(); if (msg.getResourceUuid() != null) { vo.setUuid(msg.getResourceUuid()); } else { vo.setUuid(Platform.getUuid()); } vo.setDescription(msg.getDescription()); vo.setName(msg.getName()); vo.setPhysicalInterface(msg.getPhysicalInterface()); vo.setType(type.toString()); vo.setZoneUuid(msg.getZoneUuid()); L2NetworkInventory inv = factory.createL2Network(vo, msg); tagMgr.createTagsFromAPICreateMessage(msg, inv.getUuid(), L2NetworkVO.class.getSimpleName()); for (L2NetworkCreateExtensionPoint extp : createExtensions) { try { extp.afterCreateL2Network(inv); } catch (Exception e) { logger.warn(String.format("unhandled exception happened when calling %s", extp.getClass().getName()), e); } } APICreateL2NetworkEvent evt = new APICreateL2NetworkEvent(msg.getId()); evt.setInventory(inv); bus.publish(evt); } @Override public String getId() { return bus.makeLocalServiceId(L2NetworkConstant.SERVICE_ID); } @Override public boolean start() { populateExtensions(); return true; } @Override public boolean stop() { return false; } @Override public L2NetworkFactory getL2NetworkFactory(L2NetworkType type) { L2NetworkFactory factory = l2NetworkFactories.get(type.toString()); if (factory == null) { throw new CloudRuntimeException(String.format("Cannot find L2NetworkFactory for type(%s)", type)); } return factory; } @Override public L2NetworkRealizationExtensionPoint getRealizationExtension(L2NetworkType l2Type, HypervisorType hvType) { Map<HypervisorType, L2NetworkRealizationExtensionPoint> map = realizationExts.get(l2Type); if (map == null) { throw new IllegalArgumentException(String.format("Cannot find L2NetworkRealizationExtensionPoint supporting L2NetworkType[%s]", l2Type)); } L2NetworkRealizationExtensionPoint extp = map.get(hvType); if (extp == null) { throw new IllegalArgumentException(String.format("Cannot find L2NetworkRealizationExtensionPoint for L2NetworkType[%s] supporting hypervisor[%s]", l2Type, hvType)); } return extp; } private void populateExtensions() { for (L2NetworkFactory f : pluginRgty.getExtensionList(L2NetworkFactory.class)) { L2NetworkFactory old = l2NetworkFactories.get(f.getType().toString()); if (old != null) { throw new CloudRuntimeException(String.format("duplicate L2NetworkFactory[%s, %s] for type[%s]", f.getClass().getName(), old.getClass().getName(), f.getType())); } l2NetworkFactories.put(f.getType().toString(), f); } for (L2NetworkRealizationExtensionPoint extp : pluginRgty.getExtensionList(L2NetworkRealizationExtensionPoint.class)) { Map<HypervisorType, L2NetworkRealizationExtensionPoint> map = realizationExts.get(extp.getSupportedL2NetworkType()); if (map == null) { map = new HashMap<HypervisorType, L2NetworkRealizationExtensionPoint>(1); realizationExts.put(extp.getSupportedL2NetworkType(), map); } map.put(extp.getSupportedHypervisorType(), extp); } createExtensions = pluginRgty.getExtensionList(L2NetworkCreateExtensionPoint.class); } }