package org.zstack.network.service.virtualrouter.lifecycle; import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; import org.zstack.appliancevm.ApplianceVmConstant; import org.zstack.appliancevm.ApplianceVmSpec; import org.zstack.core.CoreGlobalProperty; import org.zstack.core.ansible.AnsibleFacade; import org.zstack.core.ansible.AnsibleGlobalProperty; import org.zstack.core.ansible.AnsibleRunner; import org.zstack.core.ansible.SshFileMd5Checker; import org.zstack.core.errorcode.ErrorFacade; import org.zstack.core.workflow.FlowChainBuilder; import org.zstack.core.workflow.ShareFlow; import org.zstack.header.core.Completion; import org.zstack.header.core.workflow.*; import org.zstack.header.errorcode.ErrorCode; import org.zstack.header.rest.JsonAsyncRESTCallback; import org.zstack.header.rest.RESTFacade; import org.zstack.header.vm.VmInstanceConstant; import org.zstack.header.vm.VmInstanceSpec; import org.zstack.header.vm.VmNicInventory; import org.zstack.network.service.virtualrouter.VirtualRouterCommands.InitCommand; import org.zstack.network.service.virtualrouter.VirtualRouterCommands.InitRsp; import org.zstack.network.service.virtualrouter.*; import org.zstack.network.service.virtualrouter.VirtualRouterConstant.Param; import org.zstack.utils.CollectionUtils; import org.zstack.utils.DebugUtils; import org.zstack.utils.Utils; import org.zstack.utils.function.Function; import org.zstack.utils.logging.CLogger; import org.zstack.utils.path.PathUtil; import static org.zstack.core.Platform.operr; import java.util.Map; @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE) public class VirtualRouterDeployAgentFlow extends NoRollbackFlow { private static final CLogger logger = Utils.getLogger(VirtualRouterDeployAgentFlow.class); @Autowired private AnsibleFacade asf; @Autowired private VirtualRouterManager vrMgr; @Autowired private RESTFacade restf; @Autowired private ErrorFacade errf; private String agentPackageName = VirtualRouterGlobalProperty.AGENT_PACKAGE_NAME; private void continueConnect(final VmNicInventory mgmtNic, final Map<String, Object> data, final FlowTrigger completion) { final VirtualRouterVmInventory vr = (VirtualRouterVmInventory) data.get(VirtualRouterConstant.Param.VR.toString()); final FlowChain chain = FlowChainBuilder.newShareFlowChain(); chain.setName(String.format("virtual-router-%s-continue-connecting", mgmtNic.getVmInstanceUuid())); chain.then(new ShareFlow() { @Override public void setup() { flow(new NoRollbackFlow() { String __name__ = "echo"; @Override public void run(final FlowTrigger trigger, Map data) { String url = vrMgr.buildUrl(mgmtNic.getIp(), VirtualRouterConstant.VR_ECHO_PATH); restf.echo(url, new Completion(trigger) { @Override public void success() { trigger.next(); } @Override public void fail(ErrorCode errorCode) { trigger.fail(errorCode); } }); } }); flow(new NoRollbackFlow() { String __name__ = "init"; @Override public void run(final FlowTrigger trigger, Map data) { String url = vrMgr.buildUrl(mgmtNic.getIp(), VirtualRouterConstant.VR_INIT); InitCommand cmd = new InitCommand(); cmd.setUuid(vr.getUuid()); cmd.setRestartDnsmasqAfterNumberOfSIGUSER1(VirtualRouterGlobalConfig.RESTART_DNSMASQ_COUNT.value(Integer.class)); restf.asyncJsonPost(url, cmd, new JsonAsyncRESTCallback<InitRsp>(trigger) { @Override public void fail(ErrorCode err) { trigger.fail(err); } @Override public void success(InitRsp ret) { if (ret.isSuccess()) { trigger.next(); } else { trigger.fail(operr(ret.getError())); } } @Override public Class<InitRsp> getReturnClass() { return InitRsp.class; } }); } }); done(new FlowDoneHandler(completion) { @Override public void handle(Map data) { completion.next(); } }); error(new FlowErrorHandler(completion) { @Override public void handle(ErrorCode errCode, Map data) { completion.fail(errCode); } }); } }).start(); } @Override public void run(final FlowTrigger chain, final Map data) { final VirtualRouterVmInventory vr = (VirtualRouterVmInventory) data.get(VirtualRouterConstant.Param.VR.toString()); VmNicInventory mgmtNic = null; if (vr != null) { mgmtNic = vr.getManagementNic(); } else { final VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString()); final ApplianceVmSpec aspec = spec.getExtensionData(ApplianceVmConstant.Params.applianceVmSpec.toString(), ApplianceVmSpec.class); mgmtNic = CollectionUtils.find(spec.getDestNics(), new Function<VmNicInventory, VmNicInventory>() { @Override public VmNicInventory call(VmNicInventory arg) { if (arg.getL3NetworkUuid().equals(aspec.getManagementNic().getL3NetworkUuid())) { return arg; } return null; } }); DebugUtils.Assert(mgmtNic!=null, String.format("cannot find management nic for virtual router[uuid:%s, name:%s]", spec.getVmInventory().getUuid(), spec.getVmInventory().getName())); } boolean isReconnect = Boolean.valueOf((String) data.get(Param.IS_RECONNECT.toString())); if (CoreGlobalProperty.UNIT_TEST_ON) { continueConnect(mgmtNic, data, chain); return; } else if (!isReconnect && !VirtualRouterGlobalConfig.DEPLOY_AGENT_ON_START.value(Boolean.class)) { continueConnect(mgmtNic, data, chain); return; } final String username = "root"; final String privKey = asf.getPrivateKey(); final String mgmtIp = mgmtNic.getIp(); SshFileMd5Checker checker = new SshFileMd5Checker(); checker.setTargetIp(mgmtIp); checker.setUsername(username); checker.setPrivateKey(privKey); checker.addSrcDestPair(SshFileMd5Checker.ZSTACKLIB_SRC_PATH, String.format("/var/lib/zstack/virtualrouter/%s", AnsibleGlobalProperty.ZSTACKLIB_PACKAGE_NAME)); checker.addSrcDestPair(PathUtil.findFileOnClassPath(String.format("ansible/virtualrouter/%s", agentPackageName), true).getAbsolutePath(), String.format("/var/lib/zstack/virtualrouter/%s", agentPackageName)); AnsibleRunner runner = new AnsibleRunner(); runner.installChecker(checker); runner.setUsername(username); runner.setPlayBookName(VirtualRouterConstant.ANSIBLE_PLAYBOOK_NAME); runner.setPrivateKey(privKey); runner.setAgentPort(VirtualRouterGlobalProperty.AGENT_PORT); runner.setTargetIp(mgmtIp); runner.putArgument("pkg_virtualrouter", agentPackageName); final VmNicInventory fmgmtNic = mgmtNic; runner.run(new Completion(chain) { @Override public void success() { continueConnect(fmgmtNic, data, chain); } @Override public void fail(ErrorCode errorCode) { chain.fail(errorCode); } }); } }