From 4d616cdd449d7e38a7ed0306118a22100e623e83 Mon Sep 17 00:00:00 2001 From: stiv03 Date: Mon, 17 Nov 2025 16:17:52 +0200 Subject: [PATCH 1/7] Fix existing service instance not found by resource name # Conflicts: # multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java --- .../process/steps/DetectDeployedMtaStep.java | 73 ++++++++++++++++++- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java index eb25617a37..ca59ff2cae 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java @@ -9,19 +9,27 @@ import org.apache.commons.lang3.StringUtils; import org.cloudfoundry.multiapps.controller.client.facade.CloudControllerClient; import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials; +import org.cloudfoundry.multiapps.controller.client.facade.CloudOperationException; +import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceInstance; import org.cloudfoundry.multiapps.controller.core.cf.clients.CustomServiceKeysClient; import org.cloudfoundry.multiapps.controller.core.cf.clients.WebClientFactory; import org.cloudfoundry.multiapps.controller.core.cf.detect.DeployedMtaDetector; import org.cloudfoundry.multiapps.controller.core.cf.metadata.MtaMetadata; +import org.cloudfoundry.multiapps.controller.core.cf.v2.ResourceType; import org.cloudfoundry.multiapps.controller.core.model.DeployedMta; import org.cloudfoundry.multiapps.controller.core.model.DeployedMtaService; import org.cloudfoundry.multiapps.controller.core.model.DeployedMtaServiceKey; import org.cloudfoundry.multiapps.controller.core.security.serialization.SecureSerialization; import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; +import org.cloudfoundry.multiapps.controller.core.util.CloudModelBuilderUtil; import org.cloudfoundry.multiapps.controller.core.util.NameUtil; import org.cloudfoundry.multiapps.controller.process.Constants; import org.cloudfoundry.multiapps.controller.process.Messages; import org.cloudfoundry.multiapps.controller.process.variables.Variables; +import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor; +import org.cloudfoundry.multiapps.mta.model.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; @@ -38,6 +46,8 @@ public class DetectDeployedMtaStep extends SyncFlowableStep { @Inject private WebClientFactory webClientFactory; + private static final Logger LOGGER = LoggerFactory.getLogger(DetectDeployedMtaStep.class); + @Override protected StepPhase executeStep(ProcessContext context) { getStepLogger().debug(Messages.DETECTING_DEPLOYED_MTA); @@ -94,14 +104,73 @@ private void detectBackupMta(String mtaId, String mtaNamespace, CloudControllerC private List detectDeployedServiceKeys(String mtaId, String mtaNamespace, DeployedMta deployedMta, ProcessContext context) { - List deployedMtaServices = deployedMta == null ? null : deployedMta.getServices(); + List deployedManagedMtaServices = Optional.ofNullable(deployedMta) + .map(DeployedMta::getServices) + .orElse(List.of()); String spaceGuid = context.getVariable(Variables.SPACE_GUID); String userGuid = context.getVariable(Variables.USER_GUID); var token = tokenService.getToken(userGuid); var creds = new CloudCredentials(token, true); CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(creds, context.getVariable(Variables.CORRELATION_ID)); - return serviceKeysClient.getServiceKeysByMetadataAndGuids(spaceGuid, mtaId, mtaNamespace, deployedMtaServices); + + List existingInstanceGuids = getExistingServiceGuids(context); + + return serviceKeysClient.getServiceKeysByMetadataAndGuids( + spaceGuid, mtaId, mtaNamespace, deployedManagedMtaServices, existingInstanceGuids + ); + } + + private List getExistingServiceGuids(ProcessContext context) { + CloudControllerClient client = context.getControllerClient(); + List resources = getExistingServiceResourcesFromDescriptor(context); + + return resources.stream() + .map(resource -> resolveServiceGuid(client, resource)) + .flatMap(Optional::stream) + .toList(); + } + + private Optional resolveServiceGuid(CloudControllerClient client, Resource resource) { + String serviceInstanceName = NameUtil.getServiceName(resource); + + if (serviceInstanceName == null || serviceInstanceName.isBlank()) { + serviceInstanceName = resource.getName(); + } + + try { + CloudServiceInstance instance = client.getServiceInstance(serviceInstanceName); + return Optional.of(instance.getGuid() + .toString()); + } catch (CloudOperationException e) { + if (resource.isOptional()) { + logIgnoredService(Messages.IGNORING_NOT_FOUND_OPTIONAL_SERVICE, resource.getName(), e); + return Optional.empty(); + } + if (!resource.isActive()) { + logIgnoredService(Messages.IGNORING_NOT_FOUND_INACTIVE_SERVICE, resource.getName(), e); + return Optional.empty(); + } + throw e; + } + } + + private void logIgnoredService(String message, String serviceName, Exception e) { + String formattedMessage = MessageFormat.format(message, serviceName); + getStepLogger().debug(formattedMessage); + LOGGER.error(formattedMessage, e); + } + + private List getExistingServiceResourcesFromDescriptor(ProcessContext context) { + DeploymentDescriptor descriptor = context.getVariable(Variables.DEPLOYMENT_DESCRIPTOR); + + if (descriptor == null) { + return List.of(); + } + return descriptor.getResources() + .stream() + .filter(resource -> CloudModelBuilderUtil.getResourceType(resource) == ResourceType.EXISTING_SERVICE) + .toList(); } private void logNoMtaDeployedDetected(String mtaId, String mtaNamespace) { From 5e3e42f897872a872a4d1a6addb18dd523562e24 Mon Sep 17 00:00:00 2001 From: stiv03 Date: Tue, 18 Nov 2025 10:07:51 +0200 Subject: [PATCH 2/7] Add test for getting service instance name or resource name --- .../controller/core/util/NameUtil.java | 12 ++++- .../controller/core/util/NameUtilTest.java | 49 +++++++++++++++++-- .../process/steps/DetectDeployedMtaStep.java | 8 +-- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/NameUtil.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/NameUtil.java index 675f4603e9..2441ef044d 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/NameUtil.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/NameUtil.java @@ -73,7 +73,8 @@ public static String computeNamespacedNameWithLength(String name, String namespa private static String getNameWithNamespaceSuffix(String name, String namespace, int maxLength) { String namespaceSuffix = getNamespaceSuffix(namespace); - String shortenedName = getNameWithProperLength(name, calculateNameLengthWithoutNamespaceAndBlueGreenSuffix(namespaceSuffix, maxLength)); + String shortenedName = getNameWithProperLength(name, + calculateNameLengthWithoutNamespaceAndBlueGreenSuffix(namespaceSuffix, maxLength)); return correctNameSuffix(shortenedName, name, namespaceSuffix); } @@ -120,6 +121,7 @@ public static String computeUserNamespaceWithSystemNamespace(String systemNamesp } return systemNamespace; } + private static String getShortenedName(String name, int maxLength) { String nameHashCode = getHashCodeAsHexString(name); if (maxLength < nameHashCode.length()) { @@ -157,6 +159,14 @@ public static String getServiceName(Resource resource) { .get(SupportedParameters.SERVICE_NAME); } + public static String getServiceInstanceNameOrDefault(Resource resource) { + String serviceInstanceName = getServiceName(resource); + if (serviceInstanceName == null || serviceInstanceName.isBlank()) { + return resource.getName(); + } + return serviceInstanceName; + } + public static class NameRequirements { public static final String XS_APP_NAME_PATTERN = "(?!sap_system)[a-zA-Z0-9\\._\\-\\\\/]{1,240}"; diff --git a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/util/NameUtilTest.java b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/util/NameUtilTest.java index db4c1f3731..b3b0d9cc4f 100644 --- a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/util/NameUtilTest.java +++ b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/util/NameUtilTest.java @@ -1,16 +1,20 @@ package org.cloudfoundry.multiapps.controller.core.util; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - +import java.util.HashMap; +import java.util.Map; import java.util.stream.Stream; +import org.cloudfoundry.multiapps.controller.core.model.SupportedParameters; import org.cloudfoundry.multiapps.controller.core.util.NameUtil.NameRequirements; +import org.cloudfoundry.multiapps.mta.model.Resource; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + class NameUtilTest { static Stream testGetNameWithProperLength() { @@ -94,4 +98,43 @@ void testComputeNamespacedNameWithLength(String name, String namespace, boolean NameUtil.computeNamespacedNameWithLength(name, namespace, applyNamespace, applyNamespaceAsSuffix, maxLength)); } + @Test + void testGetServiceInstanceNameOrDefault_UsesServiceNameParameter() { + Resource resource = createResource("resource-name", "service-name-from-param"); + + String serviceInstanceName = NameUtil.getServiceInstanceNameOrDefault(resource); + + assertEquals("service-name-from-param", serviceInstanceName); + } + + @Test + void testGetServiceInstanceNameOrDefault_FallsBackToResourceNameWhenServiceNameMissing() { + Resource resource = createResource("resource-name-1", null); + + String serviceInstanceName = NameUtil.getServiceInstanceNameOrDefault(resource); + + assertEquals("resource-name-1", serviceInstanceName); + } + + @Test + void testGetServiceInstanceNameOrDefault_FallsBackToResourceNameWhenServiceNameBlank() { + Resource resource = createResource("resource-name-2", " "); + + String serviceInstanceName = NameUtil.getServiceInstanceNameOrDefault(resource); + + assertEquals("resource-name-2", serviceInstanceName); + } + + private Resource createResource(String name, String paramValue) { + Resource resource = Resource.createV3(); + resource.setName(name); + + Map params = new HashMap<>(); + if (paramValue != null) { + params.put(SupportedParameters.SERVICE_NAME, paramValue); + } + resource.setParameters(params); + + return resource; + } } diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java index ca59ff2cae..204b1359c8 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java @@ -132,12 +132,8 @@ private List getExistingServiceGuids(ProcessContext context) { } private Optional resolveServiceGuid(CloudControllerClient client, Resource resource) { - String serviceInstanceName = NameUtil.getServiceName(resource); - - if (serviceInstanceName == null || serviceInstanceName.isBlank()) { - serviceInstanceName = resource.getName(); - } - + String serviceInstanceName = NameUtil.getServiceInstanceNameOrDefault(resource); + try { CloudServiceInstance instance = client.getServiceInstance(serviceInstanceName); return Optional.of(instance.getGuid() From 0fa6088404bf4a0542f64ead298dab4263014b50 Mon Sep 17 00:00:00 2001 From: stiv03 Date: Tue, 18 Nov 2025 12:39:20 +0200 Subject: [PATCH 3/7] fix comment --- .../multiapps/controller/core/util/NameUtilTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/util/NameUtilTest.java b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/util/NameUtilTest.java index b3b0d9cc4f..264f2c56a8 100644 --- a/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/util/NameUtilTest.java +++ b/multiapps-controller-core/src/test/java/org/cloudfoundry/multiapps/controller/core/util/NameUtilTest.java @@ -125,13 +125,13 @@ void testGetServiceInstanceNameOrDefault_FallsBackToResourceNameWhenServiceNameB assertEquals("resource-name-2", serviceInstanceName); } - private Resource createResource(String name, String paramValue) { + private Resource createResource(String resourceName, String serviceInstanceName) { Resource resource = Resource.createV3(); - resource.setName(name); + resource.setName(resourceName); Map params = new HashMap<>(); - if (paramValue != null) { - params.put(SupportedParameters.SERVICE_NAME, paramValue); + if (serviceInstanceName != null) { + params.put(SupportedParameters.SERVICE_NAME, serviceInstanceName); } resource.setParameters(params); From 23d9f76e640b56d3ecd3c71664b0bc82cc4d8f32 Mon Sep 17 00:00:00 2001 From: stiv03 Date: Thu, 8 Jan 2026 14:34:37 +0200 Subject: [PATCH 4/7] Add logic for service keys not renewed when existing service is used --- .../cf/clients/CustomServiceKeysClient.java | 69 ++++++++++--------- .../controller/process/Messages.java | 3 + .../steps/DetectDeployedMtaStepTest.java | 55 +++++++++++---- 3 files changed, 78 insertions(+), 49 deletions(-) diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java index 733843fd25..45c295e7bf 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java @@ -3,8 +3,10 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.function.Function; +import java.util.Objects; +import java.util.UUID; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceType; import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials; @@ -30,7 +32,8 @@ public CustomServiceKeysClient(ApplicationConfiguration configuration, WebClient } public List getServiceKeysByMetadataAndGuids(String spaceGuid, String mtaId, String mtaNamespace, - List services) { + List services, + List existingServiceGuids) { String labelSelector = MtaMetadataCriteriaBuilder.builder() .label(MtaMetadataLabels.SPACE_GUID) .hasValue(spaceGuid) @@ -43,31 +46,40 @@ public List getServiceKeysByMetadataAndGuids(String space .build() .get(); + List managedGuids = extractManagedServiceGuids(services); + + List allServiceGuids = Stream.concat(managedGuids.stream(), existingServiceGuids.stream()) + .filter(Objects::nonNull) + .toList(); + + if (allServiceGuids.isEmpty()) { + return List.of(); + } return new CustomControllerClientErrorHandler().handleErrorsOrReturnResult( - () -> getServiceKeysByMetadataInternal(labelSelector, services)); + () -> getServiceKeysByMetadataInternal(labelSelector, allServiceGuids)); } - private List getServiceKeysByMetadataInternal(String labelSelector, List services) { - String uriSuffix = INCLUDE_SERVICE_INSTANCE_RESOURCES_PARAM; - List managedServices = getManagedServices(services); - if (managedServices != null) { - uriSuffix += "&service_instance_guids=" + managedServices.stream() - .map(service -> service.getGuid() - .toString()) - .collect(Collectors.joining(",")); - } - return getListOfResources(new ServiceKeysResponseMapper(managedServices), SERVICE_KEYS_BY_METADATA_SELECTOR_URI + uriSuffix, + private List extractManagedServiceGuids(List services) { + return getManagedServices(services).stream() + .map(DeployedMtaService::getGuid) + .map(UUID::toString) + .toList(); + } + + private List getServiceKeysByMetadataInternal(String labelSelector, List guids) { + + String uriSuffix = INCLUDE_SERVICE_INSTANCE_RESOURCES_PARAM + + "&service_instance_guids=" + String.join(",", guids); + + return getListOfResources(new ServiceKeysResponseMapper(), + SERVICE_KEYS_BY_METADATA_SELECTOR_URI + uriSuffix, labelSelector); } private List getManagedServices(List services) { - if (services == null) { - return null; - } - List managedServices = services.stream() - .filter(this::serviceIsNotUserProvided) - .collect(Collectors.toList()); - return managedServices.isEmpty() ? null : managedServices; + return services.stream() + .filter(this::serviceIsNotUserProvided) + .toList(); } private boolean serviceIsNotUserProvided(DeployedMtaService service) { @@ -76,23 +88,12 @@ private boolean serviceIsNotUserProvided(DeployedMtaService service) { } protected class ServiceKeysResponseMapper extends ResourcesResponseMapper { - - List mtaServices; - - public ServiceKeysResponseMapper(List mtaServices) { - this.mtaServices = mtaServices; + public ServiceKeysResponseMapper() { } @Override public List getMappedResources() { - Map serviceMapping; - if (mtaServices != null) { - serviceMapping = mtaServices.stream() - .collect(Collectors.toMap(service -> service.getGuid() - .toString(), Function.identity())); - } else { - serviceMapping = getIncludedServiceInstancesMapping(); - } + Map serviceMapping = getIncludedServiceInstancesMapping(); return getQueriedResources().stream() .map(resource -> resourceMapper.mapServiceKeyResource(resource, serviceMapping)) .collect(Collectors.toList()); @@ -108,4 +109,4 @@ public Map getIncludedServiceInstancesMapping() { } } -} +} \ No newline at end of file diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java index 8e259ae732..2e0e66e9a1 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/Messages.java @@ -789,6 +789,9 @@ public class Messages { public static final String TOTAL_SIZE_OF_ALL_RESOLVED_CONTENT_0 = "Total size for all resolved content {0}"; + public static final String IGNORING_NOT_FOUND_OPTIONAL_SERVICE = "Service {0} not found but is optional"; + public static final String IGNORING_NOT_FOUND_INACTIVE_SERVICE = "Service {0} not found but is inactive"; + // Not log messages public static final String SERVICE_TYPE = "{0}/{1}"; public static final String PARSE_NULL_STRING_ERROR = "Cannot parse null string"; diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStepTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStepTest.java index 39faae73aa..8b027b3719 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStepTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStepTest.java @@ -6,7 +6,7 @@ import org.cloudfoundry.client.v3.Metadata; import org.cloudfoundry.multiapps.common.test.TestUtil; -import org.cloudfoundry.multiapps.common.test.Tester.Expectation; +import org.cloudfoundry.multiapps.common.test.Tester; import org.cloudfoundry.multiapps.common.util.JsonUtil; import org.cloudfoundry.multiapps.controller.client.facade.CloudControllerClient; import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials; @@ -31,6 +31,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.when; class DetectDeployedMtaStepTest extends SyncFlowableStepTest { @@ -62,19 +68,30 @@ void testExecuteWithDeployedMta() { .getKeys(); List deployedComponents = List.of(deployedMta); - when(deployedMtaDetector.detectDeployedMtas(Mockito.any(CloudControllerClient.class))).thenReturn(deployedComponents); - when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(Mockito.eq(MTA_ID), Mockito.eq(null), - Mockito.any( - CloudControllerClient.class))).thenReturn( - Optional.of(deployedMta)); - when(customClientMock.getServiceKeysByMetadataAndGuids(Mockito.eq(SPACE_GUID), Mockito.eq(MTA_ID), Mockito.isNull(), - Mockito.eq(deployedMta.getServices()))).thenReturn(deployedKeys); + when(deployedMtaDetector.detectDeployedMtas(any(CloudControllerClient.class))) + .thenReturn(deployedComponents); + when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(eq(MTA_ID), eq(null), + any(CloudControllerClient.class))) + .thenReturn(Optional.of(deployedMta)); + + when(customClientMock.getServiceKeysByMetadataAndGuids( + eq(SPACE_GUID), eq(MTA_ID), isNull(), + eq(deployedMta.getServices()), + argThat(List::isEmpty))) + .thenReturn(deployedKeys); + + when(customClientMock.getServiceKeysByMetadataAndGuids( + eq(SPACE_GUID), eq(MTA_ID), isNull(), + anyList(), + argThat(list -> list != null && !list.isEmpty()))) + .thenReturn(Collections.emptyList()); step.execute(execution); assertStepFinishedSuccessfully(); - tester.test(() -> context.getVariable(Variables.DEPLOYED_MTA), new Expectation(Expectation.Type.JSON, DEPLOYED_MTA_LOCATION)); + tester.test(() -> context.getVariable(Variables.DEPLOYED_MTA), + new Tester.Expectation(Tester.Expectation.Type.JSON, DEPLOYED_MTA_LOCATION)); assertEquals(deployedKeys, context.getVariable(Variables.DEPLOYED_MTA_SERVICE_KEYS)); } @@ -82,8 +99,16 @@ void testExecuteWithDeployedMta() { void testExecuteWithoutDeployedMta() { when(deployedMtaDetector.detectDeployedMtas(client)).thenReturn(Collections.emptyList()); when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(MTA_ID, null, client)).thenReturn(Optional.empty()); - when(customClientMock.getServiceKeysByMetadataAndGuids(SPACE_GUID, MTA_ID, null, - Collections.emptyList())).thenReturn(Collections.emptyList()); + when(customClientMock.getServiceKeysByMetadataAndGuids( + eq(SPACE_GUID), eq(MTA_ID), isNull(), + eq(Collections.emptyList()), + eq(Collections.emptyList()))) + .thenReturn(Collections.emptyList()); + + when(customClientMock.getServiceKeysByMetadataAndGuids( + anyString(), anyString(), isNull(), + anyList(), anyList())) + .thenReturn(Collections.emptyList()); step.execute(execution); @@ -130,10 +155,10 @@ void testExecuteWithBackupdMta() { .build()) .build(); - when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(Mockito.eq(MTA_ID), Mockito.eq(null), + when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(eq(MTA_ID), eq(null), Mockito.any())).thenReturn(Optional.of(deployedMta)); - when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(Mockito.eq(MTA_ID), - Mockito.eq(NameUtil.computeUserNamespaceWithSystemNamespace( + when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(eq(MTA_ID), + eq(NameUtil.computeUserNamespaceWithSystemNamespace( Constants.MTA_BACKUP_NAMESPACE, null)), Mockito.any())).thenReturn(Optional.of(backupMta)); @@ -174,4 +199,4 @@ protected CustomServiceKeysClient getCustomServiceKeysClient(CloudCredentials cr } } -} +} \ No newline at end of file From 294d2ecc7f81dd5213fdb6cfe0d9813ad8c8e2c9 Mon Sep 17 00:00:00 2001 From: stiv03 Date: Mon, 12 Jan 2026 11:16:17 +0200 Subject: [PATCH 5/7] add service keys to delete --- .../process/steps/BuildCloudUndeployModelStep.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudUndeployModelStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudUndeployModelStep.java index 75c29b4619..56256bfcd2 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudUndeployModelStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudUndeployModelStep.java @@ -65,9 +65,16 @@ protected StepPhase executeStep(ProcessContext context) { getStepLogger().debug(Messages.BUILDING_CLOUD_UNDEPLOY_MODEL); DeployedMta deployedMta = context.getVariable(Variables.DEPLOYED_MTA); + List serviceKeysToDelete = computeServiceKeysToDelete(context); + getStepLogger().debug(Messages.SERVICE_KEYS_FOR_DELETION, serviceKeysToDelete); + if (deployedMta == null) { setComponentsToUndeploy(context, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + if (!serviceKeysToDelete.isEmpty()) { + context.setVariable(Variables.SERVICE_KEYS_TO_DELETE, + getServiceKeysToDelete(context, serviceKeysToDelete)); + } return StepPhase.DONE; } @@ -98,9 +105,6 @@ protected StepPhase executeStep(ProcessContext context) { servicesForApplications, serviceNames); getStepLogger().debug(Messages.SERVICES_TO_DELETE, servicesToDelete); - List serviceKeysToDelete = computeServiceKeysToDelete(context); - getStepLogger().debug(Messages.SERVICE_KEYS_FOR_DELETION, serviceKeysToDelete); - List appsToUndeploy = computeAppsToUndeploy(deployedAppsToUndeploy, context.getControllerClient()); DeployedMta backupMta = context.getVariable(Variables.BACKUP_MTA); From bfa2a62bae23b56878bd89a7b7ed7716feaf0726 Mon Sep 17 00:00:00 2001 From: stiv03 Date: Wed, 14 Jan 2026 11:39:19 +0200 Subject: [PATCH 6/7] Move deletion of existing service keys logic --- .../cf/clients/CustomServiceKeysClient.java | 57 ++++++++--- .../steps/BuildCloudDeployModelStep.java | 94 +++++++++++++++++++ .../process/steps/DetectDeployedMtaStep.java | 64 +------------ .../steps/BuildCloudDeployModelStepTest.java | 6 ++ .../steps/DetectDeployedMtaStepTest.java | 53 +++-------- 5 files changed, 162 insertions(+), 112 deletions(-) diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java index 45c295e7bf..0b9915b93f 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java @@ -6,7 +6,6 @@ import java.util.Objects; import java.util.UUID; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceType; import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials; @@ -31,9 +30,12 @@ public CustomServiceKeysClient(ApplicationConfiguration configuration, WebClient super(configuration, webClientFactory, credentials, correlationId); } - public List getServiceKeysByMetadataAndGuids(String spaceGuid, String mtaId, String mtaNamespace, - List services, - List existingServiceGuids) { + public List getServiceKeysByMetadataAndExistingGuids( + String spaceGuid, + String mtaId, + String mtaNamespace, + List existingServiceGuids) { + String labelSelector = MtaMetadataCriteriaBuilder.builder() .label(MtaMetadataLabels.SPACE_GUID) .hasValue(spaceGuid) @@ -46,17 +48,50 @@ public List getServiceKeysByMetadataAndGuids(String space .build() .get(); - List managedGuids = extractManagedServiceGuids(services); - - List allServiceGuids = Stream.concat(managedGuids.stream(), existingServiceGuids.stream()) - .filter(Objects::nonNull) - .toList(); + List allServiceGuids = existingServiceGuids.stream() + .filter(Objects::nonNull) + .toList(); if (allServiceGuids.isEmpty()) { return List.of(); } - return new CustomControllerClientErrorHandler().handleErrorsOrReturnResult( - () -> getServiceKeysByMetadataInternal(labelSelector, allServiceGuids)); + + return new CustomControllerClientErrorHandler() + .handleErrorsOrReturnResult( + () -> getServiceKeysByMetadataInternal(labelSelector, allServiceGuids) + ); + } + + public List getServiceKeysByMetadataAndManagedServices( + String spaceGuid, + String mtaId, + String mtaNamespace, + List services) { + + String labelSelector = MtaMetadataCriteriaBuilder.builder() + .label(MtaMetadataLabels.SPACE_GUID) + .hasValue(spaceGuid) + .and() + .label(MtaMetadataLabels.MTA_NAMESPACE) + .hasValueOrIsntPresent(MtaMetadataUtil.getHashedLabel(mtaNamespace)) + .and() + .label(MtaMetadataLabels.MTA_ID) + .hasValue(MtaMetadataUtil.getHashedLabel(mtaId)) + .build() + .get(); + + List managedGuids = extractManagedServiceGuids(services).stream() + .filter(Objects::nonNull) + .toList(); + + if (managedGuids.isEmpty()) { + return List.of(); + } + + return new CustomControllerClientErrorHandler() + .handleErrorsOrReturnResult( + () -> getServiceKeysByMetadataInternal(labelSelector, managedGuids) + ); } private List extractManagedServiceGuids(List services) { diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStep.java index 8057ba4423..6ac553db39 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStep.java @@ -1,9 +1,11 @@ package org.cloudfoundry.multiapps.controller.process.steps; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; @@ -13,9 +15,14 @@ import org.cloudfoundry.multiapps.common.SLException; import org.cloudfoundry.multiapps.controller.api.model.ProcessType; import org.cloudfoundry.multiapps.controller.client.facade.CloudControllerClient; +import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials; +import org.cloudfoundry.multiapps.controller.client.facade.CloudOperationException; +import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceInstance; import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceKey; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudServiceInstanceExtended; import org.cloudfoundry.multiapps.controller.core.cf.CloudHandlerFactory; +import org.cloudfoundry.multiapps.controller.core.cf.clients.CustomServiceKeysClient; +import org.cloudfoundry.multiapps.controller.core.cf.clients.WebClientFactory; import org.cloudfoundry.multiapps.controller.core.cf.util.CloudModelBuilderContentCalculator; import org.cloudfoundry.multiapps.controller.core.cf.util.DeployedAfterModulesContentValidator; import org.cloudfoundry.multiapps.controller.core.cf.util.ModulesCloudModelBuilderContentCalculator; @@ -23,13 +30,16 @@ import org.cloudfoundry.multiapps.controller.core.cf.util.ResourcesCloudModelBuilderContentCalculator; import org.cloudfoundry.multiapps.controller.core.cf.util.UnresolvedModulesContentValidator; import org.cloudfoundry.multiapps.controller.core.cf.v2.ApplicationCloudModelBuilder; +import org.cloudfoundry.multiapps.controller.core.cf.v2.ResourceType; import org.cloudfoundry.multiapps.controller.core.cf.v2.ServiceKeysCloudModelBuilder; import org.cloudfoundry.multiapps.controller.core.cf.v2.ServicesCloudModelBuilder; import org.cloudfoundry.multiapps.controller.core.helpers.ModuleToDeployHelper; import org.cloudfoundry.multiapps.controller.core.model.DeployedMta; import org.cloudfoundry.multiapps.controller.core.model.DeployedMtaApplication; +import org.cloudfoundry.multiapps.controller.core.model.DeployedMtaServiceKey; import org.cloudfoundry.multiapps.controller.core.model.SupportedParameters; import org.cloudfoundry.multiapps.controller.core.security.serialization.SecureSerialization; +import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; import org.cloudfoundry.multiapps.controller.core.util.CloudModelBuilderUtil; import org.cloudfoundry.multiapps.controller.core.util.NameUtil; import org.cloudfoundry.multiapps.controller.process.Messages; @@ -47,6 +57,8 @@ import org.cloudfoundry.multiapps.mta.model.Resource; import org.cloudfoundry.multiapps.mta.util.PropertiesUtil; import org.flowable.engine.delegate.DelegateExecution; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; @@ -64,11 +76,25 @@ public class BuildCloudDeployModelStep extends SyncFlowableStep { @Inject private DeprecatedBuildpackChecker buildpackChecker; + @Inject + private TokenService tokenService; + @Inject + private WebClientFactory webClientFactory; + + private static final Logger LOGGER = LoggerFactory.getLogger(BuildCloudDeployModelStep.class); + @Override protected StepPhase executeStep(ProcessContext context) { getStepLogger().debug(Messages.BUILDING_CLOUD_MODEL); DeploymentDescriptor deploymentDescriptor = context.getVariable(Variables.COMPLETE_DEPLOYMENT_DESCRIPTOR); + String mtaId = context.getVariable(Variables.MTA_ID); + String mtaNamespace = context.getVariable(Variables.MTA_NAMESPACE); + + var deployedServiceKeys = detectDeployedServiceKeys(mtaId, mtaNamespace, context); + context.setVariable(Variables.DEPLOYED_MTA_SERVICE_KEYS, deployedServiceKeys); + getStepLogger().debug(Messages.DEPLOYED_MTA_SERVICE_KEYS, SecureSerialization.toJson(deployedServiceKeys)); + // Get module sets: DeployedMta deployedMta = context.getVariable(Variables.DEPLOYED_MTA); List deployedApplications = (deployedMta != null) ? deployedMta.getApplications() : Collections.emptyList(); @@ -331,4 +357,72 @@ private List getDomainsFromApps(ProcessContext context, DeploymentDescri return new ArrayList<>(domains); } + private List detectDeployedServiceKeys(String mtaId, String mtaNamespace, + ProcessContext context) { + String spaceGuid = context.getVariable(Variables.SPACE_GUID); + String userGuid = context.getVariable(Variables.USER_GUID); + var token = tokenService.getToken(userGuid); + var creds = new CloudCredentials(token, true); + + CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(creds, context.getVariable(Variables.CORRELATION_ID)); + + List existingInstanceGuids = getExistingServiceGuids(context); + + return serviceKeysClient.getServiceKeysByMetadataAndExistingGuids( + spaceGuid, mtaId, mtaNamespace, existingInstanceGuids + ); + } + + private List getExistingServiceGuids(ProcessContext context) { + CloudControllerClient client = context.getControllerClient(); + List resources = getExistingServiceResourcesFromDescriptor(context); + + return resources.stream() + .map(resource -> resolveServiceGuid(client, resource)) + .flatMap(Optional::stream) + .toList(); + } + + private Optional resolveServiceGuid(CloudControllerClient client, Resource resource) { + String serviceInstanceName = NameUtil.getServiceInstanceNameOrDefault(resource); + + try { + CloudServiceInstance instance = client.getServiceInstance(serviceInstanceName); + return Optional.of(instance.getGuid() + .toString()); + } catch (CloudOperationException e) { + if (resource.isOptional()) { + logIgnoredService(Messages.IGNORING_NOT_FOUND_OPTIONAL_SERVICE, resource.getName(), e); + return Optional.empty(); + } + if (!resource.isActive()) { + logIgnoredService(Messages.IGNORING_NOT_FOUND_INACTIVE_SERVICE, resource.getName(), e); + return Optional.empty(); + } + throw e; + } + } + + private void logIgnoredService(String message, String serviceName, Exception e) { + String formattedMessage = MessageFormat.format(message, serviceName); + getStepLogger().debug(formattedMessage); + LOGGER.error(formattedMessage, e); + } + + private List getExistingServiceResourcesFromDescriptor(ProcessContext context) { + DeploymentDescriptor descriptor = context.getVariable(Variables.COMPLETE_DEPLOYMENT_DESCRIPTOR); + + if (descriptor == null) { + return List.of(); + } + return descriptor.getResources() + .stream() + .filter(resource -> CloudModelBuilderUtil.getResourceType(resource) == ResourceType.EXISTING_SERVICE) + .toList(); + } + + protected CustomServiceKeysClient getCustomServiceKeysClient(CloudCredentials credentials, String correlationId) { + return new CustomServiceKeysClient(configuration, webClientFactory, credentials, correlationId); + } + } diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java index 204b1359c8..dc39aba61f 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java @@ -9,27 +9,19 @@ import org.apache.commons.lang3.StringUtils; import org.cloudfoundry.multiapps.controller.client.facade.CloudControllerClient; import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials; -import org.cloudfoundry.multiapps.controller.client.facade.CloudOperationException; -import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceInstance; import org.cloudfoundry.multiapps.controller.core.cf.clients.CustomServiceKeysClient; import org.cloudfoundry.multiapps.controller.core.cf.clients.WebClientFactory; import org.cloudfoundry.multiapps.controller.core.cf.detect.DeployedMtaDetector; import org.cloudfoundry.multiapps.controller.core.cf.metadata.MtaMetadata; -import org.cloudfoundry.multiapps.controller.core.cf.v2.ResourceType; import org.cloudfoundry.multiapps.controller.core.model.DeployedMta; import org.cloudfoundry.multiapps.controller.core.model.DeployedMtaService; import org.cloudfoundry.multiapps.controller.core.model.DeployedMtaServiceKey; import org.cloudfoundry.multiapps.controller.core.security.serialization.SecureSerialization; import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; -import org.cloudfoundry.multiapps.controller.core.util.CloudModelBuilderUtil; import org.cloudfoundry.multiapps.controller.core.util.NameUtil; import org.cloudfoundry.multiapps.controller.process.Constants; import org.cloudfoundry.multiapps.controller.process.Messages; import org.cloudfoundry.multiapps.controller.process.variables.Variables; -import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor; -import org.cloudfoundry.multiapps.mta.model.Resource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; @@ -46,8 +38,6 @@ public class DetectDeployedMtaStep extends SyncFlowableStep { @Inject private WebClientFactory webClientFactory; - private static final Logger LOGGER = LoggerFactory.getLogger(DetectDeployedMtaStep.class); - @Override protected StepPhase executeStep(ProcessContext context) { getStepLogger().debug(Messages.DETECTING_DEPLOYED_MTA); @@ -114,61 +104,11 @@ private List detectDeployedServiceKeys(String mtaId, Stri CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(creds, context.getVariable(Variables.CORRELATION_ID)); - List existingInstanceGuids = getExistingServiceGuids(context); - - return serviceKeysClient.getServiceKeysByMetadataAndGuids( - spaceGuid, mtaId, mtaNamespace, deployedManagedMtaServices, existingInstanceGuids + return serviceKeysClient.getServiceKeysByMetadataAndManagedServices( + spaceGuid, mtaId, mtaNamespace, deployedManagedMtaServices ); } - private List getExistingServiceGuids(ProcessContext context) { - CloudControllerClient client = context.getControllerClient(); - List resources = getExistingServiceResourcesFromDescriptor(context); - - return resources.stream() - .map(resource -> resolveServiceGuid(client, resource)) - .flatMap(Optional::stream) - .toList(); - } - - private Optional resolveServiceGuid(CloudControllerClient client, Resource resource) { - String serviceInstanceName = NameUtil.getServiceInstanceNameOrDefault(resource); - - try { - CloudServiceInstance instance = client.getServiceInstance(serviceInstanceName); - return Optional.of(instance.getGuid() - .toString()); - } catch (CloudOperationException e) { - if (resource.isOptional()) { - logIgnoredService(Messages.IGNORING_NOT_FOUND_OPTIONAL_SERVICE, resource.getName(), e); - return Optional.empty(); - } - if (!resource.isActive()) { - logIgnoredService(Messages.IGNORING_NOT_FOUND_INACTIVE_SERVICE, resource.getName(), e); - return Optional.empty(); - } - throw e; - } - } - - private void logIgnoredService(String message, String serviceName, Exception e) { - String formattedMessage = MessageFormat.format(message, serviceName); - getStepLogger().debug(formattedMessage); - LOGGER.error(formattedMessage, e); - } - - private List getExistingServiceResourcesFromDescriptor(ProcessContext context) { - DeploymentDescriptor descriptor = context.getVariable(Variables.DEPLOYMENT_DESCRIPTOR); - - if (descriptor == null) { - return List.of(); - } - return descriptor.getResources() - .stream() - .filter(resource -> CloudModelBuilderUtil.getResourceType(resource) == ResourceType.EXISTING_SERVICE) - .toList(); - } - private void logNoMtaDeployedDetected(String mtaId, String mtaNamespace) { if (StringUtils.isNotEmpty(mtaNamespace)) { getStepLogger().info(MessageFormat.format(Messages.NO_DEPLOYED_MTA_DETECTED_WITH_NAMESPACE, mtaId, mtaNamespace)); diff --git a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStepTest.java b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStepTest.java index ddf288592c..331a51601f 100644 --- a/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStepTest.java +++ b/multiapps-controller-process/src/test/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStepTest.java @@ -11,11 +11,13 @@ import org.cloudfoundry.multiapps.common.test.Tester.Expectation; import org.cloudfoundry.multiapps.common.util.JsonUtil; import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceKey; +import org.cloudfoundry.multiapps.controller.core.cf.clients.WebClientFactory; import org.cloudfoundry.multiapps.controller.core.cf.util.ModulesCloudModelBuilderContentCalculator; import org.cloudfoundry.multiapps.controller.core.cf.v2.ApplicationCloudModelBuilder; import org.cloudfoundry.multiapps.controller.core.cf.v2.ServiceKeysCloudModelBuilder; import org.cloudfoundry.multiapps.controller.core.helpers.ModuleToDeployHelper; import org.cloudfoundry.multiapps.controller.core.model.DeployedMta; +import org.cloudfoundry.multiapps.controller.core.security.token.TokenService; import org.cloudfoundry.multiapps.controller.core.test.DescriptorTestUtil; import org.cloudfoundry.multiapps.controller.process.util.DeprecatedBuildpackChecker; import org.cloudfoundry.multiapps.controller.process.util.ProcessTypeParser; @@ -53,6 +55,10 @@ class BuildCloudDeployModelStepTest extends SyncFlowableStepTest { @@ -68,30 +62,19 @@ void testExecuteWithDeployedMta() { .getKeys(); List deployedComponents = List.of(deployedMta); - when(deployedMtaDetector.detectDeployedMtas(any(CloudControllerClient.class))) - .thenReturn(deployedComponents); - when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(eq(MTA_ID), eq(null), - any(CloudControllerClient.class))) - .thenReturn(Optional.of(deployedMta)); - - when(customClientMock.getServiceKeysByMetadataAndGuids( - eq(SPACE_GUID), eq(MTA_ID), isNull(), - eq(deployedMta.getServices()), - argThat(List::isEmpty))) - .thenReturn(deployedKeys); - - when(customClientMock.getServiceKeysByMetadataAndGuids( - eq(SPACE_GUID), eq(MTA_ID), isNull(), - anyList(), - argThat(list -> list != null && !list.isEmpty()))) - .thenReturn(Collections.emptyList()); + when(deployedMtaDetector.detectDeployedMtas(Mockito.any(CloudControllerClient.class))).thenReturn(deployedComponents); + when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(Mockito.eq(MTA_ID), Mockito.eq(null), + Mockito.any( + CloudControllerClient.class))).thenReturn( + Optional.of(deployedMta)); + when(customClientMock.getServiceKeysByMetadataAndManagedServices(Mockito.eq(SPACE_GUID), Mockito.eq(MTA_ID), Mockito.isNull(), + Mockito.eq(deployedMta.getServices()))).thenReturn(deployedKeys); step.execute(execution); assertStepFinishedSuccessfully(); - tester.test(() -> context.getVariable(Variables.DEPLOYED_MTA), - new Tester.Expectation(Tester.Expectation.Type.JSON, DEPLOYED_MTA_LOCATION)); + tester.test(() -> context.getVariable(Variables.DEPLOYED_MTA), new Expectation(Expectation.Type.JSON, DEPLOYED_MTA_LOCATION)); assertEquals(deployedKeys, context.getVariable(Variables.DEPLOYED_MTA_SERVICE_KEYS)); } @@ -99,16 +82,8 @@ void testExecuteWithDeployedMta() { void testExecuteWithoutDeployedMta() { when(deployedMtaDetector.detectDeployedMtas(client)).thenReturn(Collections.emptyList()); when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(MTA_ID, null, client)).thenReturn(Optional.empty()); - when(customClientMock.getServiceKeysByMetadataAndGuids( - eq(SPACE_GUID), eq(MTA_ID), isNull(), - eq(Collections.emptyList()), - eq(Collections.emptyList()))) - .thenReturn(Collections.emptyList()); - - when(customClientMock.getServiceKeysByMetadataAndGuids( - anyString(), anyString(), isNull(), - anyList(), anyList())) - .thenReturn(Collections.emptyList()); + when(customClientMock.getServiceKeysByMetadataAndManagedServices(SPACE_GUID, MTA_ID, null, + Collections.emptyList())).thenReturn(Collections.emptyList()); step.execute(execution); @@ -155,10 +130,10 @@ void testExecuteWithBackupdMta() { .build()) .build(); - when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(eq(MTA_ID), eq(null), + when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(Mockito.eq(MTA_ID), Mockito.eq(null), Mockito.any())).thenReturn(Optional.of(deployedMta)); - when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(eq(MTA_ID), - eq(NameUtil.computeUserNamespaceWithSystemNamespace( + when(deployedMtaDetector.detectDeployedMtaByNameAndNamespace(Mockito.eq(MTA_ID), + Mockito.eq(NameUtil.computeUserNamespaceWithSystemNamespace( Constants.MTA_BACKUP_NAMESPACE, null)), Mockito.any())).thenReturn(Optional.of(backupMta)); From a831ec1ca5425d16dd6a14b2c90d84a7c9b0d415 Mon Sep 17 00:00:00 2001 From: stiv03 Date: Thu, 15 Jan 2026 15:03:02 +0200 Subject: [PATCH 7/7] Fix managed service keys not detected and fix some comments --- .../cf/clients/CustomServiceKeysClient.java | 48 +++++++++---------- .../controller/core/util/NameUtil.java | 2 +- .../steps/BuildCloudDeployModelStep.java | 27 ++++++++--- .../process/steps/DetectDeployedMtaStep.java | 9 ++-- 4 files changed, 49 insertions(+), 37 deletions(-) diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java index 0b9915b93f..3d4def6631 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/clients/CustomServiceKeysClient.java @@ -36,17 +36,7 @@ public List getServiceKeysByMetadataAndExistingGuids( String mtaNamespace, List existingServiceGuids) { - String labelSelector = MtaMetadataCriteriaBuilder.builder() - .label(MtaMetadataLabels.SPACE_GUID) - .hasValue(spaceGuid) - .and() - .label(MtaMetadataLabels.MTA_NAMESPACE) - .hasValueOrIsntPresent(MtaMetadataUtil.getHashedLabel(mtaNamespace)) - .and() - .label(MtaMetadataLabels.MTA_ID) - .hasValue(MtaMetadataUtil.getHashedLabel(mtaId)) - .build() - .get(); + String labelSelector = buildMtaMetadataLabelSelector(spaceGuid, mtaId, mtaNamespace); List allServiceGuids = existingServiceGuids.stream() .filter(Objects::nonNull) @@ -68,21 +58,9 @@ public List getServiceKeysByMetadataAndManagedServices( String mtaNamespace, List services) { - String labelSelector = MtaMetadataCriteriaBuilder.builder() - .label(MtaMetadataLabels.SPACE_GUID) - .hasValue(spaceGuid) - .and() - .label(MtaMetadataLabels.MTA_NAMESPACE) - .hasValueOrIsntPresent(MtaMetadataUtil.getHashedLabel(mtaNamespace)) - .and() - .label(MtaMetadataLabels.MTA_ID) - .hasValue(MtaMetadataUtil.getHashedLabel(mtaId)) - .build() - .get(); - - List managedGuids = extractManagedServiceGuids(services).stream() - .filter(Objects::nonNull) - .toList(); + String labelSelector = buildMtaMetadataLabelSelector(spaceGuid, mtaId, mtaNamespace); + + List managedGuids = extractManagedServiceGuids(services); if (managedGuids.isEmpty()) { return List.of(); @@ -94,10 +72,28 @@ public List getServiceKeysByMetadataAndManagedServices( ); } + private String buildMtaMetadataLabelSelector(String spaceGuid, + String mtaId, + String mtaNamespace) { + + return MtaMetadataCriteriaBuilder.builder() + .label(MtaMetadataLabels.SPACE_GUID) + .hasValue(spaceGuid) + .and() + .label(MtaMetadataLabels.MTA_NAMESPACE) + .hasValueOrIsntPresent(MtaMetadataUtil.getHashedLabel(mtaNamespace)) + .and() + .label(MtaMetadataLabels.MTA_ID) + .hasValue(MtaMetadataUtil.getHashedLabel(mtaId)) + .build() + .get(); + } + private List extractManagedServiceGuids(List services) { return getManagedServices(services).stream() .map(DeployedMtaService::getGuid) .map(UUID::toString) + .filter(Objects::nonNull) .toList(); } diff --git a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/NameUtil.java b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/NameUtil.java index 2441ef044d..d588c05155 100644 --- a/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/NameUtil.java +++ b/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/util/NameUtil.java @@ -161,7 +161,7 @@ public static String getServiceName(Resource resource) { public static String getServiceInstanceNameOrDefault(Resource resource) { String serviceInstanceName = getServiceName(resource); - if (serviceInstanceName == null || serviceInstanceName.isBlank()) { + if (StringUtils.isBlank(serviceInstanceName)) { return resource.getName(); } return serviceInstanceName; diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStep.java index 6ac553db39..3b15707bff 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/BuildCloudDeployModelStep.java @@ -9,6 +9,7 @@ import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; +import java.util.stream.Stream; import jakarta.inject.Inject; import jakarta.inject.Named; @@ -19,6 +20,7 @@ import org.cloudfoundry.multiapps.controller.client.facade.CloudOperationException; import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceInstance; import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceKey; +import org.cloudfoundry.multiapps.controller.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; import org.cloudfoundry.multiapps.controller.client.lib.domain.CloudServiceInstanceExtended; import org.cloudfoundry.multiapps.controller.core.cf.CloudHandlerFactory; import org.cloudfoundry.multiapps.controller.core.cf.clients.CustomServiceKeysClient; @@ -91,9 +93,7 @@ protected StepPhase executeStep(ProcessContext context) { String mtaId = context.getVariable(Variables.MTA_ID); String mtaNamespace = context.getVariable(Variables.MTA_NAMESPACE); - var deployedServiceKeys = detectDeployedServiceKeys(mtaId, mtaNamespace, context); - context.setVariable(Variables.DEPLOYED_MTA_SERVICE_KEYS, deployedServiceKeys); - getStepLogger().debug(Messages.DEPLOYED_MTA_SERVICE_KEYS, SecureSerialization.toJson(deployedServiceKeys)); + addDetectedExistingServiceKeysToDetectedManagedKeys(mtaId, mtaNamespace, context); // Get module sets: DeployedMta deployedMta = context.getVariable(Variables.DEPLOYED_MTA); @@ -357,14 +357,29 @@ private List getDomainsFromApps(ProcessContext context, DeploymentDescri return new ArrayList<>(domains); } + private void addDetectedExistingServiceKeysToDetectedManagedKeys(String mtaId, String mtaNamespace, ProcessContext context) { + List deployedServiceKeys = detectDeployedServiceKeys(mtaId, mtaNamespace, context); + if (!deployedServiceKeys.isEmpty()) { + + List detectedServiceKeysForManagedServices = context.getVariable(Variables.DEPLOYED_MTA_SERVICE_KEYS); + List allServiceKeys = Stream.concat( + deployedServiceKeys.stream(), + detectedServiceKeysForManagedServices.stream()) + .toList(); + + context.setVariable(Variables.DEPLOYED_MTA_SERVICE_KEYS, allServiceKeys); + getStepLogger().debug(Messages.DEPLOYED_MTA_SERVICE_KEYS, SecureSerialization.toJson(allServiceKeys)); + } + } + private List detectDeployedServiceKeys(String mtaId, String mtaNamespace, ProcessContext context) { String spaceGuid = context.getVariable(Variables.SPACE_GUID); String userGuid = context.getVariable(Variables.USER_GUID); - var token = tokenService.getToken(userGuid); - var creds = new CloudCredentials(token, true); + OAuth2AccessTokenWithAdditionalInfo token = tokenService.getToken(userGuid); + CloudCredentials credentials = new CloudCredentials(token, true); - CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(creds, context.getVariable(Variables.CORRELATION_ID)); + CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(credentials, context.getVariable(Variables.CORRELATION_ID)); List existingInstanceGuids = getExistingServiceGuids(context); diff --git a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java index dc39aba61f..c5e2bd99ee 100644 --- a/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java +++ b/multiapps-controller-process/src/main/java/org/cloudfoundry/multiapps/controller/process/steps/DetectDeployedMtaStep.java @@ -9,6 +9,7 @@ import org.apache.commons.lang3.StringUtils; import org.cloudfoundry.multiapps.controller.client.facade.CloudControllerClient; import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials; +import org.cloudfoundry.multiapps.controller.client.facade.oauth2.OAuth2AccessTokenWithAdditionalInfo; import org.cloudfoundry.multiapps.controller.core.cf.clients.CustomServiceKeysClient; import org.cloudfoundry.multiapps.controller.core.cf.clients.WebClientFactory; import org.cloudfoundry.multiapps.controller.core.cf.detect.DeployedMtaDetector; @@ -50,7 +51,7 @@ protected StepPhase executeStep(ProcessContext context) { detectBackupMta(mtaId, mtaNamespace, client, context); - var deployedServiceKeys = detectDeployedServiceKeys(mtaId, mtaNamespace, deployedMta, context); + List deployedServiceKeys = detectDeployedServiceKeys(mtaId, mtaNamespace, deployedMta, context); context.setVariable(Variables.DEPLOYED_MTA_SERVICE_KEYS, deployedServiceKeys); getStepLogger().debug(Messages.DEPLOYED_MTA_SERVICE_KEYS, SecureSerialization.toJson(deployedServiceKeys)); @@ -99,10 +100,10 @@ private List detectDeployedServiceKeys(String mtaId, Stri .orElse(List.of()); String spaceGuid = context.getVariable(Variables.SPACE_GUID); String userGuid = context.getVariable(Variables.USER_GUID); - var token = tokenService.getToken(userGuid); - var creds = new CloudCredentials(token, true); + OAuth2AccessTokenWithAdditionalInfo token = tokenService.getToken(userGuid); + CloudCredentials credentials = new CloudCredentials(token, true); - CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(creds, context.getVariable(Variables.CORRELATION_ID)); + CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(credentials, context.getVariable(Variables.CORRELATION_ID)); return serviceKeysClient.getServiceKeysByMetadataAndManagedServices( spaceGuid, mtaId, mtaNamespace, deployedManagedMtaServices