Skip to content

Commit c8b77b3

Browse files
authored
[#5013] Fixing the issue where microservices cannot be registered when enabling RBAC authentication in a dual-engine disaster recovery scenario. (#5014)
1 parent 88774b8 commit c8b77b3

File tree

39 files changed

+463
-175
lines changed

39 files changed

+463
-175
lines changed

clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterAddressManager.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@
2828

2929
public class ConfigCenterAddressManager extends AbstractAddressManager {
3030

31-
public ConfigCenterAddressManager(String projectName, List<String> addresses, EventBus eventBus) {
32-
super(projectName, addresses);
31+
public ConfigCenterAddressManager(String projectName, List<String> addresses, String ownRegion,
32+
String ownAvailableZone, EventBus eventBus) {
33+
super(projectName, addresses, ownRegion, ownAvailableZone);
3334
eventBus.register(this);
3435
}
3536

clients/config-center-client/src/main/java/org/apache/servicecomb/config/center/client/ConfigCenterClient.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.apache.servicecomb.http.client.common.HttpResponse;
3333
import org.apache.servicecomb.http.client.common.HttpTransport;
3434
import org.apache.servicecomb.http.client.common.HttpUtils;
35+
import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
3536
import org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils;
3637
import org.slf4j.Logger;
3738
import org.slf4j.LoggerFactory;
@@ -61,12 +62,15 @@ public class ConfigCenterClient implements ConfigCenterOperation {
6162

6263
private final Map<String, List<String>> dimensionConfigNames = new HashMap<>();
6364

65+
private EventBus eventBus;
66+
6467
public ConfigCenterClient(ConfigCenterAddressManager addressManager, HttpTransport httpTransport) {
6568
this.addressManager = addressManager;
6669
this.httpTransport = httpTransport;
6770
}
6871

6972
public void setEventBus(EventBus eventBus) {
73+
this.eventBus = eventBus;
7074
addressManager.setEventBus(eventBus);
7175
}
7276

@@ -88,6 +92,7 @@ public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsReques
8892
HttpRequest.GET);
8993

9094
HttpResponse httpResponse = httpTransport.doRequest(httpRequest);
95+
recordAndSendUnAuthorizedEvent(httpResponse, address);
9196
if (httpResponse.getStatusCode() == HttpStatus.SC_OK) {
9297
Map<String, Map<String, Object>> allConfigMap = HttpUtils.deserialize(
9398
httpResponse.getContent(),
@@ -121,21 +126,17 @@ public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsReques
121126
}
122127
queryConfigurationsResponse.setConfigurations(configurations);
123128
queryConfigurationsResponse.setChanged(true);
124-
addressManager.recordSuccessState(address);
125129
return queryConfigurationsResponse;
126130
} else if (httpResponse.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
127131
queryConfigurationsResponse.setChanged(false);
128-
addressManager.recordSuccessState(address);
129132
return queryConfigurationsResponse;
130133
} else if (httpResponse.getStatusCode() == HttpStatus.SC_TOO_MANY_REQUESTS) {
131134
LOGGER.warn("rate limited, keep the local dimension [{}] configs unchanged.", dimensionsInfo);
132135
queryConfigurationsResponse.setChanged(false);
133-
addressManager.recordSuccessState(address);
134136
return queryConfigurationsResponse;
135137
} else if (httpResponse.getStatusCode() == HttpStatus.SC_BAD_REQUEST) {
136138
throw new OperationException("Bad request for query configurations.");
137139
} else {
138-
addressManager.recordFailState(address);
139140
throw new OperationException(
140141
"read response failed. status:"
141142
+ httpResponse.getStatusCode()
@@ -151,6 +152,16 @@ public QueryConfigurationsResponse queryConfigurations(QueryConfigurationsReques
151152
}
152153
}
153154

155+
private void recordAndSendUnAuthorizedEvent(HttpResponse response, String address) {
156+
if (this.eventBus != null && response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
157+
LOGGER.warn("query configuration unauthorized from server [{}], message [{}]", address, response.getMessage());
158+
addressManager.recordFailState(address);
159+
this.eventBus.post(new UnAuthorizedOperationEvent(address));
160+
} else {
161+
addressManager.recordSuccessState(address);
162+
}
163+
}
164+
154165
/**
155166
* Only the name of the new configuration item is printed.
156167
* No log is printed when the configuration content is updated.

clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.apache.servicecomb.http.client.common.HttpResponse;
4747
import org.apache.servicecomb.http.client.common.HttpTransport;
4848
import org.apache.servicecomb.http.client.common.HttpUtils;
49+
import org.apache.servicecomb.http.client.event.OperationEvents.UnAuthorizedOperationEvent;
4950
import org.apache.servicecomb.http.client.utils.ServiceCombServiceAvailableUtils;
5051
import org.slf4j.Logger;
5152
import org.slf4j.LoggerFactory;
@@ -71,13 +72,16 @@ public class KieClient implements KieConfigOperation {
7172

7273
private final Map<String, List<String>> dimensionConfigNames = new HashMap<>();
7374

75+
private EventBus eventBus;
76+
7477
public KieClient(KieAddressManager addressManager, HttpTransport httpTransport, KieConfiguration kieConfiguration) {
7578
this.httpTransport = httpTransport;
7679
this.addressManager = addressManager;
7780
this.kieConfiguration = kieConfiguration;
7881
}
7982

8083
public void setEventBus(EventBus eventBus) {
84+
this.eventBus = eventBus;
8185
addressManager.setEventBus(eventBus);
8286
}
8387

@@ -91,6 +95,7 @@ public ConfigurationsResponse queryConfigurations(ConfigurationsRequest request,
9195

9296
HttpRequest httpRequest = new HttpRequest(url, null, null, HttpRequest.GET);
9397
HttpResponse httpResponse = httpTransport.doRequest(httpRequest);
98+
recordAndSendUnAuthorizedEvent(httpResponse, address);
9499
ConfigurationsResponse configurationsResponse = new ConfigurationsResponse();
95100
if (httpResponse.getStatusCode() == HttpStatus.SC_OK) {
96101
revision = httpResponse.getHeader("X-Kie-Revision");
@@ -100,24 +105,20 @@ public ConfigurationsResponse queryConfigurations(ConfigurationsRequest request,
100105
configurationsResponse.setConfigurations(configurations);
101106
configurationsResponse.setChanged(true);
102107
configurationsResponse.setRevision(revision);
103-
addressManager.recordSuccessState(address);
104108
return configurationsResponse;
105109
}
106110
if (httpResponse.getStatusCode() == HttpStatus.SC_BAD_REQUEST) {
107111
throw new OperationException("Bad request for query configurations.");
108112
}
109113
if (httpResponse.getStatusCode() == HttpStatus.SC_NOT_MODIFIED) {
110114
configurationsResponse.setChanged(false);
111-
addressManager.recordSuccessState(address);
112115
return configurationsResponse;
113116
}
114117
if (httpResponse.getStatusCode() == HttpStatus.SC_TOO_MANY_REQUESTS) {
115118
LOGGER.warn("rate limited, keep the local dimension [{}] configs unchanged.", request.getLabelsQuery());
116119
configurationsResponse.setChanged(false);
117-
addressManager.recordSuccessState(address);
118120
return configurationsResponse;
119121
}
120-
addressManager.recordFailState(address);
121122
throw new OperationException(
122123
"read response failed. status:" + httpResponse.getStatusCode() + "; message:" +
123124
httpResponse.getMessage() + "; content:" + httpResponse.getContent());
@@ -128,6 +129,16 @@ public ConfigurationsResponse queryConfigurations(ConfigurationsRequest request,
128129
}
129130
}
130131

132+
private void recordAndSendUnAuthorizedEvent(HttpResponse response, String address) {
133+
if (this.eventBus != null && response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
134+
LOGGER.warn("query configuration unauthorized from server [{}], message [{}]", address, response.getMessage());
135+
addressManager.recordFailState(address);
136+
this.eventBus.post(new UnAuthorizedOperationEvent(address));
137+
} else {
138+
addressManager.recordSuccessState(address);
139+
}
140+
}
141+
131142
/**
132143
* Only the name of the new configuration item is printed.
133144
* No log is printed when the configuration content is updated.

clients/config-kie-client/src/main/java/org/apache/servicecomb/config/kie/client/model/KieAddressManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727

2828
public class KieAddressManager extends AbstractAddressManager {
2929

30-
public KieAddressManager(List<String> addresses, EventBus eventBus) {
31-
super(addresses);
30+
public KieAddressManager(List<String> addresses, String ownRegion, String ownAvailableZone, EventBus eventBus) {
31+
super(addresses, ownRegion, ownAvailableZone);
3232
eventBus.register(this);
3333
}
3434

clients/config-kie-client/src/test/java/org/apache/servicecomb/config/kie/client/model/KieAddressManagerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class KieAddressManagerTest {
4040
public void kieAddressManagerTest() throws NoSuchFieldException, IllegalAccessException {
4141
addresses.add("http://127.0.0.1:30103");
4242
addresses.add("https://127.0.0.2:30103");
43-
addressManager1 = new KieAddressManager(addresses, new EventBus());
43+
addressManager1 = new KieAddressManager(addresses, "", "", new EventBus());
4444
Field addressManagerField = addressManager1.getClass().getSuperclass().getDeclaredField("index");
4545
addressManagerField.setAccessible(true);
4646
addressManagerField.set(addressManager1, 0);
@@ -64,7 +64,7 @@ public void onRefreshEndpointEvent() {
6464
Map<String, List<String>> zoneAndRegion = new HashMap<>();
6565
zoneAndRegion.put("sameZone", addressAZ);
6666
zoneAndRegion.put("sameRegion", addressRG);
67-
addressManager1 = new KieAddressManager(addresses, new EventBus());
67+
addressManager1 = new KieAddressManager(addresses, "", "", new EventBus());
6868
RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "KIE");
6969
addressManager1.refreshEndpoint(event, "KIE");
7070

clients/dashboard-client/src/main/java/org/apache/servicecomb/dashboard/client/DashboardAddressManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929

3030
public class DashboardAddressManager extends AbstractAddressManager {
3131

32-
public DashboardAddressManager(List<String> addresses, EventBus eventBus) {
33-
super(addresses);
32+
public DashboardAddressManager(List<String> addresses, String ownRegion, String ownAvailableZone, EventBus eventBus) {
33+
super(addresses, ownRegion, ownAvailableZone);
3434
eventBus.register(this);
3535
}
3636

clients/dashboard-client/src/test/java/org/apache/servicecomb/dashboard/client/AddressManagerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class AddressManagerTest {
4141
public void kieAddressManagerTest() throws IllegalAccessException, NoSuchFieldException {
4242
addresses.add("http://127.0.0.1:30103");
4343
addresses.add("https://127.0.0.2:30103");
44-
addressManager1 = new DashboardAddressManager(addresses, new EventBus());
44+
addressManager1 = new DashboardAddressManager(addresses, "", "", new EventBus());
4545
Field addressManagerField = addressManager1.getClass().getSuperclass().getDeclaredField("index");
4646
addressManagerField.setAccessible(true);
4747
addressManagerField.set(addressManager1, 0);
@@ -65,7 +65,7 @@ public void onRefreshEndpointEvent() {
6565
Map<String, List<String>> zoneAndRegion = new HashMap<>();
6666
zoneAndRegion.put("sameZone", addressAZ);
6767
zoneAndRegion.put("sameRegion", addressRG);
68-
addressManager1 = new DashboardAddressManager(addresses, new EventBus());
68+
addressManager1 = new DashboardAddressManager(addresses, "", "", new EventBus());
6969
RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "CseMonitoring");
7070
addressManager1.refreshEndpoint(event, "CseMonitoring");
7171

clients/http-client-common/src/main/java/org/apache/servicecomb/http/client/common/AbstractAddressManager.java

Lines changed: 99 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@
1717

1818
package org.apache.servicecomb.http.client.common;
1919

20+
import java.net.URI;
2021
import java.util.ArrayList;
2122
import java.util.List;
2223
import java.util.Map;
2324
import java.util.Random;
25+
import java.util.Set;
2426
import java.util.concurrent.ConcurrentHashMap;
2527
import java.util.stream.Collectors;
2628

27-
import org.apache.commons.lang.StringUtils;
29+
import org.apache.commons.lang3.StringUtils;
2830
import org.apache.servicecomb.http.client.event.EngineConnectChangedEvent;
2931
import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
3032
import org.slf4j.Logger;
3133
import org.slf4j.LoggerFactory;
34+
import org.springframework.util.CollectionUtils;
3235

3336
import com.google.common.annotations.VisibleForTesting;
3437
import com.google.common.eventbus.EventBus;
@@ -42,6 +45,10 @@ public class AbstractAddressManager {
4245

4346
private static final String V3_PREFIX = "/v3/";
4447

48+
private static final String ZONE = "availableZone";
49+
50+
private static final String REGION = "region";
51+
4552
private static final int ISOLATION_THRESHOLD = 3;
4653

4754
private volatile List<String> addresses = new ArrayList<>();
@@ -74,17 +81,58 @@ public class AbstractAddressManager {
7481

7582
private EventBus eventBus;
7683

77-
public AbstractAddressManager(List<String> addresses) {
84+
public AbstractAddressManager(List<String> addresses, String ownRegion, String ownAvailableZone) {
7885
this.projectName = DEFAULT_PROJECT;
79-
this.addresses.addAll(addresses);
80-
this.defaultAddress.addAll(addresses);
86+
parseAndInitAddresses(addresses, ownRegion, ownAvailableZone, false);
8187
this.index = !addresses.isEmpty() ? getRandomIndex() : 0;
8288
}
8389

84-
public AbstractAddressManager(String projectName, List<String> addresses) {
90+
/**
91+
* address support config with region/availableZone info, to enable engine affinity calls during startup
92+
* address may be like:
93+
* https://192.168.20.13:30110?region=region1&availableZone=az
94+
* https://192.168.20.13:30100?region=region1&availableZone=az
95+
* When address have no datacenter information, roundRobin using address
96+
*
97+
* @param addresses engine addresses
98+
* @param ownRegion microservice region
99+
* @param ownAvailableZone microservice zone
100+
* @param isFormat is need format
101+
*/
102+
private void parseAndInitAddresses(List<String> addresses, String ownRegion, String ownAvailableZone,
103+
boolean isFormat) {
104+
if (CollectionUtils.isEmpty(addresses)) {
105+
return;
106+
}
107+
List<String> tempList = new ArrayList<>();
108+
addressAutoRefreshed = addresses.stream().anyMatch(addr -> addr.contains(ZONE) || addr.contains(REGION));
109+
for (String address : addresses) {
110+
// Compatible IpPortManager init address is 127.0.0.1:30100
111+
if (!address.startsWith("http")) {
112+
tempList.add(address);
113+
continue;
114+
}
115+
URLEndPoint endpoint = new URLEndPoint(address);
116+
tempList.add(endpoint.toString());
117+
buildAffinityAddress(endpoint, ownRegion, ownAvailableZone);
118+
}
119+
this.addresses.addAll(isFormat ? this.transformAddress(tempList) : tempList);
120+
this.defaultAddress.addAll(isFormat ? this.transformAddress(tempList) : tempList);
121+
}
122+
123+
private void buildAffinityAddress(URLEndPoint endpoint, String ownRegion, String ownAvailableZone) {
124+
if (addressAutoRefreshed) {
125+
if (regionAndAZMatch(ownRegion, ownAvailableZone, endpoint.getFirst(REGION), endpoint.getFirst(ZONE))) {
126+
availableZone.add(endpoint.toString());
127+
} else {
128+
availableRegion.add(endpoint.toString());
129+
}
130+
}
131+
}
132+
133+
public AbstractAddressManager(String projectName, List<String> addresses, String ownRegion, String ownAvailableZone) {
85134
this.projectName = StringUtils.isEmpty(projectName) ? DEFAULT_PROJECT : projectName;
86-
this.addresses = this.transformAddress(addresses);
87-
this.defaultAddress.addAll(addresses);
135+
parseAndInitAddresses(addresses, ownRegion, ownAvailableZone, true);
88136
this.index = !addresses.isEmpty() ? getRandomIndex() : 0;
89137
}
90138

@@ -170,8 +218,9 @@ private String getAvailableZoneAddress() {
170218
return getCurrentAddress(zoneOrRegionAddress);
171219
}
172220
LOGGER.warn("all auto discovery addresses are isolation, please check server status.");
221+
173222
// when all available address are isolation, it will use config addresses for polling.
174-
return getCurrentAddress(addresses);
223+
return getDefaultAddress();
175224
}
176225

177226
private String getCurrentAddress(List<String> addresses) {
@@ -221,6 +270,11 @@ public void resetFailureStatus(String address) {
221270
addressFailureStatus.put(address, 0);
222271
}
223272

273+
/**
274+
* Only authentication failure, IO, and timeout exception record as failed.
275+
*
276+
* @param address request address
277+
*/
224278
public void recordFailState(String address) {
225279
synchronized (lock) {
226280
if (!addressFailureStatus.containsKey(address)) {
@@ -271,4 +325,41 @@ public List<String> getIsolationAddresses() {
271325
isolationAddresses.addAll(isolationRegionAddress);
272326
return isolationAddresses;
273327
}
328+
329+
public String compareAndGetAddress(String host) {
330+
for (String address : defaultAddress) {
331+
if (isAddressHostSame(address, host)) {
332+
return address;
333+
}
334+
}
335+
return "";
336+
}
337+
338+
private boolean isAddressHostSame(String address, String host) {
339+
if (StringUtils.isEmpty(host)) {
340+
return false;
341+
}
342+
try {
343+
URI uri = new URI(address);
344+
return host.equals(uri.getHost());
345+
} catch (Exception e) {
346+
LOGGER.warn("Exception occurred while constructing URI using the address [{}]", address);
347+
}
348+
return false;
349+
}
350+
351+
private boolean regionAndAZMatch(String ownRegion, String ownAvailableZone, String engineRegion,
352+
String engineAvailableZone) {
353+
return ownRegion.equalsIgnoreCase(engineRegion) && ownAvailableZone.equals(engineAvailableZone);
354+
}
355+
356+
public void refreshAffinityAddress(Set<String> sameZone, Set<String> sameRegion) {
357+
addressAutoRefreshed = true;
358+
if (!sameZone.isEmpty()) {
359+
availableZone.addAll(sameZone);
360+
}
361+
if (!sameRegion.isEmpty()) {
362+
availableRegion.addAll(sameRegion);
363+
}
364+
}
274365
}

0 commit comments

Comments
 (0)