package org.zstack.network.service.virtualrouter.nat;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
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.workflow.FlowTrigger;
import org.zstack.header.core.workflow.NoRollbackFlow;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.message.MessageReply;
import org.zstack.header.network.service.NetworkServiceType;
import org.zstack.header.vm.VmInstanceConstant;
import org.zstack.header.vm.VmNicInventory;
import org.zstack.network.service.virtualrouter.*;
import org.zstack.network.service.virtualrouter.VirtualRouterCommands.SNATInfo;
import org.zstack.network.service.virtualrouter.VirtualRouterCommands.SyncSNATRsp;
import org.zstack.utils.Utils;
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.List;
import java.util.Map;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class VirtualRouterSyncSNATOnStartFlow extends NoRollbackFlow {
private static final CLogger logger = Utils.getLogger(VirtualRouterSyncSNATOnStartFlow.class);
@Autowired
private CloudBus bus;
@Autowired
private VirtualRouterManager vrMgr;
@Autowired
private ErrorFacade errf;
@Autowired
private ApiTimeoutManager apiTimeoutManager;
@Override
public void run(final FlowTrigger chain, Map data) {
final VirtualRouterVmInventory vr = (VirtualRouterVmInventory) data.get(VirtualRouterConstant.Param.VR.toString());
List<String> nwServed = vr.getAllL3Networks();
nwServed = vrMgr.selectL3NetworksNeedingSpecificNetworkService(nwServed, NetworkServiceType.SNAT);
if (nwServed.isEmpty()) {
chain.next();
return;
}
if (VirtualRouterSystemTags.DEDICATED_ROLE_VR.hasTag(vr.getUuid()) && !VirtualRouterSystemTags.VR_SNAT_ROLE.hasTag(vr.getUuid())) {
chain.next();
return;
}
new VirtualRouterRoleManager().makeSnatRole(vr.getUuid());
final List<SNATInfo> snatInfo = new ArrayList<SNATInfo>();
for (VmNicInventory nic : vr.getVmNics()) {
if (nwServed.contains(nic.getL3NetworkUuid())) {
SNATInfo info = new SNATInfo();
info.setPrivateNicIp(nic.getIp());
info.setPrivateNicMac(nic.getMac());
info.setPublicIp(vr.getPublicNic().getIp());
info.setPublicNicMac(vr.getPublicNic().getMac());
info.setSnatNetmask(nic.getNetmask());
snatInfo.add(info);
}
}
VirtualRouterCommands.SyncSNATCmd cmd = new VirtualRouterCommands.SyncSNATCmd();
cmd.setSnats(snatInfo);
VirtualRouterAsyncHttpCallMsg msg = new VirtualRouterAsyncHttpCallMsg();
msg.setPath(VirtualRouterConstant.VR_SYNC_SNAT_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(chain) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
chain.fail(reply.getError());
return;
}
VirtualRouterAsyncHttpCallReply re = reply.castReply();
SyncSNATRsp ret = re.toResponse(SyncSNATRsp.class);
if (!ret.isSuccess()) {
ErrorCode err = operr("virtual router[name: %s, uuid: %s] failed to sync snat%s, %s",
vr.getName(), vr.getUuid(), JSONObjectUtil.toJsonString(snatInfo), ret.getError());
chain.fail(err);
} else {
chain.next();
}
}
});
}
}