package org.zstack.network.service.virtualrouter.dns; import org.springframework.beans.factory.annotation.Autowired; import org.zstack.appliancevm.ApplianceVmStatus; import org.zstack.core.cloudbus.CloudBus; import org.zstack.core.cloudbus.CloudBusCallBack; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.core.timeout.ApiTimeoutManager; import org.zstack.header.core.Completion; import org.zstack.header.core.NoErrorCompletion; import org.zstack.header.core.ReturnValueCompletion; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.message.MessageReply; import org.zstack.header.network.l3.L3NetworkInventory; import org.zstack.header.network.service.NetworkServiceProviderType; import org.zstack.header.network.service.DnsStruct; import org.zstack.header.network.service.NetworkServiceDnsBackend; import org.zstack.header.vm.VmInstanceConstant; import org.zstack.header.vm.VmInstanceSpec; import org.zstack.header.vm.VmInstanceState; import org.zstack.network.service.virtualrouter.*; import org.zstack.network.service.virtualrouter.VirtualRouterCommands.*; import org.zstack.utils.CollectionUtils; import org.zstack.utils.Utils; import org.zstack.utils.function.Function; import org.zstack.utils.gson.JSONObjectUtil; import org.zstack.utils.logging.CLogger; import static org.zstack.core.Platform.operr; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** */ public class VirtualRouterDnsBackend extends AbstractVirtualRouterBackend implements NetworkServiceDnsBackend { private final CLogger logger = Utils.getLogger(VirtualRouterDnsBackend.class); @Autowired private CloudBus bus; @Autowired private ErrorFacade errf; @Autowired private ApiTimeoutManager apiTimeoutManager; @Override public NetworkServiceProviderType getProviderType() { return VirtualRouterConstant.PROVIDER_TYPE; } @Override public void addDns(L3NetworkInventory l3, List<String> dns, final Completion completion) { VirtualRouterVmInventory vr = vrMgr.getVirtualRouterVm(l3); if (vr == null || !VmInstanceState.Running.toString().equals(vr.getState()) || !ApplianceVmStatus.Connected.toString().equals(vr.getStatus())) { completion.success(); return; } SetDnsCmd cmd = new SetDnsCmd(); cmd.setDns(CollectionUtils.transformToList(dns, new Function<DnsInfo, String>() { @Override public DnsInfo call(String arg) { DnsInfo info = new DnsInfo(); info.setNicMac(vr.getGuestNic().getMac()); info.setDnsAddress(arg); return info; } })); VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg(); msg.setVmInstanceUuid(vr.getUuid()); msg.setPath(VirtualRouterConstant.VR_SET_DNS_PATH); msg.setCommand(cmd); msg.setCommandTimeout(apiTimeoutManager.getTimeout(cmd.getClass(), "30m")); msg.setCheckStatus(true); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send(msg, new CloudBusCallBack(completion) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { completion.fail(reply.getError()); return; } VirtualRouterAsyncHttpCallReply r = reply.castReply(); SetDnsRsp rsp = r.toResponse(SetDnsRsp.class); if (!rsp.isSuccess()) { completion.fail(operr(rsp.getError())); return; } completion.success(); } }); } @Override public void removeDns(L3NetworkInventory l3, List<String> dns, final Completion completion) { VirtualRouterVmInventory vr = vrMgr.getVirtualRouterVm(l3); if (vr == null || !VmInstanceState.Running.toString().equals(vr.getState()) || !ApplianceVmStatus.Connected.toString().equals(vr.getStatus())) { completion.success(); return; } RemoveDnsCmd cmd = new RemoveDnsCmd(); cmd.setDns(CollectionUtils.transformToList(dns, new Function<DnsInfo, String>() { @Override public DnsInfo call(String arg) { DnsInfo info = new DnsInfo(); info.setDnsAddress(arg); info.setNicMac(vr.getGuestNic().getMac()); return info; } })); VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg(); msg.setVmInstanceUuid(vr.getUuid()); msg.setPath(VirtualRouterConstant.VR_REMOVE_DNS_PATH); msg.setCommand(cmd); msg.setCommandTimeout(apiTimeoutManager.getTimeout(cmd.getClass(), "30m")); msg.setCheckStatus(true); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send(msg, new CloudBusCallBack(completion) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { completion.fail(reply.getError()); return; } VirtualRouterAsyncHttpCallReply r = reply.castReply(); RemoveDnsRsp rsp = r.toResponse(RemoveDnsRsp.class); if (!rsp.isSuccess()) { completion.fail(operr(rsp.getError())); return; } completion.success(); } }); } private void applyDns(final Iterator<DnsStruct> it, final VmInstanceSpec spec, final Completion completion) { if (!it.hasNext()) { completion.success(); return; } final DnsStruct struct = it.next(); final L3NetworkInventory l3 = struct.getL3Network(); VirtualRouterStruct s = new VirtualRouterStruct(); s.setL3Network(l3); acquireVirtualRouterVm(s, new ReturnValueCompletion<VirtualRouterVmInventory>(completion) { @Override public void success(final VirtualRouterVmInventory vr) { final List<VirtualRouterCommands.DnsInfo> dns = new ArrayList<VirtualRouterCommands.DnsInfo>(l3.getDns().size()); for (String d : l3.getDns()) { VirtualRouterCommands.DnsInfo dinfo = new VirtualRouterCommands.DnsInfo(); dinfo.setDnsAddress(d); dinfo.setNicMac(vr.getGuestNic().getMac()); dns.add(dinfo); } VirtualRouterCommands.SetDnsCmd cmd = new VirtualRouterCommands.SetDnsCmd(); cmd.setDns(dns); VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg(); msg.setVmInstanceUuid(vr.getUuid()); msg.setPath(VirtualRouterConstant.VR_SET_DNS_PATH); msg.setCommand(cmd); msg.setCommandTimeout(apiTimeoutManager.getTimeout(cmd.getClass(), "30m")); msg.setCheckStatus(true); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send(msg, new CloudBusCallBack(completion) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { completion.fail(reply.getError()); return; } VirtualRouterAsyncHttpCallReply re = reply.castReply(); SetDnsRsp ret = re.toResponse(SetDnsRsp.class); if (ret.isSuccess()) { new VirtualRouterRoleManager().makeDnsRole(vr.getUuid()); logger.debug(String.format("successfully add dns entry[%s] to virtual router vm[uuid:%s, ip:%s]", struct, vr.getUuid(), vr.getManagementNic() .getIp())); applyDns(it, spec, completion); } else { ErrorCode err = operr("virtual router[uuid:%s, ip:%s] failed to configure dns%s for L3Network[uuid:%s, name:%s], %s", vr.getUuid(), vr.getManagementNic().getIp(), struct, l3.getUuid(), l3.getName(), ret.getError()); completion.fail(err); } } }); } @Override public void fail(ErrorCode errorCode) { completion.fail(errorCode); } }); } @Override public void applyDnsService(List<DnsStruct> dnsStructList, VmInstanceSpec spec, Completion completion) { if (dnsStructList.isEmpty()) { completion.success(); return; } applyDns(dnsStructList.iterator(), spec, completion); } private void releaseDns(final Iterator<DnsStruct> it, final VmInstanceSpec spec, final NoErrorCompletion completion) { if (!it.hasNext()) { completion.done(); return; } DnsStruct struct = it.next(); if (!vrMgr.isVirtualRouterRunningForL3Network(struct.getL3Network().getUuid())) { logger.debug(String.format("virtual router for l3Network[uuid:%s] is not running, skip releasing DNS", struct.getL3Network().getUuid())); releaseDns(it, spec, completion); return; } final VirtualRouterVmInventory vr = vrMgr.getVirtualRouterVm(struct.getL3Network()); final List<VirtualRouterCommands.DnsInfo> info = new ArrayList<VirtualRouterCommands.DnsInfo>(); for (String dns : struct.getDns()) { VirtualRouterCommands.DnsInfo i = new VirtualRouterCommands.DnsInfo(); i.setDnsAddress(dns); i.setNicMac(vr.getGuestNic().getMac()); info.add(i); } VirtualRouterCommands.RemoveDnsCmd cmd = new VirtualRouterCommands.RemoveDnsCmd(); cmd.setDns(info); VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg(); msg.setCheckStatus(true); msg.setPath(VirtualRouterConstant.VR_REMOVE_DNS_PATH); msg.setCommand(cmd); msg.setCommandTimeout(apiTimeoutManager.getTimeout(cmd.getClass(), "30m")); msg.setVmInstanceUuid(vr.getUuid()); bus.makeTargetServiceIdByResourceUuid(msg, VmInstanceConstant.SERVICE_ID, vr.getUuid()); bus.send(msg, new CloudBusCallBack(completion) { @Override public void run(MessageReply reply) { if (!reply.isSuccess()) { logger.warn(String.format("virtual router[name: %s, uuid: %s] failed to remove dns%s, because %s", vr.getName(), vr.getUuid(), JSONObjectUtil.toJsonString(info), reply.getError())); // TODO GC } else { VirtualRouterAsyncHttpCallReply re = reply.castReply(); RemoveDnsRsp ret = re.toResponse(RemoveDnsRsp.class); if (ret.isSuccess()) { logger.warn(String.format("virtual router[name: %s, uuid: %s] successfully removed dns%s", vr.getName(), vr.getUuid(), JSONObjectUtil.toJsonString(info))); } else { logger.warn(String.format("virtual router[name: %s, uuid: %s] failed to remove dns%s, because %s", vr.getName(), vr.getUuid(), JSONObjectUtil.toJsonString(info), ret.getError())); //TODO GC } } releaseDns(it, spec, completion); } }); } @Override public void releaseDnsService(List<DnsStruct> dnsStructList, VmInstanceSpec spec, NoErrorCompletion completion) { if (dnsStructList.isEmpty()) { completion.done(); return; } releaseDns(dnsStructList.iterator(), spec, completion); } }