Skip to content

Commit 63f6fde

Browse files
taban03achmelo
andauthored
feat: Service ID prefix replacer (#2229)
* Change service prefix and add unit tests Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Add more tests and fix codesmell Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Add integration test and gh action Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Fix env variable name Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Attempt Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Fix test scope Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Attempt Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Testing Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Fix the hostname service to reach Signed-off-by: at670475 <andrea.tabone@broadcom.com> * attempt Signed-off-by: at670475 <andrea.tabone@broadcom.com> * attempt Signed-off-by: at670475 <andrea.tabone@broadcom.com> * more attempt Signed-off-by: at670475 <andrea.tabone@broadcom.com> * revert and attempt Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Use env variable Signed-off-by: at670475 <andrea.tabone@broadcom.com> * revert Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Fix unit tests Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Add default value Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Increase timeout Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Change to faster test Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Revert Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Reset timeout to 5 minute Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Add unit tests Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Add more tests Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Refactoring Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Fix code smell Signed-off-by: at670475 <andrea.tabone@broadcom.com> * add env variable to be mapped correctly on zowe config Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Add more tests Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Create test tag Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Add tests Signed-off-by: at670475 <andrea.tabone@broadcom.com> * code refactor Signed-off-by: achmelo <a.chmelo@gmail.com> * Fix tests Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Comment the new config Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Change the property name Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Update cancel method to use the new service prefix Signed-off-by: at670475 <andrea.tabone@broadcom.com> * Fix debug message Signed-off-by: at670475 <andrea.tabone@broadcom.com> Co-authored-by: achmelo <a.chmelo@gmail.com>
1 parent 17c4da8 commit 63f6fde

File tree

12 files changed

+596
-8
lines changed

12 files changed

+596
-8
lines changed

.github/workflows/containers.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,3 +1062,47 @@ jobs:
10621062
path: api-catalog-ui/frontend/cypress/screenshots
10631063
- uses: ./.github/actions/teardown
10641064

1065+
CITestsServicePrefixReplacer:
1066+
needs: PublishJibContainers
1067+
container: ubuntu:latest
1068+
runs-on: ubuntu-latest
1069+
timeout-minutes: 15
1070+
1071+
services:
1072+
api-catalog-services:
1073+
image: ghcr.io/balhar-jakub/api-catalog-services:${{ github.event.pull_request.number || 'latest' }}
1074+
volumes:
1075+
- /api-defs:/api-defs
1076+
discoverable-client:
1077+
image: ghcr.io/balhar-jakub/discoverable-client:${{ github.event.pull_request.number || 'latest' }}
1078+
discovery-service:
1079+
image: ghcr.io/balhar-jakub/discovery-service:${{ github.event.pull_request.number || 'latest' }}
1080+
volumes:
1081+
- /api-defs:/api-defs
1082+
env:
1083+
APIML_DISCOVERY_SERVICEIDPREFIXREPLACER: "discoverable,sample"
1084+
gateway-service:
1085+
image: ghcr.io/balhar-jakub/gateway-service:${{ github.event.pull_request.number || 'latest' }}
1086+
mock-services:
1087+
image: ghcr.io/balhar-jakub/mock-services:${{ github.event.pull_request.number || 'latest' }}
1088+
steps:
1089+
- uses: actions/checkout@v2
1090+
with:
1091+
ref: ${{ github.head_ref }}
1092+
1093+
- uses: ./.github/actions/setup
1094+
1095+
- name: Run Service ID Prefix Replacer Tests
1096+
run: >
1097+
./gradlew :integration-tests:runIdPrefixReplacerTests --info -Denvironment.config=-docker -Denvironment.offPlatform=true
1098+
-Partifactory_user=${{ secrets.ARTIFACTORY_USERNAME }} -Partifactory_password=${{ secrets.ARTIFACTORY_PASSWORD }}
1099+
1100+
- name: Store results
1101+
uses: actions/upload-artifact@v2
1102+
if: always()
1103+
with:
1104+
name: CITestsServicePrefixReplacer-${{ env.JOB_ID }}
1105+
path: |
1106+
integration-tests/build/reports/**
1107+
1108+
- uses: ./.github/actions/teardown

build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,11 @@ task runRegistrationTests(dependsOn: [":integration-tests:runRegistrationTests"]
146146
group "Integration tests"
147147
}
148148

149+
task runIdPrefixReplacerTests(dependsOn: [":integration-tests:runIdPrefixReplacerTests"]) {
150+
description "Run Integration Test verifying the service ID prefix replacer mechanism"
151+
group "Integration tests"
152+
}
153+
149154
task runMainFrameTests(dependsOn: ":integration-tests:runMainFrameTests") {
150155
description "Run only tests related to the MainFrame"
151156
group "Integration tests"

config/zowe-api-dev/run-wrapper.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export ZWE_CACHING_SERVICE_PORT=$((basePort+4))
7171
export ZWE_DISCOVERY_SERVICES_LIST=https://$ZOWE_EXPLORER_HOST:$DISCOVERY_PORT/eureka/
7272
export ZWEAD_EXTERNAL_STATIC_DEF_DIRECTORIES=$dir/apidef
7373
export APIML_STATIC_DEF=$ZWEAD_EXTERNAL_STATIC_DEF_DIRECTORIES
74+
#export ZWE_configs_apiml_discovery_serviceIdPrefixReplacer=
7475
echo "******************* ENVIRONMENT *******************"
7576
echo "Working directory "$dir
7677
echo "JAVA_HOME "$JAVA_HOME

discovery-package/src/main/resources/bin/start.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
# - ZWE_haInstance_hostname
3939
# - ZWE_zowe_certificate_keystore_type - The default keystore type to use for SSL certificates
4040
# - ZWE_zowe_verifyCertificates - if we accept only verified certificates
41+
# - ZWE_configs_apiml_discovery_serviceIdPrefixReplacer - The service ID prefix replacer to be V2 conformant
4142
if [ ${LAUNCH_COMPONENT} ]
4243
then
4344
JAR_FILE="${LAUNCH_COMPONENT}/discovery-service-lite.jar"
@@ -136,6 +137,7 @@ _BPX_JOBNAME=${ZWE_zowe_job_prefix}${DISCOVERY_CODE} java -Xms32m -Xmx256m ${QUI
136137
-Dapiml.service.hostname=${ZWE_haInstance_hostname:-localhost} \
137138
-Dapiml.service.port=${ZWE_configs_port:-7553} \
138139
-Dapiml.discovery.staticApiDefinitionsDirectories=${ZWE_STATIC_DEFINITIONS_DIR} \
140+
-Dapiml.discovery.serviceIdPrefixReplacer=${ZWE_configs_apiml_discovery_serviceIdPrefixReplacer} \
139141
-Dapiml.security.ssl.verifySslCertificatesOfServices=${verifySslCertificatesOfServices:-false} \
140142
-Dapiml.security.ssl.nonStrictVerifySslCertificatesOfServices=${nonStrictVerifySslCertificatesOfServices:-false} \
141143
-Dserver.ssl.enabled=${ZWE_components_gateway_server_ssl_enabled:-true} \

discovery-package/src/main/resources/manifest.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,10 @@ apimlServices:
2929
static:
3030
- file: zosmf-static-definition.yaml.template
3131
configs:
32+
# server.prefix.replacer is used to replace service ID prefix non-conformant with v2.
33+
# Define ZWE_configs_apiml_discovery_serviceIdPrefixReplacer in the Zowe config if you want to use it
34+
# apiml:
35+
# discovery:
36+
# serviceIdPrefixReplacer: ""
3237
port: 7553
3338
debug: false

discovery-service/src/main/java/org/zowe/apiml/discovery/ApimlInstanceRegistry.java

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
import com.netflix.eureka.registry.AbstractInstanceRegistry;
1717
import com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl;
1818
import com.netflix.eureka.resources.ServerCodecs;
19+
import lombok.extern.slf4j.Slf4j;
1920
import org.springframework.cloud.netflix.eureka.server.InstanceRegistry;
2021
import org.springframework.cloud.netflix.eureka.server.InstanceRegistryProperties;
2122
import org.springframework.context.ApplicationContext;
23+
import org.zowe.apiml.discovery.config.EurekaConfig;
2224

2325
import java.lang.invoke.MethodHandle;
2426
import java.lang.invoke.MethodHandles;
@@ -37,6 +39,7 @@
3739
* #2659 Race condition with registration events in Eureka server
3840
* https://github.com/spring-cloud/spring-cloud-netflix/issues/2659
3941
*/
42+
@Slf4j
4043
public class ApimlInstanceRegistry extends InstanceRegistry {
4144

4245
private static final String EXCEPTION_MESSAGE = "Implementation of InstanceRegistry changed, please verify fix of order sending events";
@@ -49,21 +52,25 @@ public class ApimlInstanceRegistry extends InstanceRegistry {
4952
private MethodHandle register3ArgsMethodHandle;
5053
private MethodHandle cancelMethodHandle;
5154

52-
private ApplicationContext appCntx;
55+
private final ApplicationContext appCntx;
56+
private final EurekaConfig.Tuple tuple;
5357

5458
public ApimlInstanceRegistry(
5559
EurekaServerConfig serverConfig,
5660
EurekaClientConfig clientConfig,
5761
ServerCodecs serverCodecs,
5862
EurekaClient eurekaClient,
5963
InstanceRegistryProperties instanceRegistryProperties,
60-
ApplicationContext appCntx
64+
ApplicationContext appCntx,
65+
EurekaConfig.Tuple tuple
6166
) {
67+
6268
super(serverConfig, clientConfig, serverCodecs, eurekaClient,
6369
instanceRegistryProperties.getExpectedNumberOfClientsSendingRenews(),
6470
instanceRegistryProperties.getDefaultOpenForTrafficCount()
6571
);
6672
this.appCntx = appCntx;
73+
this.tuple = tuple;
6774
init();
6875
}
6976

@@ -143,6 +150,7 @@ protected int resolveInstanceLeaseDurationRewritten(final InstanceInfo info) {
143150

144151
@Override
145152
public void register(InstanceInfo info, int leaseDuration, boolean isReplication) {
153+
info = changeServiceId(info);
146154
try {
147155
register3ArgsMethodHandle.invokeWithArguments(this, info, leaseDuration, isReplication);
148156
handleRegistrationMethod.invokeWithArguments(this, info, leaseDuration, isReplication);
@@ -156,7 +164,8 @@ public void register(InstanceInfo info, int leaseDuration, boolean isReplication
156164
}
157165

158166
@Override
159-
public void register(final InstanceInfo info, final boolean isReplication) {
167+
public void register(InstanceInfo info, final boolean isReplication) {
168+
info = changeServiceId(info);
160169
try {
161170
register2ArgsMethodHandle.invokeWithArguments(this, info, isReplication);
162171
handleRegistrationMethod.invokeWithArguments(this, info, resolveInstanceLeaseDurationRewritten(info), isReplication);
@@ -172,8 +181,9 @@ public void register(final InstanceInfo info, final boolean isReplication) {
172181
@Override
173182
public boolean cancel(String appName, String serverId, boolean isReplication) {
174183
try {
175-
final boolean out = (boolean) cancelMethodHandle.invokeWithArguments(this, appName, serverId, isReplication);
176-
handleCancelationMethod.invokeWithArguments(this, appName, serverId, isReplication);
184+
String[] updatedValues = replaceValues(appName, serverId);
185+
final boolean out = (boolean) cancelMethodHandle.invokeWithArguments(this, updatedValues[0], updatedValues[1], isReplication);
186+
handleCancelationMethod.invokeWithArguments(this, updatedValues[0], updatedValues[1], isReplication);
177187
return out;
178188
} catch (ClassCastException | WrongMethodTypeException e) {
179189
throw new IllegalArgumentException(EXCEPTION_MESSAGE, e);
@@ -184,10 +194,53 @@ public boolean cancel(String appName, String serverId, boolean isReplication) {
184194
}
185195
}
186196

197+
@Override
198+
public boolean renew(String appName, String serverId, boolean isReplication) {
199+
String[] updatedValues = replaceValues(appName, serverId);
200+
return super.renew(updatedValues[0], updatedValues[1], isReplication);
201+
}
202+
187203
@Override
188204
public boolean statusUpdate(String appName, String instanceId, InstanceInfo.InstanceStatus newStatus, String lastDirtyTimestamp, boolean isReplication) {
189-
boolean isUpdated = super.statusUpdate(appName, instanceId, newStatus, lastDirtyTimestamp, isReplication);
205+
String[] updatedValues = replaceValues(appName,instanceId);
206+
boolean isUpdated = super.statusUpdate(updatedValues[0], updatedValues[1], newStatus, lastDirtyTimestamp, isReplication);
190207
this.appCntx.publishEvent(new EurekaStatusUpdateEvent(this, appName, instanceId));
191208
return isUpdated;
192209
}
210+
211+
private String[] replaceValues(String appName, String instanceId) {
212+
if (tuple.isValid()) {
213+
String servicePrefix = tuple.getOldPrefix();
214+
String targetValue = tuple.getNewPrefix();
215+
appName = appName.replace(servicePrefix.toUpperCase(), targetValue.toUpperCase());
216+
instanceId = instanceId.replace(servicePrefix, targetValue);
217+
}
218+
return new String[]{appName,instanceId};
219+
}
220+
221+
/**
222+
* Change the service ID prefix according to the mapper before the service registers to Eureka.
223+
* @param info the instance info
224+
* @return instance info with the modified service ID
225+
*/
226+
protected InstanceInfo changeServiceId(final InstanceInfo info) {
227+
if (tuple.isValid()) {
228+
String servicePrefix = tuple.getOldPrefix();
229+
String instanceId = info.getInstanceId();
230+
if (instanceId.contains(servicePrefix)) {
231+
String appName = info.getAppName();
232+
String[] updatedValues = replaceValues(appName,instanceId);
233+
log.debug("The instance ID of {} service has been changed to {}.", info.getAppName(), updatedValues[1]);
234+
return new InstanceInfo.Builder(info)
235+
.setInstanceId(updatedValues[1])
236+
.setAppGroupName(updatedValues[0])
237+
.setAppName(updatedValues[0])
238+
.setVIPAddress(updatedValues[0])
239+
.build();
240+
}
241+
return info;
242+
}
243+
return info;
244+
}
245+
193246
}

discovery-service/src/main/java/org/zowe/apiml/discovery/config/EurekaConfig.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
*/
1010
package org.zowe.apiml.discovery.config;
1111

12+
import org.apache.commons.lang3.StringUtils;
13+
import org.springframework.beans.factory.annotation.Value;
1214
import org.springframework.context.ApplicationContext;
1315
import org.zowe.apiml.discovery.ApimlInstanceRegistry;
1416
import com.netflix.discovery.EurekaClient;
@@ -26,6 +28,9 @@
2628
@Configuration
2729
public class EurekaConfig {
2830

31+
@Value("${apiml.discovery.serviceIdPrefixReplacer:#{null}}")
32+
private String tuple;
33+
2934
@Bean
3035
@Primary
3136
public ApimlInstanceRegistry getApimlInstanceRegistry(
@@ -37,7 +42,47 @@ public ApimlInstanceRegistry getApimlInstanceRegistry(
3742
ApplicationContext appCntx)
3843
{
3944
eurekaClient.getApplications(); // force initialization
40-
return new ApimlInstanceRegistry(serverConfig, clientConfig, serverCodecs, eurekaClient, instanceRegistryProperties,appCntx);
45+
return new ApimlInstanceRegistry(serverConfig, clientConfig, serverCodecs, eurekaClient, instanceRegistryProperties,appCntx, new Tuple(tuple));
46+
}
47+
48+
public static class Tuple {
49+
50+
boolean valid;
51+
String oldPrefix;
52+
String newPrefix;
53+
54+
public Tuple(String tuple) {
55+
if (isValidTuple(tuple)) {
56+
String[] prefixes = tuple.split(",");
57+
this.oldPrefix = prefixes[0];
58+
this.newPrefix = prefixes[1];
59+
this.valid = true;
60+
}
61+
}
62+
63+
public boolean isValid() {
64+
return valid;
65+
}
66+
67+
public String getOldPrefix() {
68+
return oldPrefix;
69+
}
70+
71+
public String getNewPrefix() {
72+
return newPrefix;
73+
}
74+
75+
public static boolean isValidTuple(String tuple) {
76+
if (StringUtils.isNotEmpty(tuple)) {
77+
String[] replacer = tuple.split(",");
78+
return replacer.length > 1 &&
79+
StringUtils.isNotEmpty(replacer[0]) &&
80+
StringUtils.isNotEmpty(replacer[1]) &&
81+
!replacer[0].equals(replacer[1]);
82+
}
83+
return false;
84+
}
85+
4186
}
4287

4388
}

0 commit comments

Comments
 (0)