@@ -15,10 +15,14 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.transport.config; | package com.alibaba.csp.sentinel.transport.config; | ||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import com.alibaba.csp.sentinel.config.SentinelConfig; | import com.alibaba.csp.sentinel.config.SentinelConfig; | ||||
import com.alibaba.csp.sentinel.log.RecordLog; | import com.alibaba.csp.sentinel.log.RecordLog; | ||||
import com.alibaba.csp.sentinel.util.HostNameUtil; | import com.alibaba.csp.sentinel.util.HostNameUtil; | ||||
import com.alibaba.csp.sentinel.util.StringUtil; | import com.alibaba.csp.sentinel.util.StringUtil; | ||||
import com.alibaba.csp.sentinel.util.function.Tuple2; | |||||
/** | /** | ||||
* @author leyou | * @author leyou | ||||
@@ -51,12 +55,69 @@ public class TransportConfig { | |||||
} | } | ||||
/** | /** | ||||
* Get ip:port of Sentinel Dashboard. | |||||
* Get a list of (ip/domain, port) indicating Sentinel Dashboard's address.<br> | |||||
* NOTE: only support <b>HTTP</b> protocol | |||||
* | * | ||||
* @return console server ip:port, maybe null if not configured | |||||
* @return list of (ip/domain, port) pair. <br> | |||||
* <b>May not be null</b>. <br> | |||||
* An empty list returned when not configured. | |||||
*/ | */ | ||||
public static String getConsoleServer() { | |||||
return SentinelConfig.getConfig(CONSOLE_SERVER); | |||||
public static List<Tuple2<String, Integer>> getConsoleServerList() { | |||||
String config = SentinelConfig.getConfig(CONSOLE_SERVER); | |||||
List<Tuple2<String, Integer>> list = new ArrayList<Tuple2<String, Integer>>(); | |||||
if (StringUtil.isBlank(config)) { | |||||
RecordLog.warn("Dashboard server address is not configured"); | |||||
return list; | |||||
} | |||||
int pos = -1; | |||||
int cur = 0; | |||||
while (true) { | |||||
pos = config.indexOf(',', cur); | |||||
if (cur < config.length() - 1 && pos < 0) { | |||||
// for single segment, pos move to the end | |||||
pos = config.length(); | |||||
} | |||||
if (pos < 0) { | |||||
break; | |||||
} | |||||
if (pos <= cur) { | |||||
cur ++; | |||||
continue; | |||||
} | |||||
// parsing | |||||
String ipPortStr = config.substring(cur, pos); | |||||
cur = pos + 1; | |||||
if (StringUtil.isBlank(ipPortStr)) { | |||||
continue; | |||||
} | |||||
ipPortStr = ipPortStr.trim(); | |||||
if (ipPortStr.startsWith("http://")) { | |||||
ipPortStr = ipPortStr.substring(7); | |||||
} | |||||
int index = ipPortStr.indexOf(":"); | |||||
int port = 80; | |||||
if (index == 0) { | |||||
// skip | |||||
continue; | |||||
} | |||||
String host = ipPortStr; | |||||
if (index >= 0) { | |||||
try { | |||||
port = Integer.parseInt(ipPortStr.substring(index + 1)); | |||||
if (port <= 1 || port >= 65535) { | |||||
throw new RuntimeException("Port number [" + port + "] over range"); | |||||
} | |||||
} catch (Exception e) { | |||||
RecordLog.warn("Parse port of dashboard server failed: " + ipPortStr, e); | |||||
// skip | |||||
continue; | |||||
} | |||||
host = ipPortStr.substring(0, index); | |||||
} | |||||
list.add(Tuple2.of(host, port)); | |||||
} | |||||
return list; | |||||
} | } | ||||
public static int getRuntimePort() { | public static int getRuntimePort() { | ||||
@@ -17,6 +17,7 @@ package com.alibaba.csp.sentinel.transport.config; | |||||
import com.alibaba.csp.sentinel.config.SentinelConfig; | import com.alibaba.csp.sentinel.config.SentinelConfig; | ||||
import com.alibaba.csp.sentinel.util.StringUtil; | import com.alibaba.csp.sentinel.util.StringUtil; | ||||
import com.alibaba.csp.sentinel.util.function.Tuple2; | |||||
import org.junit.After; | import org.junit.After; | ||||
import org.junit.Before; | import org.junit.Before; | ||||
@@ -24,6 +25,8 @@ import org.junit.Test; | |||||
import static org.junit.Assert.*; | import static org.junit.Assert.*; | ||||
import java.util.List; | |||||
public class TransportConfigTest { | public class TransportConfigTest { | ||||
@Before | @Before | ||||
@@ -82,4 +85,84 @@ public class TransportConfigTest { | |||||
SentinelConfig.removeConfig(TransportConfig.HEARTBEAT_API_PATH); | SentinelConfig.removeConfig(TransportConfig.HEARTBEAT_API_PATH); | ||||
assertEquals(TransportConfig.HEARTBEAT_DEFAULT_PATH, TransportConfig.getHeartbeatApiPath()); | assertEquals(TransportConfig.HEARTBEAT_DEFAULT_PATH, TransportConfig.getHeartbeatApiPath()); | ||||
} | } | ||||
} | |||||
@Test | |||||
public void testGetConsoleServerList() { | |||||
// empty | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, ""); | |||||
List<Tuple2<String, Integer>> list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(0, list.size()); | |||||
// single ip | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "112.13.223.3"); | |||||
list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(1, list.size()); | |||||
assertEquals("112.13.223.3", list.get(0).r1); | |||||
assertEquals(new Integer(80), list.get(0).r2); | |||||
// single domain | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "www.dashboard.org"); | |||||
list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(1, list.size()); | |||||
assertEquals("www.dashboard.org", list.get(0).r1); | |||||
assertEquals(new Integer(80), list.get(0).r2); | |||||
// single ip including port | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "www.dashboard.org:81"); | |||||
list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(1, list.size()); | |||||
assertEquals("www.dashboard.org", list.get(0).r1); | |||||
assertEquals(new Integer(81), list.get(0).r2); | |||||
// mixed | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "www.dashboard.org:81,112.13.223.3,112.13.223.4:8080,www.dashboard.org"); | |||||
list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(4, list.size()); | |||||
assertEquals("www.dashboard.org", list.get(0).r1); | |||||
assertEquals(new Integer(81), list.get(0).r2); | |||||
assertEquals("112.13.223.3", list.get(1).r1); | |||||
assertEquals(new Integer(80), list.get(1).r2); | |||||
assertEquals("112.13.223.4", list.get(2).r1); | |||||
assertEquals(new Integer(8080), list.get(2).r2); | |||||
assertEquals("www.dashboard.org", list.get(3).r1); | |||||
assertEquals(new Integer(80), list.get(3).r2); | |||||
// malformed | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "www.dashboard.org:0"); | |||||
list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(0, list.size()); | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "www.dashboard.org:-1"); | |||||
list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(0, list.size()); | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, ":80"); | |||||
list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(0, list.size()); | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "www.dashboard.org:"); | |||||
list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(0, list.size()); | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "www.dashboard.org:80000"); | |||||
list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(0, list.size()); | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "www.dashboard.org:80000,www.dashboard.org:81,:80"); | |||||
list = TransportConfig.getConsoleServerList(); | |||||
assertNotNull(list); | |||||
assertEquals(1, list.size()); | |||||
assertEquals("www.dashboard.org", list.get(0).r1); | |||||
assertEquals(new Integer(81), list.get(0).r2); | |||||
} | |||||
} |
@@ -15,7 +15,6 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.transport.heartbeat; | package com.alibaba.csp.sentinel.transport.heartbeat; | ||||
import java.util.ArrayList; | |||||
import java.util.List; | import java.util.List; | ||||
import com.alibaba.csp.sentinel.Constants; | import com.alibaba.csp.sentinel.Constants; | ||||
@@ -58,7 +57,7 @@ public class HttpHeartbeatSender implements HeartbeatSender { | |||||
public HttpHeartbeatSender() { | public HttpHeartbeatSender() { | ||||
this.client = HttpClients.createDefault(); | this.client = HttpClients.createDefault(); | ||||
List<Tuple2<String, Integer>> dashboardList = parseDashboardList(); | |||||
List<Tuple2<String, Integer>> dashboardList = TransportConfig.getConsoleServerList(); | |||||
if (dashboardList == null || dashboardList.isEmpty()) { | if (dashboardList == null || dashboardList.isEmpty()) { | ||||
RecordLog.info("[NettyHttpHeartbeatSender] No dashboard available"); | RecordLog.info("[NettyHttpHeartbeatSender] No dashboard available"); | ||||
} else { | } else { | ||||
@@ -68,40 +67,6 @@ public class HttpHeartbeatSender implements HeartbeatSender { | |||||
} | } | ||||
} | } | ||||
protected static List<Tuple2<String, Integer>> parseDashboardList() { | |||||
List<Tuple2<String, Integer>> list = new ArrayList<Tuple2<String, Integer>>(); | |||||
try { | |||||
String ipsStr = TransportConfig.getConsoleServer(); | |||||
if (StringUtil.isBlank(ipsStr)) { | |||||
RecordLog.warn("[NettyHttpHeartbeatSender] Dashboard server address is not configured"); | |||||
return list; | |||||
} | |||||
for (String ipPortStr : ipsStr.split(",")) { | |||||
if (ipPortStr.trim().length() == 0) { | |||||
continue; | |||||
} | |||||
ipPortStr = ipPortStr.trim(); | |||||
if (ipPortStr.startsWith("http://")) { | |||||
ipPortStr = ipPortStr.substring(7); | |||||
} | |||||
if (ipPortStr.startsWith(":")) { | |||||
continue; | |||||
} | |||||
String[] ipPort = ipPortStr.trim().split(":"); | |||||
int port = 80; | |||||
if (ipPort.length > 1) { | |||||
port = Integer.parseInt(ipPort[1].trim()); | |||||
} | |||||
list.add(Tuple2.of(ipPort[0].trim(), port)); | |||||
} | |||||
} catch (Exception ex) { | |||||
RecordLog.warn("[NettyHttpHeartbeatSender] Parse dashboard list failed, current address list: " + list, ex); | |||||
ex.printStackTrace(); | |||||
} | |||||
return list; | |||||
} | |||||
@Override | @Override | ||||
public boolean sendHeartbeat() throws Exception { | public boolean sendHeartbeat() throws Exception { | ||||
if (StringUtil.isEmpty(consoleHost)) { | if (StringUtil.isEmpty(consoleHost)) { | ||||
@@ -1,58 +0,0 @@ | |||||
package com.alibaba.csp.sentinel.transport.heartbeat; | |||||
import static org.junit.Assert.assertEquals; | |||||
import java.util.List; | |||||
import org.junit.Test; | |||||
import com.alibaba.csp.sentinel.config.SentinelConfig; | |||||
import com.alibaba.csp.sentinel.transport.config.TransportConfig; | |||||
import com.alibaba.csp.sentinel.util.function.Tuple2; | |||||
public class HttpHeartbeatSenderTest { | |||||
private void setAddr(String serverList) { | |||||
SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, serverList); | |||||
} | |||||
@Test | |||||
public void testAddr() { | |||||
setAddr(""); | |||||
assertEquals(0, HttpHeartbeatSender.parseDashboardList().size()); | |||||
setAddr("a.com"); | |||||
List<Tuple2<String, Integer>> list = HttpHeartbeatSender.parseDashboardList(); | |||||
assertEquals(1, list.size()); | |||||
assertEquals("a.com", list.get(0).r1); | |||||
assertEquals(Integer.valueOf(80), list.get(0).r2); | |||||
setAddr("a.com:88"); | |||||
list = HttpHeartbeatSender.parseDashboardList(); | |||||
assertEquals(1, list.size()); | |||||
assertEquals("a.com", list.get(0).r1); | |||||
assertEquals(Integer.valueOf(88), list.get(0).r2); | |||||
setAddr("a.com:88,,,,"); | |||||
list = HttpHeartbeatSender.parseDashboardList(); | |||||
assertEquals(1, list.size()); | |||||
assertEquals("a.com", list.get(0).r1); | |||||
assertEquals(Integer.valueOf(88), list.get(0).r2); | |||||
setAddr("a.com:88,b.com"); | |||||
list = HttpHeartbeatSender.parseDashboardList(); | |||||
assertEquals(2, list.size()); | |||||
assertEquals("a.com", list.get(0).r1); | |||||
assertEquals(Integer.valueOf(88), list.get(0).r2); | |||||
assertEquals("b.com", list.get(1).r1); | |||||
assertEquals(Integer.valueOf(80), list.get(1).r2); | |||||
setAddr("a.com:88,b.com:99999"); | |||||
list = HttpHeartbeatSender.parseDashboardList(); | |||||
assertEquals(2, list.size()); | |||||
assertEquals("a.com", list.get(0).r1); | |||||
assertEquals(Integer.valueOf(88), list.get(0).r2); | |||||
assertEquals("b.com", list.get(1).r1); | |||||
assertEquals(Integer.valueOf(99999), list.get(1).r2); | |||||
} | |||||
} |
@@ -26,6 +26,7 @@ import com.alibaba.csp.sentinel.transport.heartbeat.client.SimpleHttpClient; | |||||
import com.alibaba.csp.sentinel.transport.heartbeat.client.SimpleHttpRequest; | import com.alibaba.csp.sentinel.transport.heartbeat.client.SimpleHttpRequest; | ||||
import com.alibaba.csp.sentinel.transport.heartbeat.client.SimpleHttpResponse; | import com.alibaba.csp.sentinel.transport.heartbeat.client.SimpleHttpResponse; | ||||
import com.alibaba.csp.sentinel.util.StringUtil; | import com.alibaba.csp.sentinel.util.StringUtil; | ||||
import com.alibaba.csp.sentinel.util.function.Tuple2; | |||||
/** | /** | ||||
* The heartbeat sender provides basic API for sending heartbeat request to provided target. | * The heartbeat sender provides basic API for sending heartbeat request to provided target. | ||||
@@ -43,13 +44,13 @@ public class SimpleHttpHeartbeatSender implements HeartbeatSender { | |||||
private final HeartbeatMessage heartBeat = new HeartbeatMessage(); | private final HeartbeatMessage heartBeat = new HeartbeatMessage(); | ||||
private final SimpleHttpClient httpClient = new SimpleHttpClient(); | private final SimpleHttpClient httpClient = new SimpleHttpClient(); | ||||
private final List<InetSocketAddress> addressList; | |||||
private final List<Tuple2<String, Integer>> addressList; | |||||
private int currentAddressIdx = 0; | private int currentAddressIdx = 0; | ||||
public SimpleHttpHeartbeatSender() { | public SimpleHttpHeartbeatSender() { | ||||
// Retrieve the list of default addresses. | // Retrieve the list of default addresses. | ||||
List<InetSocketAddress> newAddrs = getDefaultConsoleIps(); | |||||
List<Tuple2<String, Integer>> newAddrs = TransportConfig.getConsoleServerList(); | |||||
RecordLog.info("[SimpleHttpHeartbeatSender] Default console address list retrieved: " + newAddrs); | RecordLog.info("[SimpleHttpHeartbeatSender] Default console address list retrieved: " + newAddrs); | ||||
this.addressList = newAddrs; | this.addressList = newAddrs; | ||||
} | } | ||||
@@ -60,11 +61,12 @@ public class SimpleHttpHeartbeatSender implements HeartbeatSender { | |||||
RecordLog.info("[SimpleHttpHeartbeatSender] Runtime port not initialized, won't send heartbeat"); | RecordLog.info("[SimpleHttpHeartbeatSender] Runtime port not initialized, won't send heartbeat"); | ||||
return false; | return false; | ||||
} | } | ||||
InetSocketAddress addr = getAvailableAddress(); | |||||
if (addr == null) { | |||||
Tuple2<String, Integer> addrInfo = getAvailableAddress(); | |||||
if (addrInfo == null) { | |||||
return false; | return false; | ||||
} | } | ||||
InetSocketAddress addr = new InetSocketAddress(addrInfo.r1, addrInfo.r2); | |||||
SimpleHttpRequest request = new SimpleHttpRequest(addr, TransportConfig.getHeartbeatApiPath()); | SimpleHttpRequest request = new SimpleHttpRequest(addr, TransportConfig.getHeartbeatApiPath()); | ||||
request.setParams(heartBeat.generateCurrentMessage()); | request.setParams(heartBeat.generateCurrentMessage()); | ||||
try { | try { | ||||
@@ -83,7 +85,7 @@ public class SimpleHttpHeartbeatSender implements HeartbeatSender { | |||||
return DEFAULT_INTERVAL; | return DEFAULT_INTERVAL; | ||||
} | } | ||||
private InetSocketAddress getAvailableAddress() { | |||||
private Tuple2<String, Integer> getAvailableAddress() { | |||||
if (addressList == null || addressList.isEmpty()) { | if (addressList == null || addressList.isEmpty()) { | ||||
return null; | return null; | ||||
} | } | ||||
@@ -94,33 +96,4 @@ public class SimpleHttpHeartbeatSender implements HeartbeatSender { | |||||
return addressList.get(index); | return addressList.get(index); | ||||
} | } | ||||
private List<InetSocketAddress> getDefaultConsoleIps() { | |||||
List<InetSocketAddress> newAddrs = new ArrayList<InetSocketAddress>(); | |||||
try { | |||||
String ipsStr = TransportConfig.getConsoleServer(); | |||||
if (StringUtil.isEmpty(ipsStr)) { | |||||
RecordLog.warn("[SimpleHttpHeartbeatSender] Dashboard server address not configured"); | |||||
return newAddrs; | |||||
} | |||||
for (String ipPortStr : ipsStr.split(",")) { | |||||
if (ipPortStr.trim().length() == 0) { | |||||
continue; | |||||
} | |||||
if (ipPortStr.startsWith("http://")) { | |||||
ipPortStr = ipPortStr.trim().substring(7); | |||||
} | |||||
String[] ipPort = ipPortStr.trim().split(":"); | |||||
int port = 80; | |||||
if (ipPort.length > 1) { | |||||
port = Integer.parseInt(ipPort[1].trim()); | |||||
} | |||||
newAddrs.add(new InetSocketAddress(ipPort[0].trim(), port)); | |||||
} | |||||
} catch (Exception ex) { | |||||
RecordLog.warn("[SimpleHeartbeatSender] Parse dashboard list failed, current address list: " + newAddrs, ex); | |||||
ex.printStackTrace(); | |||||
} | |||||
return newAddrs; | |||||
} | |||||
} | } |