diff --git a/core/src/main/java/org/zstack/core/agent/AgentManagerImpl.java b/core/src/main/java/org/zstack/core/agent/AgentManagerImpl.java index 27966a5c73c..6ee2a326222 100755 --- a/core/src/main/java/org/zstack/core/agent/AgentManagerImpl.java +++ b/core/src/main/java/org/zstack/core/agent/AgentManagerImpl.java @@ -3,6 +3,7 @@ import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.zstack.core.CoreGlobalProperty; +import org.zstack.core.Platform; import org.zstack.core.ansible.AnsibleNeedRun; import org.zstack.core.ansible.AnsibleRunner; import org.zstack.core.ansible.SshFolderMd5Checker; @@ -21,6 +22,7 @@ import org.zstack.header.core.ReturnValueCompletion; import org.zstack.header.core.workflow.*; import org.zstack.header.errorcode.ErrorCode; +import org.zstack.header.errorcode.ErrorableValue; import org.zstack.header.exception.CloudRuntimeException; import org.zstack.header.message.Message; import org.zstack.header.rest.RESTFacade; @@ -52,6 +54,10 @@ public static String buildAgentUrl(String ip, int port, String path) { return String.format(HTTP_URL_FORMAT, IPv6NetworkUtils.formatHostForUrl(ip), port, path); } + public static String buildCommandUrl(RESTFacade restf, String managementNodeIp) { + return managementNodeIp == null ? restf.getSendCommandUrl() : restf.buildSendCommandUrl(managementNodeIp); + } + @Autowired private CloudBus bus; @Autowired @@ -114,7 +120,7 @@ public String getName() { }); } - private void connect(final DeployAgentMsg msg, final Completion completion) { + private void connect(final DeployAgentMsg msg, final String managementNodeIp, final Completion completion) { FlowChain chain = FlowChainBuilder.newShareFlowChain(); chain.setName(String.format("continue-connect-agent-server-%s:%s", msg.getIp(), msg.getAgentPort())); chain.then(new ShareFlow() { @@ -149,7 +155,7 @@ public void fail(ErrorCode errorCode) { @Override public void run(FlowTrigger trigger, Map data) { Map config = new HashMap(); - config.put(AgentConstant.CONFIG_COMMAND_URL, restf.getSendCommandUrl()); + config.put(AgentConstant.CONFIG_COMMAND_URL, buildCommandUrl(restf, managementNodeIp)); if (msg.getConfig() != null) { config.putAll(msg.getConfig()); } @@ -193,6 +199,20 @@ private void deployAgent(final DeployAgentMsg msg, final NoErrorCompletion noErr return; } + final String managementNodeIp; + if (NetworkUtils.isIpAddress(msg.getIp())) { + ErrorableValue endpoint = Platform.getManagementServerIp(msg.getIp()); + if (!endpoint.isSuccess()) { + reply.setError(endpoint.error); + bus.reply(msg, reply); + noErrorCompletion.done(); + return; + } + managementNodeIp = endpoint.result; + } else { + managementNodeIp = null; + } + try { String agentYamlPath = PathUtil.join(AgentConstant.ANSIBLE_MODULE_PATH, "server", AgentConstant.ANSIBLE_PLAYBOOK_NAME); File agentYaml = PathUtil.findFileOnClassPath(agentYamlPath, true); @@ -254,6 +274,9 @@ public boolean isRunNeed() { runner.setSshPort(msg.getSshPort()); } runner.setTargetIp(msg.getIp()); + if (managementNodeIp != null) { + runner.setManagementNodeIp(managementNodeIp); + } runner.setPlayBookPath(tmpAgentYaml.getAbsolutePath()); runner.run(new ReturnValueCompletion(msg, noErrorCompletion) { @Override @@ -271,7 +294,7 @@ public void run() { } }); - connect(msg, new Completion(msg, noErrorCompletion) { + connect(msg, managementNodeIp, new Completion(msg, noErrorCompletion) { @Override public void success() { bus.reply(msg, reply); diff --git a/core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java b/core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java index 0fc9ecf4a7b..bb8dabeee48 100755 --- a/core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java +++ b/core/src/main/java/org/zstack/core/rest/RESTFacadeImpl.java @@ -63,6 +63,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import static org.zstack.core.Platform.*; import static org.zstack.utils.clouderrorcode.CloudOperationsErrorCode.*; @@ -194,7 +195,8 @@ void init() { port = Platform.getManagementNodeServicePort(); - IptablesUtils.insertRuleToFilterTable(String.format("-A INPUT -p tcp -m state --state NEW -m tcp --dport %s -j ACCEPT", port)); + installRestPortFirewallRules(port, Platform.getManagementServerIp6() != null, + IptablesUtils::insertRuleToFilterTable, IptablesUtils::insertRuleToFilterTableV6); if ("AUTO".equals(hostname)) { callbackHostName = Platform.getManagementServerIp(); @@ -224,6 +226,16 @@ public static String buildBaseUrl(String hostName, int port, String path) { return UriComponentsBuilder.fromHttpUrl(url).build().toUriString(); } + static void installRestPortFirewallRules(int port, boolean ipv6Enabled, + Consumer ipv4RuleInstaller, + Consumer ipv6RuleInstaller) { + String rule = String.format("-A INPUT -p tcp -m state --state NEW -m tcp --dport %s -j ACCEPT", port); + ipv4RuleInstaller.accept(rule); + if (ipv6Enabled) { + ipv6RuleInstaller.accept(rule); + } + } + public static String buildCallbackUrl(String hostName, int port, String path) { UriComponentsBuilder ub = UriComponentsBuilder.fromHttpUrl(buildBaseUrl(hostName, port, path)); ub.path(RESTConstant.CALLBACK_PATH); @@ -1072,6 +1084,11 @@ public String getSendCommandUrl() { return sendCommandUrl; } + @Override + public String buildSendCommandUrl(String hostName) { + return buildSendCommandUrl(hostName, port, path); + } + @Override public String getCallbackUrl() { return callbackUrl; diff --git a/header/src/main/java/org/zstack/header/rest/RESTFacade.java b/header/src/main/java/org/zstack/header/rest/RESTFacade.java index 23fee5208c2..266dec0fb01 100755 --- a/header/src/main/java/org/zstack/header/rest/RESTFacade.java +++ b/header/src/main/java/org/zstack/header/rest/RESTFacade.java @@ -89,6 +89,8 @@ public interface RESTFacade { String getSendCommandUrl(); + String buildSendCommandUrl(String hostName); + String getCallbackUrl(); /** diff --git a/test/src/test/groovy/org/zstack/core/agent/AgentManagerCommandUrlCase.groovy b/test/src/test/groovy/org/zstack/core/agent/AgentManagerCommandUrlCase.groovy new file mode 100644 index 00000000000..d71a54b3113 --- /dev/null +++ b/test/src/test/groovy/org/zstack/core/agent/AgentManagerCommandUrlCase.groovy @@ -0,0 +1,22 @@ +package org.zstack.core.agent + +import org.junit.Test +import org.zstack.header.rest.RESTFacade + +class AgentManagerCommandUrlCase { + @Test + void testSelectedManagementNodeBuildsCommandUrl() { + RESTFacade restf = [ + getSendCommandUrl: { "http://192.168.1.10:8080/zstack/asyncrest/sendcommand" }, + buildSendCommandUrl: { String host -> + assert host == "2001:db8::10" + "http://[2001:db8::10]:8080/zstack/asyncrest/sendcommand" + } + ] as RESTFacade + + assert AgentManagerImpl.buildCommandUrl(restf, "2001:db8::10") == + "http://[2001:db8::10]:8080/zstack/asyncrest/sendcommand" + assert AgentManagerImpl.buildCommandUrl(restf, null) == + "http://192.168.1.10:8080/zstack/asyncrest/sendcommand" + } +} diff --git a/utils/src/main/java/org/zstack/utils/IptablesUtils.java b/utils/src/main/java/org/zstack/utils/IptablesUtils.java index fc3e8500b30..94dd7613118 100755 --- a/utils/src/main/java/org/zstack/utils/IptablesUtils.java +++ b/utils/src/main/java/org/zstack/utils/IptablesUtils.java @@ -14,12 +14,20 @@ public static void appendRuleToFilterTable(String rule) { } public static void insertRuleToFilterTable(String rule) { - ShellResult ret = ShellUtils.runAndReturn(String.format("/sbin/iptables-save | grep -- '%s' > /dev/null", rule)); + insertRuleToFilterTable("iptables", rule); + } + + public static void insertRuleToFilterTableV6(String rule) { + insertRuleToFilterTable("ip6tables", rule); + } + + private static void insertRuleToFilterTable(String command, String rule) { + ShellResult ret = ShellUtils.runAndReturn(String.format("/sbin/%s-save | grep -- '%s' > /dev/null", command, rule)); if (ret.getRetCode() == 0) { return; } - ret = ShellUtils.runAndReturn(String.format("/sbin/iptables %s", rule.replace("-A", "-I"))); + ret = ShellUtils.runAndReturn(String.format("/sbin/%s %s", command, rule.replace("-A", "-I"))); ret.raiseExceptionIfFail(); }