diff --git a/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/instance/EurekaServiceInstanceRequest.java b/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/instance/EurekaServiceInstanceRequest.java new file mode 100644 index 0000000000..900bfc7671 --- /dev/null +++ b/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/instance/EurekaServiceInstanceRequest.java @@ -0,0 +1,25 @@ +/* + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + */ + +package org.zowe.apiml.apicatalog.instance; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class EurekaServiceInstanceRequest { + + private String serviceId; + private String eurekaRequestUrl; + private String username; + private String password; + +} diff --git a/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/instance/InstanceRetrievalService.java b/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/instance/InstanceRetrievalService.java index 65c3a73e99..cb8a7430b3 100644 --- a/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/instance/InstanceRetrievalService.java +++ b/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/instance/InstanceRetrievalService.java @@ -17,7 +17,6 @@ import com.netflix.discovery.converters.jackson.EurekaJsonJacksonCodec; import com.netflix.discovery.shared.Applications; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.tuple.Pair; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpHeaders; @@ -78,17 +77,18 @@ public InstanceInfo getInstanceInfo(@NotBlank(message = "Service Id must be supp return null; } - List>> requestInfoList = constructServiceInfoQueryRequest(serviceId, false); + List eurekaServiceInstanceRequests = constructServiceInfoQueryRequest(serviceId, false); // iterate over list of discovery services, return at first success - for (Pair> requestInfo : requestInfoList) { + for (EurekaServiceInstanceRequest eurekaServiceInstanceRequest : eurekaServiceInstanceRequests) { // call Eureka REST endpoint to fetch single or all Instances try { - String responseBody = queryDiscoveryForInstances(requestInfo); + String responseBody = queryDiscoveryForInstances(eurekaServiceInstanceRequest); if (responseBody != null) { return extractSingleInstanceFromApplication(serviceId, responseBody); } } catch (Exception e) { - log.debug("Error getting instance info from {}, error message: {}", requestInfo.getLeft(), e.getMessage()); + log.debug("Error obtaining instance information from {}, error message: {}", + eurekaServiceInstanceRequest.getEurekaRequestUrl(), e.getMessage()); } } String msg = "An error occurred when trying to get instance info for: " + serviceId; @@ -103,13 +103,13 @@ public InstanceInfo getInstanceInfo(@NotBlank(message = "Service Id must be supp */ public Applications getAllInstancesFromDiscovery(boolean delta) { - List>> requestInfoList = constructServiceInfoQueryRequest(null, delta); - for (Pair> requestInfo : requestInfoList) { + List requestInfoList = constructServiceInfoQueryRequest(null, delta); + for (EurekaServiceInstanceRequest requestInfo : requestInfoList) { try { String responseBody = queryDiscoveryForInstances(requestInfo); return extractApplications(responseBody); } catch (Exception e) { - log.debug("Not able to contact discovery service: " + requestInfo.getKey(), e); + log.debug("Not able to contact discovery service: {}", requestInfo.getEurekaRequestUrl(), e); } } // call Eureka REST endpoint to fetch single or all Instances @@ -139,12 +139,12 @@ private Applications extractApplications(String responseBody) { /** * Query Discovery * - * @param requestInfo information used to query the discovery service + * @param eurekaServiceInstanceRequest information used to query the discovery service * @return ResponseEntity query response */ - private String queryDiscoveryForInstances(Pair> requestInfo) throws IOException { - HttpGet httpGet = new HttpGet(requestInfo.getLeft()); - for (Header header : createRequestHeader(requestInfo.getRight())) { + private String queryDiscoveryForInstances(EurekaServiceInstanceRequest eurekaServiceInstanceRequest) throws IOException { + HttpGet httpGet = new HttpGet(eurekaServiceInstanceRequest.getEurekaRequestUrl()); + for (Header header : createRequestHeader(eurekaServiceInstanceRequest)) { httpGet.setHeader(header); } CloseableHttpResponse response = httpClient.execute(httpGet); @@ -157,9 +157,14 @@ private String queryDiscoveryForInstances(Pair> req if (statusCode >= HttpStatus.SC_OK && statusCode < HttpStatus.SC_MULTIPLE_CHOICES) { return responseBody; } + apimlLog.log("org.zowe.apiml.apicatalog.serviceRetrievalRequestFailed", - statusCode, response.getStatusLine() != null ? response.getStatusLine().getReasonPhrase() : responseBody, - requestInfo.getLeft()); + eurekaServiceInstanceRequest.getServiceId(), + eurekaServiceInstanceRequest.getEurekaRequestUrl(), + statusCode, + response.getStatusLine() != null ? response.getStatusLine().getReasonPhrase() : responseBody + ); + return null; } @@ -195,9 +200,9 @@ private InstanceInfo extractSingleInstanceFromApplication(String serviceId, Stri * @param serviceId optional service id * @return request information */ - private List>> constructServiceInfoQueryRequest(String serviceId, boolean getDelta) { + private List constructServiceInfoQueryRequest(String serviceId, boolean getDelta) { String[] discoveryServiceUrls = discoveryConfigProperties.getLocations(); - List>> discoveryPairs = new ArrayList<>(discoveryServiceUrls.length); + List eurekaServiceInstanceRequests = new ArrayList<>(discoveryServiceUrls.length); for (String discoveryUrl : discoveryServiceUrls) { String discoveryServiceLocatorUrl = discoveryUrl + APPS_ENDPOINT; if (getDelta) { @@ -211,17 +216,20 @@ private List>> constructServiceInfoQueryReques String eurekaUsername = discoveryConfigProperties.getEurekaUserName(); String eurekaUserPassword = discoveryConfigProperties.getEurekaUserPassword(); - Pair discoveryServiceCredentials = Pair.of(eurekaUsername, eurekaUserPassword); - - log.debug("Eureka credentials retrieved for user: {} {}", - eurekaUsername, - (!eurekaUserPassword.isEmpty() ? "*******" : "NO PASSWORD") - ); - - log.debug("Checking instance info from: " + discoveryServiceLocatorUrl); - discoveryPairs.add(Pair.of(discoveryServiceLocatorUrl, discoveryServiceCredentials)); + log.debug("Querying instance information of the service {} from the URL {} with the user {} and password {}", + serviceId, discoveryServiceLocatorUrl, eurekaUsername, + eurekaUserPassword.isEmpty() ? "NO PASSWORD" : "*******"); + + EurekaServiceInstanceRequest eurekaServiceInstanceRequest = EurekaServiceInstanceRequest.builder() + .serviceId(serviceId) + .eurekaRequestUrl(discoveryServiceLocatorUrl) + .username(eurekaUsername) + .password(eurekaUserPassword) + .build(); + eurekaServiceInstanceRequests.add(eurekaServiceInstanceRequest); } - return discoveryPairs; + + return eurekaServiceInstanceRequests; } /** @@ -229,11 +237,11 @@ private List>> constructServiceInfoQueryReques * * @return HTTP Headers */ - private List
createRequestHeader(Pair credentials) { + private List
createRequestHeader(EurekaServiceInstanceRequest eurekaServiceInstanceRequest) { List
headers = new ArrayList<>(); - if (credentials != null && credentials.getLeft() != null && credentials.getRight() != null) { - String basicToken = "Basic " + Base64.getEncoder().encodeToString((credentials.getLeft() + ":" - + credentials.getRight()).getBytes()); + if (eurekaServiceInstanceRequest != null && eurekaServiceInstanceRequest.getUsername() != null && eurekaServiceInstanceRequest.getPassword() != null) { + String basicToken = "Basic " + Base64.getEncoder().encodeToString((eurekaServiceInstanceRequest.getUsername() + ":" + + eurekaServiceInstanceRequest.getPassword()).getBytes()); headers.add(new BasicHeader(HttpHeaders.AUTHORIZATION, basicToken)); } headers.add(new BasicHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)); diff --git a/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/services/status/APIDocRetrievalService.java b/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/services/status/APIDocRetrievalService.java index 1c252d63cf..a592283009 100644 --- a/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/services/status/APIDocRetrievalService.java +++ b/api-catalog-services/src/main/java/org/zowe/apiml/apicatalog/services/status/APIDocRetrievalService.java @@ -36,6 +36,7 @@ import org.zowe.apiml.eurekaservice.client.util.EurekaMetadataParser; import org.zowe.apiml.product.gateway.GatewayClient; import org.zowe.apiml.product.gateway.GatewayConfigProperties; +import org.zowe.apiml.product.instance.InstanceInitializationException; import org.zowe.apiml.product.routing.RoutedService; import org.zowe.apiml.product.routing.RoutedServices; @@ -395,11 +396,17 @@ private ApiInfo findApi(List apiInfos, String apiVersion) { } private InstanceInfo getInstanceInfo(String serviceId) { - InstanceInfo instanceInfo = instanceRetrievalService.getInstanceInfo(serviceId); - if (instanceInfo == null) { - throw new ApiDocNotFoundException("Could not load instance information for service " + serviceId + "."); + String errMsg = "Could not load instance information for service " + serviceId + "."; + try { + InstanceInfo instanceInfo = instanceRetrievalService.getInstanceInfo(serviceId); + if (instanceInfo == null) { + throw new ApiDocNotFoundException(errMsg); + } + + return instanceInfo; + } catch (InstanceInitializationException e) { + throw new ApiDocNotFoundException(errMsg, e); } - return instanceInfo; } /** diff --git a/api-catalog-services/src/main/resources/apicatalog-log-messages.yml b/api-catalog-services/src/main/resources/apicatalog-log-messages.yml index c3c4d088cd..c830720b45 100644 --- a/api-catalog-services/src/main/resources/apicatalog-log-messages.yml +++ b/api-catalog-services/src/main/resources/apicatalog-log-messages.yml @@ -7,9 +7,9 @@ messages: - key: org.zowe.apiml.apicatalog.serviceRetrievalRequestFailed number: ZWEAC100 type: WARNING - text: "Could not retrieve all service info from discovery -- %s -- %s -- %s" - reason: "The response from The Discovery Service about the registered instances returned an error or empty body." - action: "Make sure the Discovery Service is up and running. If the http response error code refers to a security issue, check that both the Discovery Service and Catalog are running with the https scheme and that security is configured properly." + text: "Could not retrieve information about service %s from the Discovery Service. Requested URL: %s. Response received: status code: %s, body: %s" + reason: "The response from The Discovery Service about the registered service instances returned an error or empty body." + action: "Make sure the Discovery Service and requested service are up and running. If the HTTP response error code refers to a security issue, make sure that security configuration is correct." - key: org.zowe.apiml.apicatalog.serviceRetrievalParsingFailed number: ZWEAC101