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..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 @@ -3,7 +3,8 @@ 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 org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceType; @@ -29,45 +30,87 @@ public CustomServiceKeysClient(ApplicationConfiguration configuration, WebClient super(configuration, webClientFactory, credentials, correlationId); } - public List getServiceKeysByMetadataAndGuids(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(); - - return new CustomControllerClientErrorHandler().handleErrorsOrReturnResult( - () -> getServiceKeysByMetadataInternal(labelSelector, services)); + public List getServiceKeysByMetadataAndExistingGuids( + String spaceGuid, + String mtaId, + String mtaNamespace, + List existingServiceGuids) { + + String labelSelector = buildMtaMetadataLabelSelector(spaceGuid, mtaId, mtaNamespace); + + List allServiceGuids = existingServiceGuids.stream() + .filter(Objects::nonNull) + .toList(); + + if (allServiceGuids.isEmpty()) { + return List.of(); + } + + return new CustomControllerClientErrorHandler() + .handleErrorsOrReturnResult( + () -> 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(",")); + public List getServiceKeysByMetadataAndManagedServices( + String spaceGuid, + String mtaId, + String mtaNamespace, + List services) { + + String labelSelector = buildMtaMetadataLabelSelector(spaceGuid, mtaId, mtaNamespace); + + List managedGuids = extractManagedServiceGuids(services); + + if (managedGuids.isEmpty()) { + return List.of(); } - return getListOfResources(new ServiceKeysResponseMapper(managedServices), SERVICE_KEYS_BY_METADATA_SELECTOR_URI + uriSuffix, + + return new CustomControllerClientErrorHandler() + .handleErrorsOrReturnResult( + () -> getServiceKeysByMetadataInternal(labelSelector, managedGuids) + ); + } + + 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(); + } + + 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 +119,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 +140,4 @@ public Map getIncludedServiceInstancesMapping() { } } -} +} \ No newline at end of file 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..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 @@ -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 (StringUtils.isBlank(serviceInstanceName)) { + 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..c58b506b36 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() { @@ -64,6 +68,13 @@ static Stream testComputeNamespacedNameWithLength() { "long-long-name-long-long-name-long-long-nam18cc4f54-limit-idle")); } + static Stream serviceInstanceNameCases() { + return Stream.of(Arguments.of("resource-name", "service-name-from-param", "service-name-from-param"), + Arguments.of("resource-name-1", null, "resource-name-1"), + Arguments.of("resource-name-2", " ", "resource-name-2"), + Arguments.of("resource-name-3", "", "resource-name-3")); + } + @ParameterizedTest @MethodSource void testGetNameWithProperLength(String name, int maxLength, String expectedName) { @@ -94,4 +105,25 @@ void testComputeNamespacedNameWithLength(String name, String namespace, boolean NameUtil.computeNamespacedNameWithLength(name, namespace, applyNamespace, applyNamespaceAsSuffix, maxLength)); } + @ParameterizedTest + @MethodSource + void serviceInstanceNameCases(String resourceName, String serviceNameParam, String expected) { + Resource resource = createResource(resourceName, serviceNameParam); + String serviceInstanceName = NameUtil.getServiceInstanceNameOrDefault(resource); + + assertEquals(expected, serviceInstanceName); + } + + private Resource createResource(String resourceName, String serviceInstanceName) { + Resource resource = Resource.createV3(); + resource.setName(resourceName); + + Map params = new HashMap<>(); + if (serviceInstanceName != null) { + params.put(SupportedParameters.SERVICE_NAME, serviceInstanceName); + } + resource.setParameters(params); + + return resource; + } } 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/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..82f4838678 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,21 +1,30 @@ 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; +import java.util.stream.Stream; import jakarta.inject.Inject; import jakarta.inject.Named; 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.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; +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 +32,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 +59,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 +78,20 @@ 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); + addDetectedExistingServiceKeysToDetectedManagedKeys(context); + // Get module sets: DeployedMta deployedMta = context.getVariable(Variables.DEPLOYED_MTA); List deployedApplications = (deployedMta != null) ? deployedMta.getApplications() : Collections.emptyList(); @@ -331,4 +354,90 @@ private List getDomainsFromApps(ProcessContext context, DeploymentDescri return new ArrayList<>(domains); } + private void addDetectedExistingServiceKeysToDetectedManagedKeys(ProcessContext context) { + String mtaId = context.getVariable(Variables.MTA_ID); + String mtaNamespace = context.getVariable(Variables.MTA_NAMESPACE); + + 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); + OAuth2AccessTokenWithAdditionalInfo token = tokenService.getToken(userGuid); + CloudCredentials credentials = new CloudCredentials(token); + + CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(credentials, 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.parallelStream() + .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/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); 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..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)); @@ -94,14 +95,19 @@ 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); + OAuth2AccessTokenWithAdditionalInfo token = tokenService.getToken(userGuid); + CloudCredentials credentials = new CloudCredentials(token, true); - CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(creds, context.getVariable(Variables.CORRELATION_ID)); - return serviceKeysClient.getServiceKeysByMetadataAndGuids(spaceGuid, mtaId, mtaNamespace, deployedMtaServices); + CustomServiceKeysClient serviceKeysClient = getCustomServiceKeysClient(credentials, context.getVariable(Variables.CORRELATION_ID)); + + return serviceKeysClient.getServiceKeysByMetadataAndManagedServices( + spaceGuid, mtaId, mtaNamespace, deployedManagedMtaServices + ); } private void logNoMtaDeployedDetected(String mtaId, String 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..9359af4976 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 @@ -4,24 +4,37 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.stream.Stream; import com.fasterxml.jackson.core.type.TypeReference; import org.cloudfoundry.multiapps.common.test.TestUtil; import org.cloudfoundry.multiapps.common.test.Tester.Expectation; import org.cloudfoundry.multiapps.common.util.JsonUtil; +import org.cloudfoundry.multiapps.controller.client.facade.CloudCredentials; import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudServiceKey; +import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudMetadata; +import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudServiceInstance; +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.ModulesCloudModelBuilderContentCalculator; 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.helpers.ModuleToDeployHelper; import org.cloudfoundry.multiapps.controller.core.model.DeployedMta; +import org.cloudfoundry.multiapps.controller.core.model.DeployedMtaServiceKey; +import org.cloudfoundry.multiapps.controller.core.model.ImmutableDeployedMtaServiceKey; +import org.cloudfoundry.multiapps.controller.core.model.SupportedParameters; +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; import org.cloudfoundry.multiapps.controller.process.variables.Variables; import org.cloudfoundry.multiapps.mta.model.DeploymentDescriptor; import org.cloudfoundry.multiapps.mta.model.Module; +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; @@ -29,13 +42,27 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; class BuildCloudDeployModelStepTest extends SyncFlowableStepTest { private static final Integer MTA_MAJOR_SCHEMA_VERSION = 2; + private static final String TEST_MTA_ID = "mta-id"; + private static final String TEST_MTA_NAMESPACE = "mta-namespace"; + private static final String TEST_SPACE_GUID = "space-guid"; + + private static final String TEST_RESOURCE_NAME = "test-resource-name"; + private static final String TEST_RESOURCE_NAME_2 = "test-resource-name-2"; + private static final DeploymentDescriptor DEPLOYMENT_DESCRIPTOR = DescriptorTestUtil.loadDeploymentDescriptor("build-cloud-model.yaml", BuildCloudDeployModelStepTest.class); @@ -53,6 +80,10 @@ class BuildCloudDeployModelStepTest extends SyncFlowableStepTest all = context.getVariable(Variables.DEPLOYED_MTA_SERVICE_KEYS); + + assertEquals(2, all.size()); + assertTrue(all.contains(deployedKey1)); + assertTrue(all.contains(deployedKey2)); + + } + + private DeploymentDescriptor createDescriptorWithExistingServicesForKeysTest() { + Resource resource1 = createExistingServiceResource(TEST_RESOURCE_NAME); + Resource resource2 = createExistingServiceResource(TEST_RESOURCE_NAME_2); + + DeploymentDescriptor descriptor = DeploymentDescriptor.createV3(); + descriptor.setResources(List.of(resource1, resource2)); + + return descriptor; + } + + private Resource createExistingServiceResource(String name) { + Resource resource = Resource.createV3(); + resource.setName(name); + + resource.setParameters(Map.of( + SupportedParameters.TYPE, ResourceType.EXISTING_SERVICE.toString(), + SupportedParameters.SERVICE_NAME, name + )); + return resource; + } + + private ImmutableDeployedMtaServiceKey createDeployedKey(String resourceName) { + return ImmutableDeployedMtaServiceKey.builder() + .resourceName(resourceName) + .metadata(ImmutableCloudMetadata.of(UUID.randomUUID())) + .build(); + } + + private ImmutableCloudServiceInstance createCfInstance(String name) { + return ImmutableCloudServiceInstance.builder() + .name(name) + .metadata(ImmutableCloudMetadata.of(UUID.randomUUID())) + .build(); + } } 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..9d9c09c8db 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 @@ -67,8 +67,8 @@ void testExecuteWithDeployedMta() { 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(customClientMock.getServiceKeysByMetadataAndManagedServices(Mockito.eq(SPACE_GUID), Mockito.eq(MTA_ID), Mockito.isNull(), + Mockito.eq(deployedMta.getServices()))).thenReturn(deployedKeys); step.execute(execution); @@ -82,8 +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(SPACE_GUID, MTA_ID, null, - Collections.emptyList())).thenReturn(Collections.emptyList()); + when(customClientMock.getServiceKeysByMetadataAndManagedServices(SPACE_GUID, MTA_ID, null, + Collections.emptyList())).thenReturn(Collections.emptyList()); step.execute(execution); @@ -174,4 +174,4 @@ protected CustomServiceKeysClient getCustomServiceKeysClient(CloudCredentials cr } } -} +} \ No newline at end of file