Skip to content

Commit 9b7f8e6

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

File tree

32 files changed

+402
-183
lines changed

32 files changed

+402
-183
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, EventBus eventBus, String region,
32+
String availableZone) {
33+
super(projectName, addresses, region, availableZone);
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, EventBus eventBus, String region, String availableZone) {
31+
super(addresses, region, availableZone);
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, EventBus eventBus, String region, String availableZone) {
33+
super(addresses, region, availableZone);
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
@@ -39,7 +39,7 @@ class AddressManagerTest {
3939
public void kieAddressManagerTest() throws IllegalAccessException, NoSuchFieldException {
4040
addresses.add("http://127.0.0.1:30103");
4141
addresses.add("https://127.0.0.2:30103");
42-
addressManager1 = new DashboardAddressManager(addresses, new EventBus());
42+
addressManager1 = new DashboardAddressManager(addresses, new EventBus(), "", "");
4343
Field addressManagerField = addressManager1.getClass().getSuperclass().getDeclaredField("index");
4444
addressManagerField.setAccessible(true);
4545
addressManagerField.set(addressManager1, 0);
@@ -63,7 +63,7 @@ public void onRefreshEndpointEvent() {
6363
Map<String, List<String>> zoneAndRegion = new HashMap<>();
6464
zoneAndRegion.put("sameZone", addressAZ);
6565
zoneAndRegion.put("sameRegion", addressRG);
66-
addressManager1 = new DashboardAddressManager(addresses, new EventBus());
66+
addressManager1 = new DashboardAddressManager(addresses, new EventBus(), "", "");
6767
RefreshEndpointEvent event = new RefreshEndpointEvent(zoneAndRegion, "CseMonitoring");
6868
addressManager1.refreshEndpoint(event, "CseMonitoring");
6969

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

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
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;
@@ -29,6 +30,7 @@
2930
import org.apache.servicecomb.http.client.event.RefreshEndpointEvent;
3031
import org.slf4j.Logger;
3132
import org.slf4j.LoggerFactory;
33+
import org.springframework.util.CollectionUtils;
3234

3335
import com.google.common.annotations.VisibleForTesting;
3436
import com.google.common.eventbus.EventBus;
@@ -42,6 +44,10 @@ public class AbstractAddressManager {
4244

4345
private static final String V3_PREFIX = "/v3/";
4446

47+
private static final String ZONE = "availableZone";
48+
49+
private static final String REGION = "region";
50+
4551
private static final int ISOLATION_THRESHOLD = 3;
4652

4753
private volatile List<String> addresses = new ArrayList<>();
@@ -74,17 +80,63 @@ public class AbstractAddressManager {
7480

7581
private EventBus eventBus;
7682

77-
public AbstractAddressManager(List<String> addresses) {
83+
public AbstractAddressManager(List<String> addresses, String ownRegion, String ownAvailableZone) {
7884
this.projectName = DEFAULT_PROJECT;
79-
this.addresses.addAll(addresses);
80-
this.defaultAddress.addAll(addresses);
85+
parseAndInitAddresses(addresses, ownRegion, ownAvailableZone, false);
8186
this.index = !addresses.isEmpty() ? getRandomIndex() : 0;
8287
}
8388

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

@@ -271,4 +323,26 @@ public List<String> getIsolationAddresses() {
271323
isolationAddresses.addAll(isolationRegionAddress);
272324
return isolationAddresses;
273325
}
326+
327+
public String compareAndGetAddress(String host) {
328+
for (String address : defaultAddress) {
329+
if (isAddressHostSame(address, host)) {
330+
return address;
331+
}
332+
}
333+
return "";
334+
}
335+
336+
private boolean isAddressHostSame(String address, String host) {
337+
if (StringUtils.isEmpty(host)) {
338+
return false;
339+
}
340+
try {
341+
URI uri = new URI(address);
342+
return host.equals(uri.getHost());
343+
} catch (Exception e) {
344+
LOGGER.warn("Exception occurred while constructing URI using the address [{}]", address);
345+
}
346+
return false;
347+
}
274348
}

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,21 @@
1818
package org.apache.servicecomb.http.client.common;
1919

2020
import java.io.IOException;
21+
import java.net.URI;
2122
import java.util.Map;
2223

2324
import org.apache.http.client.HttpClient;
2425
import org.apache.http.util.EntityUtils;
2526
import org.apache.servicecomb.foundation.auth.SignRequest;
2627
import org.apache.servicecomb.http.client.auth.RequestAuthHeaderProvider;
28+
import org.slf4j.Logger;
29+
import org.slf4j.LoggerFactory;
2730

2831
/**
2932
* Created by on 2019/10/16.
3033
*/
3134
public class HttpTransportImpl implements HttpTransport {
35+
private static final Logger LOGGER = LoggerFactory.getLogger(HttpTransportImpl.class);
3236

3337
private static final String HEADER_CONTENT_TYPE = "Content-Type";
3438

@@ -87,7 +91,7 @@ public HttpResponse doRequest(HttpRequest httpRequest) throws IOException {
8791
globalHeaders.forEach(httpRequest::addHeader);
8892
}
8993

90-
httpRequest.getHeaders().putAll(requestAuthHeaderProvider.loadAuthHeader(createSignRequest()));
94+
httpRequest.getHeaders().putAll(requestAuthHeaderProvider.loadAuthHeader(createSignRequest(httpRequest.getUrl())));
9195

9296
//get Http response
9397
org.apache.http.HttpResponse response = httpClient.execute(httpRequest.getRealRequest());
@@ -98,9 +102,16 @@ public HttpResponse doRequest(HttpRequest httpRequest) throws IOException {
98102
response.getAllHeaders());
99103
}
100104

101-
private static SignRequest createSignRequest() {
102-
// Now the implementations do not process SignRequest, so return null. Maybe future will use it.
103-
return null;
105+
private static SignRequest createSignRequest(String url) {
106+
try {
107+
URI uri = URI.create(url);
108+
SignRequest signRequest = new SignRequest();
109+
signRequest.setEndpoint(uri);
110+
return signRequest;
111+
} catch (Exception e) {
112+
LOGGER.error("create signRequest failed!", e);
113+
return null;
114+
}
104115
}
105116

106117
@Override

0 commit comments

Comments
 (0)