package org.zstack.kvm;
import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.GLock;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.core.timeout.ApiTimeoutManager;
import org.zstack.header.core.Completion;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.host.HostConstant;
import org.zstack.header.host.HypervisorType;
import org.zstack.header.message.MessageReply;
import org.zstack.header.network.l2.*;
import org.zstack.header.vm.VmNicInventory;
import org.zstack.kvm.KVMAgentCommands.CheckVlanBridgeResponse;
import org.zstack.kvm.KVMAgentCommands.CreateVlanBridgeCmd;
import org.zstack.kvm.KVMAgentCommands.CreateVlanBridgeResponse;
import org.zstack.kvm.KVMAgentCommands.NicTO;
import org.zstack.tag.SystemTagCreator;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
import static org.zstack.core.Platform.operr;
import static org.zstack.utils.CollectionDSL.e;
import static org.zstack.utils.CollectionDSL.map;
public class KVMRealizeL2VlanNetworkBackend implements L2NetworkRealizationExtensionPoint, KVMCompleteNicInformationExtensionPoint {
private static final CLogger logger = Utils.getLogger(KVMRealizeL2VlanNetworkBackend.class);
@Autowired
private DatabaseFacade dbf;
@Autowired
private ErrorFacade errf;
@Autowired
private CloudBus bus;
@Autowired
private ApiTimeoutManager timeoutMgr;
private String makeBridgeName(String physicalInterfaceName, int vlan) {
physicalInterfaceName = physicalInterfaceName.substring(0, Math.min(physicalInterfaceName.length(), 7));
return String.format("br_%s_%s", physicalInterfaceName, vlan);
}
public void realize(final L2NetworkInventory l2Network, final String hostUuid, boolean noStatusCheck, final Completion completion) {
final L2VlanNetworkInventory l2vlan = (L2VlanNetworkInventory) l2Network;
final CreateVlanBridgeCmd cmd = new CreateVlanBridgeCmd();
cmd.setPhysicalInterfaceName(l2Network.getPhysicalInterface());
cmd.setBridgeName(makeBridgeName(l2vlan.getPhysicalInterface(), l2vlan.getVlan()));
cmd.setVlan(l2vlan.getVlan());
KVMHostAsyncHttpCallMsg msg = new KVMHostAsyncHttpCallMsg();
msg.setHostUuid(hostUuid);
msg.setCommand(cmd);
msg.setCommandTimeout(timeoutMgr.getTimeout(cmd.getClass(), "5m"));
msg.setNoStatusCheck(noStatusCheck);
msg.setPath(KVMConstant.KVM_REALIZE_L2VLAN_NETWORK_PATH);
bus.makeTargetServiceIdByResourceUuid(msg, HostConstant.SERVICE_ID, hostUuid);
bus.send(msg, new CloudBusCallBack(completion) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
completion.fail(reply.getError());
return;
}
KVMHostAsyncHttpCallReply hreply = reply.castReply();
CreateVlanBridgeResponse rsp = hreply.toResponse(CreateVlanBridgeResponse.class);
if (!rsp.isSuccess()) {
ErrorCode err = operr("failed to create bridge[%s] for l2Network[uuid:%s, type:%s, vlan:%s] on kvm host[uuid:%s], because %s",
cmd.getBridgeName(), l2Network.getUuid(), l2Network.getType(), l2vlan.getVlan(), hostUuid, rsp.getError());
completion.fail(err);
return;
}
String info = String.format(
"successfully realize bridge[%s] for l2Network[uuid:%s, type:%s, vlan:%s] on kvm host[uuid:%s]", cmd
.getBridgeName(), l2Network.getUuid(), l2Network.getType(), l2vlan.getVlan(), hostUuid);
logger.debug(info);
SystemTagCreator creator = KVMSystemTags.L2_BRIDGE_NAME.newSystemTagCreator(l2Network.getUuid());
creator.inherent = true;
creator.ignoreIfExisting = true;
creator.setTagByTokens(map(e(KVMSystemTags.L2_BRIDGE_NAME_TOKEN, cmd.getBridgeName())));
creator.create();
completion.success();
}
});
}
@Override
public void realize(final L2NetworkInventory l2Network, final String hostUuid, final Completion completion) {
realize(l2Network, hostUuid, false, completion);
}
public void check(final L2NetworkInventory l2Network, final String hostUuid, boolean noStatusCheck, final Completion completion) {
final L2VlanNetworkInventory l2vlan = (L2VlanNetworkInventory) l2Network;
final KVMAgentCommands.CheckVlanBridgeCmd cmd = new KVMAgentCommands.CheckVlanBridgeCmd();
cmd.setPhysicalInterfaceName(l2Network.getPhysicalInterface());
cmd.setBridgeName(makeBridgeName(l2vlan.getPhysicalInterface(), l2vlan.getVlan()));
cmd.setVlan(l2vlan.getVlan());
KVMHostAsyncHttpCallMsg msg = new KVMHostAsyncHttpCallMsg();
msg.setHostUuid(hostUuid);
msg.setCommand(cmd);
msg.setCommandTimeout(timeoutMgr.getTimeout(cmd.getClass(), "5m"));
msg.setPath(KVMConstant.KVM_CHECK_L2VLAN_NETWORK_PATH);
msg.setNoStatusCheck(noStatusCheck);
bus.makeTargetServiceIdByResourceUuid(msg, HostConstant.SERVICE_ID, hostUuid);
bus.send(msg, new CloudBusCallBack(completion) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
completion.fail(reply.getError());
return;
}
KVMHostAsyncHttpCallReply hreply = reply.castReply();
CheckVlanBridgeResponse rsp = hreply.toResponse(CheckVlanBridgeResponse.class);
if (!rsp.isSuccess()) {
ErrorCode err = operr("failed to check bridge[%s] for l2VlanNetwork[uuid:%s, name:%s] on kvm host[uuid:%s], %s",
cmd.getBridgeName(), l2vlan.getUuid(), l2vlan.getName(), hostUuid, rsp.getError());
completion.fail(err);
return;
}
String info = String.format("successfully checked bridge[%s] for l2VlanNetwork[uuid:%s, name:%s] on kvm host[uuid:%s]",
cmd.getBridgeName(), l2vlan.getUuid(), l2vlan.getName(), hostUuid);
logger.debug(info);
completion.success();
}
});
}
@Override
public void check(final L2NetworkInventory l2Network, final String hostUuid, final Completion completion) {
check(l2Network, hostUuid, false, completion);
}
@Override
public L2NetworkType getSupportedL2NetworkType() {
return L2NetworkType.valueOf(L2NetworkConstant.L2_VLAN_NETWORK_TYPE);
}
@Override
public HypervisorType getSupportedHypervisorType() {
return HypervisorType.valueOf(KVMConstant.KVM_HYPERVISOR_TYPE);
}
@Override
public L2NetworkType getL2NetworkTypeVmNicOn() {
return getSupportedL2NetworkType();
}
@Override
public NicTO completeNicInformation(L2NetworkInventory l2Network, VmNicInventory nic) {
L2VlanNetworkVO vo = dbf.findByUuid(l2Network.getUuid(), L2VlanNetworkVO.class);
NicTO to = new NicTO();
to.setMac(nic.getMac());
to.setUuid(nic.getUuid());
to.setBridgeName(makeBridgeName(l2Network.getPhysicalInterface(), vo.getVlan()));
to.setDeviceId(nic.getDeviceId());
to.setNicInternalName(nic.getInternalName());
to.setMetaData(String.valueOf(vo.getVlan()));
return to;
}
}