Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
2f2d444
exposing eurekaversion endpoint
pavel-jares-bcm Jan 7, 2026
19fac57
checking of eureka version on all instances
pavel-jares-bcm Jan 8, 2026
a4469d0
add missing catalog check
pavel-jares-bcm Jan 8, 2026
badd484
modulith support for eurekaversion endpoint
pavel-jares-bcm Jan 8, 2026
62eff42
Merge branch 'v3.x.x' into reboot/complex-start-up-check
pavel-jares-bcm Jan 22, 2026
1415af2
ignore configuration when instance is not configured
pavel-jares-bcm Jan 22, 2026
ec76467
fix modulith
pavel-jares-bcm Jan 22, 2026
9149a40
fix init eureka version
pavel-jares-bcm Jan 22, 2026
20786a3
Merge branch 'v3.x.x' into reboot/complex-start-up-check
pavel-jares-bcm Jan 26, 2026
00e740b
eureka fixes
pavel-jares-bcm Jan 26, 2026
9ed4547
log update
pavel-jares-bcm Jan 26, 2026
2113901
fix usage of additionalHost on DS config
pavel-jares-bcm Jan 26, 2026
1d9c944
instead of taking any version from DS wait till DS are in sync and th…
pavel-jares-bcm Jan 26, 2026
9fae271
fix HA - missing API Catalog instance
pavel-jares-bcm Jan 26, 2026
3a36879
increase timeouts
pavel-jares-bcm Jan 26, 2026
a2f8d9e
cosmetic changes
pavel-jares-bcm Jan 26, 2026
f0836e6
minor changes
pavel-jares-bcm Jan 27, 2026
6cff407
Merge branch 'v3.x.x' into reboot/complex-start-up-check
pavel-jares-bcm Jan 27, 2026
5e7da10
same replica timeout on DS and apiml
pavel-jares-bcm Jan 27, 2026
d43feb7
split per APIML instances
pavel-jares-bcm Jan 27, 2026
a1a4aaa
Merge branch 'v3.x.x' into reboot/complex-start-up-check
pavel-jares-bcm Jan 27, 2026
a2967bf
fix
pavel-jares-bcm Jan 27, 2026
15e45fa
refactor old start-up checks
pavel-jares-bcm Jan 27, 2026
c295629
Merge branch 'v3.x.x' into reboot/complex-start-up-check
pavel-jares-bcm Jan 27, 2026
6b5b1d6
small refactoring + fix
pavel-jares-bcm Jan 27, 2026
6eeda7c
fix from #4251
pavel-jares-bcm Jan 27, 2026
5e74649
minor fix (priority to use BeanDefinitionRegistryPostProcessor)
pavel-jares-bcm Jan 27, 2026
1684dde
fix auth issue (discoverable client)
pavel-jares-bcm Jan 27, 2026
a5defd4
fixes
pavel-jares-bcm Jan 27, 2026
d98fe73
fixes
pavel-jares-bcm Jan 27, 2026
54ce71e
fixes
pavel-jares-bcm Jan 28, 2026
96272fb
fix static registration
pavel-jares-bcm Jan 28, 2026
237eb28
fix Central vs. domain apiml instance
pavel-jares-bcm Jan 28, 2026
9c1225b
fix non-immutable list
pavel-jares-bcm Jan 28, 2026
6a13138
fixes
pavel-jares-bcm Jan 28, 2026
fc900d7
fixes
pavel-jares-bcm Jan 28, 2026
6f07339
remove timeouts for start-up checker
pavel-jares-bcm Jan 28, 2026
92c51f2
set new timeouts in start-up checker
pavel-jares-bcm Jan 28, 2026
df3bb97
fixes
pavel-jares-bcm Jan 28, 2026
9a91406
increase timeouts
pavel-jares-bcm Jan 28, 2026
e3165c5
fixes
pavel-jares-bcm Jan 28, 2026
0b1e59f
fix
nxhafa Jan 28, 2026
3ea23c2
improvement (no fix)
nxhafa Jan 28, 2026
d4aa8be
fix (revert of JSON path)
pavel-jares-bcm Jan 28, 2026
ff8bddf
removing unnecessary peerAwareInstanceRegistry bean override from mod…
nxhafa Jan 28, 2026
0f15508
renaming method
nxhafa Jan 28, 2026
665643f
attempt to call syncUp on the DS start-up
pavel-jares-bcm Jan 28, 2026
39c14f4
a new way to construct a list of instances for specific check
pavel-jares-bcm Jan 28, 2026
0cf6883
fixes
pavel-jares-bcm Jan 29, 2026
7c6f343
fix discovery instanceId
pavel-jares-bcm Jan 29, 2026
4e7ad9d
fix apiml checkstyle
pavel-jares-bcm Jan 29, 2026
5338d15
log message improvement
pavel-jares-bcm Jan 29, 2026
c3e7a2a
log messages
pavel-jares-bcm Jan 29, 2026
12d5d1c
use hashcode instead of deltaVersion
pavel-jares-bcm Jan 29, 2026
6bbabcd
static registration after Eureka is initialized
pavel-jares-bcm Jan 29, 2026
6c46836
Merge branch 'v3.x.x' into reboot/complex-start-up-check
pavel-jares-bcm Jan 29, 2026
62c914a
fixes
pavel-jares-bcm Jan 29, 2026
8f81977
attempt to postpone static registration
pavel-jares-bcm Jan 29, 2026
86f65c2
adding logs
nxhafa Jan 29, 2026
2596546
adding startup check in missing integration test runs
nxhafa Jan 30, 2026
90e6198
Merge branch 'v3.x.x' into reboot/complex-start-up-check
nxhafa Jan 30, 2026
c648321
Merge branch 'v3.x.x' into reboot/complex-start-up-check
pavel-jares-bcm Feb 2, 2026
592bcd5
fix DS list
pavel-jares-bcm Feb 2, 2026
43de764
fix config CITestsModulithWithInfinispan
pavel-jares-bcm Feb 2, 2026
cd4ef2f
fix caching service health checker when other storage than infinispan
pavel-jares-bcm Feb 2, 2026
fadd85a
fixes
pavel-jares-bcm Feb 2, 2026
c1c30d1
fixes
pavel-jares-bcm Feb 2, 2026
9f84ed1
Merge branch 'v3.x.x' into reboot/complex-start-up-check
pavel-jares-bcm Feb 2, 2026
a7200a9
fixes
pavel-jares-bcm Feb 2, 2026
83a65bf
fix
pavel-jares-bcm Feb 2, 2026
2cc2f16
fix invalid format exception
pavel-jares-bcm Feb 2, 2026
98c1fbe
fix count of discoverable clients in Python workflow
pavel-jares-bcm Feb 2, 2026
522dd8d
log for mock services on Redis IT
pavel-jares-bcm Feb 3, 2026
f8d0104
health endpoint independent of cachemanager initialization
pavel-jares-bcm Feb 3, 2026
b81e9e6
attempt to increase time for Redis tests
pavel-jares-bcm Feb 3, 2026
80b261b
fix redis startup (start-up checker replacement)
pavel-jares-bcm Feb 3, 2026
c7476d7
attempt to fix default cache - error on start-up
pavel-jares-bcm Feb 3, 2026
6ecbbe1
remove always on start up check - previous error is enough
pavel-jares-bcm Feb 3, 2026
2c983d0
attempt to fix cache definition
pavel-jares-bcm Feb 3, 2026
bbeb497
fix config for start-up checker on Redis tasks
pavel-jares-bcm Feb 3, 2026
b84032c
fix certs for Redis
pavel-jares-bcm Feb 3, 2026
32992d5
make caching endpoint independent on initialization (see autoconfig o…
pavel-jares-bcm Feb 3, 2026
eec8304
increase timeout for Redis
pavel-jares-bcm Feb 3, 2026
b24ef47
remove defineConfiguration
pavel-jares-bcm Feb 3, 2026
4e820eb
fix redis (cache init)
pavel-jares-bcm Feb 3, 2026
8853b62
Merge branch 'v3.x.x' into reboot/complex-start-up-check
pavel-jares-bcm Feb 3, 2026
4d8268f
disable AuthenticateApar
pavel-jares-bcm Feb 3, 2026
f6b50d2
add log message to check why Gateway replica could be forgotten
pavel-jares-bcm Feb 4, 2026
7d72b04
remove unuseful comment
pavel-jares-bcm Feb 4, 2026
71518e2
lazy cache manage (to avoid failing during the start-up)
pavel-jares-bcm Feb 4, 2026
4083fcb
fix infinispan init
pavel-jares-bcm Feb 4, 2026
e40b943
fix cacheManager beans duplicity
pavel-jares-bcm Feb 4, 2026
c0af80e
fix service ID for logback (second and third instances)
pavel-jares-bcm Feb 4, 2026
c3b933c
caching service using cluster to evaluate state
pavel-jares-bcm Feb 4, 2026
6e0a65a
lazy usage of caches in infinity storage
pavel-jares-bcm Feb 4, 2026
66505f0
lazy init
pavel-jares-bcm Feb 6, 2026
9322033
fix DC count
pavel-jares-bcm Feb 6, 2026
1dd970c
improve health endpoint on cs
pavel-jares-bcm Feb 6, 2026
2c92ee4
fix unmodified list
pavel-jares-bcm Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 0 additions & 83 deletions .github/actions/validate-apiml-healthy/action.yml

This file was deleted.

434 changes: 349 additions & 85 deletions .github/workflows/integration-tests.yml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
@ComponentScan(value = {
"org.zowe.apiml.apicatalog",
"org.zowe.apiml.product.compatibility",
"org.zowe.apiml.product.eureka.web",
"org.zowe.apiml.product.security",
"org.zowe.apiml.product.web",
"org.zowe.apiml.product.gateway",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp
* @return processor to create new customizer beans or an empty processor if there are no additional address.
*/
@Bean
public BeanDefinitionRegistryPostProcessor registerAdditionalTomcatConnectors() {
public static BeanDefinitionRegistryPostProcessor registerAdditionalTomcatConnectors() {
if (ADDITIONAL_NETWORKS.isEmpty()) {
return registry -> {};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,9 @@ public ProcessingResult process(List<ReplicationTask> tasks) {
logNetworkErrorSample(null, "; retrying after delay.", e);
return ProcessingResult.TransientError;
} else {
log.warn("Cannot replicate to another DS instance: {}", e.getMessage());
logNetworkErrorSample(null, "; not re-trying this exception because it does not seem to be a network exception.", e);
return ProcessingResult.PermanentError;
return ProcessingResult.TransientError;
}
}
return ProcessingResult.Success;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*/

package org.zowe.apiml.product.eureka.web;

import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.EurekaEvent;
import jakarta.annotation.PostConstruct;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import java.util.regex.Pattern;

import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;

@Component
@RequiredArgsConstructor
@Endpoint(id = "eurekaversion")
@ConditionalOnMissingBean(name = "modulithConfig")
@Slf4j
public class EurekaRegistryVersionEndpoint {

private static final Pattern VERSION_PATTERN = Pattern.compile("^.*_([0-9]+)_.*$");

private Long version = -1L;

private final EurekaClient eurekaClient;

@PostConstruct
void registerListener() {
eurekaClient.registerEventListener(event -> {
onRegistryUpdate(event);
});
}

@EventListener
void onRegistryUpdate(EurekaEvent event) {
var hashCode = eurekaClient.getApplications().getAppsHashCode();
var matcher = VERSION_PATTERN.matcher(hashCode);
if (matcher.matches()) {
version = Long.parseLong(matcher.group(1));
log.debug("New Eureka registry version: {}", this.version);
} else {
log.debug("Unexpected Eureka registry hashCode: {}", hashCode);
}
}

@ReadOperation(produces = APPLICATION_JSON)
public VersionDto status() {
return VersionDto.builder().version(this.version).build();
}

@Builder
@Value
static class VersionDto {

private Long version;

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ private <E extends Exception> Map.Entry<Class<E>, ExceptionHandler<E>> entry(Cla
entry(WebClientResponseException.BadRequest.class,
(ex, ctx) -> handleBadRequest(ctx.requestUri, ctx.function, ex, "org.zowe.apiml.security.login.invalidInput")),
entry(AccessDeniedException.class,
(ex, ctx) -> handleForbidden(ctx.function, ex)
(ex, ctx) -> handleForbidden(ctx.requestUri, ctx.function, ex)
),
entry(GatewayNotAvailableException.class,
(ex, ctx) -> handleGatewayNotAvailable(ctx.function, ex, ctx.requestUri)
Expand Down Expand Up @@ -270,9 +270,9 @@ private void handleRuntimeException(String uri, BiConsumer<ApiMessageView, HttpS
writeErrorResponse("org.zowe.apiml.common.internalRequestError", HttpStatus.INTERNAL_SERVER_ERROR, function, uri, ExceptionUtils.getMessage(ex), ExceptionUtils.getRootCauseMessage(ex));
}

private void handleForbidden(BiConsumer<ApiMessageView, HttpStatus> function, AccessDeniedException ex) {
private void handleForbidden(String uri, BiConsumer<ApiMessageView, HttpStatus> function, AccessDeniedException ex) {
log.debug(MESSAGE_FORMAT, HttpStatus.FORBIDDEN.value(), ex.getMessage());
writeErrorResponse("org.zowe.apiml.security.forbidden", HttpStatus.FORBIDDEN, function);
writeErrorResponse("org.zowe.apiml.security.forbidden", HttpStatus.FORBIDDEN, function, uri);
}

private void handleGatewayNotAvailable(BiConsumer<ApiMessageView, HttpStatus> function, GatewayNotAvailableException ex, String uri) {
Expand Down
1 change: 1 addition & 0 deletions apiml/src/main/java/org/zowe/apiml/ApimlApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
scanBasePackages = {
"org.zowe.apiml.filter",
"org.zowe.apiml.gateway",
"org.zowe.apiml.product.eureka.web",
"org.zowe.apiml.product.web",
"org.zowe.apiml.product.gateway",
"org.zowe.apiml.product.version",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*/

package org.zowe.apiml;

import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.stereotype.Component;

import java.util.regex.Pattern;

import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;

@Component
@RequiredArgsConstructor
@Endpoint(id = "eurekaversion")
@Slf4j
public class ApimlEurekaRegistryVersionEndpoint {

private static final Pattern VERSION_PATTERN = Pattern.compile("^.*_([0-9]+)_.*$");

private final PeerAwareInstanceRegistry peerAwareInstanceRegistry;

@ReadOperation(produces = APPLICATION_JSON)
public VersionDto status() {
long version = -1;
var hashCode = peerAwareInstanceRegistry.getApplications().getAppsHashCode();
var matcher = VERSION_PATTERN.matcher(hashCode);
if (matcher.matches()) {
version = Long.parseLong(matcher.group(1));
log.debug("New Eureka registry version: {}", version);
} else {
log.debug("Unexpected Eureka registry hashCode: {}", hashCode);
}
return VersionDto.builder().version(version).build();
}

@Builder
@Value
static class VersionDto {

private Long version;

}


}
29 changes: 0 additions & 29 deletions apiml/src/main/java/org/zowe/apiml/EurekaConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.client.actuator.HasFeatures;
import org.springframework.cloud.netflix.eureka.EurekaConstants;
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
import org.springframework.cloud.netflix.eureka.server.*;
import org.springframework.context.annotation.*;
import org.springframework.core.Ordered;
Expand All @@ -88,8 +87,6 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Pattern;

/**
Expand Down Expand Up @@ -208,32 +205,6 @@ PeerReplicationResource peerReplicationResource() {
return new PeerReplicationResource();
}

@Bean
PeerAwareInstanceRegistry peerAwareInstanceRegistry(ServerCodecs serverCodecs,
EurekaServerHttpClientFactory eurekaServerHttpClientFactory,
EurekaInstanceConfigBean eurekaInstanceConfigBean) {
if (eurekaInstanceConfigBean.isAsyncClientInitialization()) {
if (log.isDebugEnabled()) {
log.debug("Initializing client asynchronously...");
}

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(() -> {
this.eurekaClient.getApplications();
if (log.isDebugEnabled()) {
log.debug("Asynchronous client initialization done.");
}
});
} else {
this.eurekaClient.getApplications(); // force initialization
}

return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.eurekaClient,
eurekaServerHttpClientFactory,
this.instanceRegistryProperties.getExpectedNumberOfClientsSendingRenews(),
this.instanceRegistryProperties.getDefaultOpenForTrafficCount());
}

@Bean
@ConditionalOnMissingBean
EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs, PeerAwareInstanceRegistry registry,
Expand Down
65 changes: 65 additions & 0 deletions apiml/src/main/java/org/zowe/apiml/EurekaHealthIndicatorApiml.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*/

package org.zowe.apiml;

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.eureka.EurekaHealthIndicator;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.stream.Collectors;

/**
* This class is replacement of org.springframework.cloud.netflix.eureka.EurekaHealthIndicator, because it is using
* a different Eureka client
*/
@Primary
@Component("eurekaHealthIndicator")
public class EurekaHealthIndicatorApiml extends EurekaHealthIndicator {

private final DiscoveryClient discoveryClient;

public EurekaHealthIndicatorApiml(DiscoveryClient discoveryClient) {
super(null, null, null);
this.discoveryClient = discoveryClient;
}

@Override
public String getName() {
return "eureka";
}

@Override
public Health health() {
Health.Builder builder = Health.unknown();
Status status = getStatus(builder);
return builder.status(status).withDetail("applications", getApplications()).build();
}

private Status getStatus(Health.Builder builder) {
if (discoveryClient.getServices().isEmpty()) {
return new Status("UP", "Eureka registry is not available at the moment");
}
return new Status("UP", "Eureka is ready to use");
}

private Map<String, Object> getApplications() {
return discoveryClient.getServices().stream()
.collect(Collectors.toMap(
String::toLowerCase,
serviceId -> discoveryClient.getInstances(serviceId).size())
);
}

}
Loading
Loading