Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
a50094e
fix not to stop caching service during the start-up because of a conn…
pavel-jares-bcm Nov 28, 2025
f5c7e72
Merge branch 'v2.x.x' into reboot/caching-error-on-lock
pavel-jares-bcm Nov 28, 2025
ead581b
code review
pavel-jares-bcm Nov 28, 2025
312ffff
test fixes
pavel-jares-bcm Nov 28, 2025
8ddf6b2
Merge remote-tracking branch 'origin/reboot/caching-error-on-lock' in…
pavel-jares-bcm Nov 28, 2025
36215b2
cherry-pick of fix "Use HA instance ID in path to infinispan storage …
pavel-jares-bcm Jan 29, 2025
6517fd5
cherry-pick of fix "disable infinispan diagnostics by default" #4157
pavel-jares-bcm Dec 1, 2025
6d43525
fix Eureka period to 30s from 1s
pavel-jares-bcm Dec 3, 2025
19aef22
add debug message about salt issue
pavel-jares-bcm Dec 3, 2025
e1a967b
fix: Fix detection of connection issue (#4142)
pavel-jares-bcm Jun 2, 2025
4c03732
compilation fix
pavel-jares-bcm Dec 3, 2025
d0c4b71
migration step of infinispan storage location
pavel-jares-bcm Dec 3, 2025
a70aa09
lazy init of lock
pavel-jares-bcm Dec 3, 2025
59a43ac
add debug messages
pavel-jares-bcm Dec 3, 2025
e57b648
stop caching of salt on Gateway side
pavel-jares-bcm Dec 3, 2025
032f3bc
fix infinispan diag configuration
pavel-jares-bcm Jan 29, 2025
7ac792d
Merge remote-tracking branch 'refs/remotes/origin/detached3' into reb…
pavel-jares-bcm Dec 3, 2025
903c873
infinispan config improvements
pavel-jares-bcm Dec 8, 2025
2d10631
fix handling response from caching service by gateway (see no record …
pavel-jares-bcm Dec 8, 2025
a91e11d
Merge remote-tracking branch 'refs/remotes/origin/detached4' into reb…
pavel-jares-bcm Dec 8, 2025
2c3dd63
draft of IT of distributed cache
pavel-jares-bcm Dec 8, 2025
2bf3b87
clean-up
pavel-jares-bcm Dec 9, 2025
364d1b7
optimized usage of salt
pavel-jares-bcm Dec 9, 2025
8c3a3e4
fixes
pavel-jares-bcm Nov 19, 2025
915c12d
extend for server address (internal vs. external)
pavel-jares-bcm Nov 20, 2025
8a07f22
Fix handling of unsupported caching service mode
pavel-jares-bcm Dec 9, 2025
1d6ba32
fix org.infinispan.commons.marshall.MarshallingException: java.lang.N…
pavel-jares-bcm Dec 9, 2025
8fd4748
Merge remote-tracking branch 'refs/remotes/origin/detached7' into reb…
pavel-jares-bcm Dec 9, 2025
9636c9b
fix tests
pavel-jares-bcm Dec 9, 2025
4339cb5
Merge remote-tracking branch 'refs/remotes/origin/detached8' into reb…
pavel-jares-bcm Dec 9, 2025
3942b4b
remove dependency IT > caching service
pavel-jares-bcm Dec 9, 2025
be17120
Merge remote-tracking branch 'refs/remotes/origin/detached9' into reb…
pavel-jares-bcm Dec 9, 2025
4e986b2
draft of GA for IT and new keystore to support caching-service-3 host
pavel-jares-bcm Dec 10, 2025
002fc17
Merge remote-tracking branch 'refs/remotes/origin/detached10' into re…
pavel-jares-bcm Dec 10, 2025
7f2d096
waiting to caching services are up
pavel-jares-bcm Dec 10, 2025
217c3ac
add log messages
pavel-jares-bcm Dec 10, 2025
24b2879
IT fixes
pavel-jares-bcm Dec 10, 2025
0fb850b
update infinispan ports
pavel-jares-bcm Dec 10, 2025
40e9db9
fix test to use infinispan
pavel-jares-bcm Dec 10, 2025
6c5a801
debugging - wait for JGroups for another 2mins
pavel-jares-bcm Dec 10, 2025
d752643
fix
pavel-jares-bcm Dec 10, 2025
82067c8
fixes
pavel-jares-bcm Dec 10, 2025
b565a81
remove unused values
pavel-jares-bcm Dec 10, 2025
acd42dc
update certificate
pavel-jares-bcm Dec 10, 2025
d7de2b0
update all-services.keystore.p12
pavel-jares-bcm Dec 10, 2025
338c8ce
test clean-up
pavel-jares-bcm Dec 10, 2025
c746652
fix usage of truststore by caching service (key exchange)
pavel-jares-bcm Dec 11, 2025
6ead3cc
code coverage
pavel-jares-bcm Dec 11, 2025
1046d1d
fix the initialization part (java.net.UnknownHostException: caching-s…
pavel-jares-bcm Dec 11, 2025
039b568
fix test
pavel-jares-bcm Dec 11, 2025
8a93aed
Revert "fix usage of truststore by caching service (key exchange)"
pavel-jares-bcm Dec 12, 2025
4aeb7c1
IT extension for tokenCache
pavel-jares-bcm Dec 12, 2025
cb7cd75
improve log message
pavel-jares-bcm Dec 12, 2025
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
79 changes: 79 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,85 @@ jobs:

- uses: ./.github/actions/teardown

CITestsCachingChaoticHA:
needs: PublishJibContainers
container: ubuntu:latest
runs-on: ubuntu-latest
timeout-minutes: 15

services:
caching-service:
image: ghcr.io/balhar-jakub/caching-service:${{ github.run_id }}-${{ github.run_number }}
env:
MANAGEMENT_ENDPOINT_SHUTDOWN_ENABLED: true
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE: health,info,hystrixstream,shutdown
CACHING_STORAGE_MODE: infinispan
CACHING_STORAGE_INFINISPAN_INITIALHOSTS: "caching-service[7098],caching-service-2[7098],caching-service-3[7098]"
JGROUPS_BIND_PORT: 7098
JGROUPS_BIND_ADDRESS: caching-service
JGROUPS_KEYEXCHANGE_PORT: 7118
APIML_SERVICE_HOSTNAME: caching-service
caching-service-2:
image: ghcr.io/balhar-jakub/caching-service:${{ github.run_id }}-${{ github.run_number }}
env:
MANAGEMENT_ENDPOINT_SHUTDOWN_ENABLED: true
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE: health,info,hystrixstream,shutdown
CACHING_STORAGE_MODE: infinispan
CACHING_STORAGE_INFINISPAN_INITIALHOSTS: "caching-service[7098],caching-service-2[7098],caching-service-3[7098]"
JGROUPS_BIND_PORT: 7098
JGROUPS_BIND_ADDRESS: caching-service-2
JGROUPS_KEYEXCHANGE_PORT: 7118
APIML_SERVICE_HOSTNAME: caching-service-2
caching-service-3:
image: ghcr.io/balhar-jakub/caching-service:${{ github.run_id }}-${{ github.run_number }}
env:
MANAGEMENT_ENDPOINT_SHUTDOWN_ENABLED: true
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE: health,info,hystrixstream,shutdown
CACHING_STORAGE_MODE: infinispan
CACHING_STORAGE_INFINISPAN_INITIALHOSTS: "caching-service[7098],caching-service-2[7098],caching-service-3[7098]"
JGROUPS_BIND_PORT: 7098
JGROUPS_BIND_ADDRESS: caching-service-3
JGROUPS_KEYEXCHANGE_PORT: 7118
APIML_SERVICE_HOSTNAME: caching-service-3
mock-services:
image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }}
discovery-service:
image: ghcr.io/balhar-jakub/discovery-service:${{ github.run_id }}-${{ github.run_number }}
volumes:
- /api-defs:/api-defs
gateway-service:
image: ghcr.io/balhar-jakub/gateway-service:${{ github.run_id }}-${{ github.run_number }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}

- uses: ./.github/actions/setup

- name: Run Caching Chaotic HA Tests
run: >
./gradlew :integration-tests:runChaoticHATests --tests org.zowe.apiml.integration.ha.CachingService
--info -Denvironment.config=-ha -Denvironment.offPlatform=true -DcloudGateway.enabled=false
-Partifactory_user=$ARTIFACTORY_USERNAME -Partifactory_password=$ARTIFACTORY_PASSWORD
env:
ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}

- name: Correct Permisions
run: |
chmod 755 -R .gradle
# Coverage results are not stored in this job as it would not provide much additional data
- name: Store results
uses: actions/upload-artifact@v4
if: always()
with:
name: CITestsCachingChaoticHA-${{ env.JOB_ID }}
path: |
integration-tests/build/reports/**
results/**

- uses: ./.github/actions/teardown

CITestsWithInfinispan:
needs: PublishJibContainers
runs-on: ubuntu-latest
Expand Down
12 changes: 10 additions & 2 deletions caching-service-package/src/main/resources/bin/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,16 @@ if [ "${ATTLS_SERVER_ENABLED}" = "true" -a "${APIML_ATTLS_LOAD_KEYRING:-false}"
keystore_location=
fi

# migration step of Infinispan since version 2.18.4 (see #https://github.com/zowe/api-layer/pull/3960)
original_infinispan_data_location="${ZWE_configs_storage_infinispan_persistence_dataLocation:-${ZWE_zowe_workspaceDirectory:-$(pwd)}}/caching-service/data"
if [ -d "${original_infinispan_data_location}" ]; then
mv -f "${original_infinispan_data_location}" "${ZWE_zowe_workspaceDirectory:-$(pwd)}/caching-service/${ZWE_haInstance_id:-localhost}/${ZWE_configs_storage_infinispan_persistence_dataLocation:-data}"
fi
original_infinispan_index_location="${ZWE_configs_storage_infinispan_persistence_indexLocation:-${ZWE_zowe_workspaceDirectory:-$(pwd)}}/caching-service/index"
if [ -d "${original_infinispan_index_location}" ]; then
mv -f "${original_infinispan_index_location}" "${ZWE_zowe_workspaceDirectory:-$(pwd)}/caching-service/${ZWE_haInstance_id:-localhost}/${ZWE_configs_storage_infinispan_persistence_indexLocation:-index}"
fi

CACHING_CODE=CS
_BPXK_AUTOCVT=OFF
_BPX_JOBNAME=${ZWE_zowe_job_prefix}${CACHING_CODE} java \
Expand Down Expand Up @@ -273,8 +283,6 @@ _BPX_JOBNAME=${ZWE_zowe_job_prefix}${CACHING_CODE} java \
-Djgroups.bind.port=${ZWE_configs_storage_infinispan_jgroups_port:-7098} \
-Djgroups.keyExchange.port=${ZWE_configs_storage_infinispan_jgroups_keyExchange_port:-7118} \
-Djgroups.tcp.diag.enabled=${ZWE_configs_storage_infinispan_jgroups_tcp_diag_enabled:-false} \
-Dcaching.storage.infinispan.persistence.dataLocation=${ZWE_configs_storage_infinispan_persistence_dataLocation:-data} \
-Dcaching.storage.infinispan.persistence.indexLocation=${ZWE_configs_storage_infinispan_persistence_indexLocation:-index} \
-Dcaching.storage.infinispan.initialHosts=${ZWE_configs_storage_infinispan_initialHosts:-localhost[7098]} \
-Dserver.address=0.0.0.0 \
-Dserver.ssl.enabled=${ZWE_configs_server_ssl_enabled:-true} \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
Expand All @@ -28,6 +29,7 @@
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1")
Expand Down Expand Up @@ -128,7 +130,13 @@ public ResponseEntity<Object> getAllMapItems(@PathVariable String mapKey, HttpSe
try {
return new ResponseEntity<>(storage.getAllMapItems(s, mapKey), HttpStatus.OK);
} catch (Exception exception) {
return handleIncompatibleStorageMethod(exception, request.getRequestURL());
if (
(exception instanceof StorageException) &&
Messages.INCOMPATIBLE_STORAGE_METHOD.getKey().equals(((StorageException) exception).getKey())
) {
return handleIncompatibleStorageMethod(exception, request.getRequestURL());
}
return handleInternalError(exception, request.getRequestURL());
}
}
).orElseGet(this::getUnauthorizedResponse);
Expand All @@ -145,7 +153,13 @@ public ResponseEntity<Object> getAllMaps(HttpServletRequest request) {
try {
return new ResponseEntity<>(storage.getAllMaps(s), HttpStatus.OK);
} catch (Exception exception) {
return handleIncompatibleStorageMethod(exception, request.getRequestURL());
if (
(exception instanceof StorageException) &&
Messages.INCOMPATIBLE_STORAGE_METHOD.getKey().equals(((StorageException) exception).getKey())
) {
return handleIncompatibleStorageMethod(exception, request.getRequestURL());
}
return handleInternalError(exception, request.getRequestURL());
}
}
).orElseGet(this::getUnauthorizedResponse);
Expand Down Expand Up @@ -199,6 +213,7 @@ public ResponseEntity<Object> update(@RequestBody KeyValue keyValue, HttpServlet


private ResponseEntity<Object> exceptionToResponse(StorageException exception) {
log.debug("Storage exception", exception);
Message message = messageService.createMessage(exception.getKey(), (Object[]) exception.getParameters());
return new ResponseEntity<>(message.mapToView(), exception.getStatus());
}
Expand Down Expand Up @@ -298,12 +313,14 @@ private Optional<String> getHeader(HttpServletRequest request, String headerName
}

private ResponseEntity<Object> handleInternalError(Exception exception, StringBuffer requestURL) {
log.debug("Internal error occurred", exception);
Messages internalServerError = Messages.INTERNAL_SERVER_ERROR;
Message message = messageService.createMessage(internalServerError.getKey(), requestURL, exception.getMessage(), exception.toString());
return new ResponseEntity<>(message.mapToView(), internalServerError.getStatus());
}

private ResponseEntity<Object> handleIncompatibleStorageMethod(Exception exception, StringBuffer requestURL) {
log.debug("Incompatible storage method", exception);
Messages internalServerError = Messages.INCOMPATIBLE_STORAGE_METHOD;
Message message = messageService.createMessage(internalServerError.getKey(), requestURL, exception.getMessage(), exception.toString());
return new ResponseEntity<>(message.mapToView(), internalServerError.getStatus());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public enum Messages {
PAYLOAD_TOO_LARGE("org.zowe.apiml.cache.payloadTooLarge", HttpStatus.BAD_REQUEST),
INTERNAL_SERVER_ERROR("org.zowe.apiml.common.internalRequestError", HttpStatus.INTERNAL_SERVER_ERROR),
MISSING_CERTIFICATE("org.zowe.apiml.cache.missingCertificate", HttpStatus.UNAUTHORIZED),
INCOMPATIBLE_STORAGE_METHOD("org.zowe.apiml.cache.incompatibleStorageMethod", HttpStatus.BAD_REQUEST);
INCOMPATIBLE_STORAGE_METHOD("org.zowe.apiml.cache.incompatibleStorageMethod", HttpStatus.BAD_REQUEST),
CACHE_NOT_AVAILABLE("org.zowe.apiml.cache.notAvailable", HttpStatus.SERVICE_UNAVAILABLE);
private final String key;
private final HttpStatus status;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

package org.zowe.apiml.caching.service.infinispan.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.infinispan.commons.api.CacheContainerAdmin;
import org.infinispan.commons.dataconversion.MediaType;
Expand All @@ -21,27 +22,33 @@
import org.infinispan.lock.api.ClusteredLock;
import org.infinispan.lock.api.ClusteredLockManager;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.partitionhandling.AvailabilityException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.zowe.apiml.caching.service.Messages;
import org.zowe.apiml.caching.service.Storage;
import org.zowe.apiml.caching.service.StorageException;
import org.zowe.apiml.caching.service.infinispan.exception.InfinispanConfigException;
import org.zowe.apiml.caching.service.infinispan.storage.InfinispanStorage;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;

import static org.zowe.apiml.security.SecurityUtils.formatKeyringUrl;
import static org.zowe.apiml.security.SecurityUtils.isKeyring;

@Slf4j
@Configuration
@ConfigurationProperties(value = "caching.storage.infinispan")
@ConditionalOnProperty(name = "caching.storage.mode", havingValue = "infinispan")
Expand All @@ -55,12 +62,6 @@ public class InfinispanConfig implements InitializingBean {
@Value("${caching.storage.infinispan.initialHosts}")
private String initialHosts;

@Value("${caching.storage.infinispan.persistence.dataLocation}")
private String dataLocation;

@Value("${caching.storage.infinispan.persistence.indexLocation:index}")
private String indexLocation;

@Value("${server.ssl.keyStoreType}")
private String keyStoreType;

Expand All @@ -85,6 +86,8 @@ public class InfinispanConfig implements InitializingBean {
@Value("${server.attlsServer.enabled:false}")
private boolean isServerAttlsEnabled;

private AtomicReference<ClusteredLock> zoweInvalidatedTokenLock = new AtomicReference<>();

@Override
public void afterPropertiesSet() {
updateKeyring();
Expand All @@ -98,7 +101,22 @@ void updateKeyring() {
}
}

@Bean
static String getRootFolder() {
// using getenv().get is because of system compatibility (see non-case sensitive on Windows)
String instanceId = System.getenv().get("ZWE_haInstance_id");
if (StringUtils.isBlank(instanceId)) {
instanceId = "localhost";
}

String workspaceFolder = System.getenv().get("ZWE_zowe_workspaceDirectory");
if (StringUtils.isBlank(workspaceFolder)) {
return Paths.get("caching-service", instanceId).toString();
} else {
return Paths.get(workspaceFolder, "caching-service", instanceId).toString();
}
}

@Bean(destroyMethod = "stop")
synchronized DefaultCacheManager cacheManager(ResourceLoader resourceLoader) {
System.setProperty("jgroups.tcpping.initial_hosts", initialHosts);
System.setProperty("jgroups.bind.port", port);
Expand All @@ -124,20 +142,18 @@ synchronized DefaultCacheManager cacheManager(ResourceLoader resourceLoader) {
} catch (IOException e) {
throw new InfinispanConfigException("Can't read configuration file", e);
}
holder.getGlobalConfigurationBuilder().globalState().persistentLocation(getRootFolder()).enable();
holder.newConfigurationBuilder("default").persistence()
.addSoftIndexFileStore()
.clustering().cacheMode(CacheMode.DIST_SYNC);

DefaultCacheManager cacheManager = new DefaultCacheManager(holder, true);

ConfigurationBuilder builder = new ConfigurationBuilder();
builder.clustering()
.cacheMode(CacheMode.REPL_SYNC)
.encoding()
.mediaType("application/x-jboss-marshalling");

builder.persistence()
.passivation(true)
.addSoftIndexFileStore()
.shared(false)
.dataLocation(dataLocation).indexLocation(indexLocation);
builder
.encoding().mediaType("application/x-jboss-marshalling")
.persistence().addSoftIndexFileStore().clustering()
.clustering().cacheMode(CacheMode.DIST_SYNC);

List<String> caches = Arrays.asList("zoweCache", "zoweInvalidatedTokenCache");
caches.forEach(cacheName -> cacheManager.administration()
Expand All @@ -151,17 +167,37 @@ synchronized DefaultCacheManager cacheManager(ResourceLoader resourceLoader) {
return cacheManager;
}

@Bean
public ClusteredLock lock(DefaultCacheManager cacheManager) {
ClusteredLockManager clm = EmbeddedClusteredLockManagerFactory.from(cacheManager);
clm.defineLock("zoweInvalidatedTokenLock");
return clm.get("zoweInvalidatedTokenLock");
}
private ClusteredLock lock(DefaultCacheManager cacheManager) {
ClusteredLock lock = zoweInvalidatedTokenLock.get();
if (lock != null) {
return lock;
}

try {
synchronized (zoweInvalidatedTokenLock) {
lock = zoweInvalidatedTokenLock.get();
if (lock == null) {
ClusteredLockManager clm = EmbeddedClusteredLockManagerFactory.from(cacheManager);
// it can throw AvailabilityException
clm.defineLock("zoweInvalidatedTokenLock");
lock = clm.get("zoweInvalidatedTokenLock");
}
zoweInvalidatedTokenLock.set(lock);
}
return lock;
} catch (AvailabilityException ae) {
log.debug("Cannot obtain lock", ae);
throw new StorageException(Messages.CACHE_NOT_AVAILABLE.getKey(), Messages.CACHE_NOT_AVAILABLE.getStatus(), ae.getMessage());
}
}

@Bean
public Storage storage(DefaultCacheManager cacheManager, ClusteredLock clusteredLock) {
return new InfinispanStorage(cacheManager.getCache("zoweCache"), cacheManager.getCache("zoweInvalidatedTokenCache"), clusteredLock);
public Storage storage(DefaultCacheManager cacheManager) {
return new InfinispanStorage(
cacheManager.getCache("zoweCache"),
cacheManager.getCache("zoweInvalidatedTokenCache"),
() -> lock(cacheManager)
);
}

}
Loading
Loading