Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove stacktrace from Catalog log when service is down #3019

Merged
merged 7 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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;
JirkaAichler marked this conversation as resolved.
Show resolved Hide resolved

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -78,17 +77,18 @@ public InstanceInfo getInstanceInfo(@NotBlank(message = "Service Id must be supp
return null;
}

List<Pair<String, Pair<String, String>>> requestInfoList = constructServiceInfoQueryRequest(serviceId, false);
List<EurekaServiceInstanceRequest> eurekaServiceInstanceRequests = constructServiceInfoQueryRequest(serviceId, false);
// iterate over list of discovery services, return at first success
for (Pair<String, Pair<String, String>> 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;
Expand All @@ -103,13 +103,13 @@ public InstanceInfo getInstanceInfo(@NotBlank(message = "Service Id must be supp
*/
public Applications getAllInstancesFromDiscovery(boolean delta) {

List<Pair<String, Pair<String, String>>> requestInfoList = constructServiceInfoQueryRequest(null, delta);
for (Pair<String, Pair<String, String>> requestInfo : requestInfoList) {
List<EurekaServiceInstanceRequest> 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);
JirkaAichler marked this conversation as resolved.
Show resolved Hide resolved
}
}
// call Eureka REST endpoint to fetch single or all Instances
Expand Down Expand Up @@ -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<String> query response
*/
private String queryDiscoveryForInstances(Pair<String, Pair<String, String>> 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);
Expand All @@ -157,9 +157,14 @@ private String queryDiscoveryForInstances(Pair<String, Pair<String, String>> 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;
}

Expand Down Expand Up @@ -195,9 +200,9 @@ private InstanceInfo extractSingleInstanceFromApplication(String serviceId, Stri
* @param serviceId optional service id
* @return request information
*/
private List<Pair<String, Pair<String, String>>> constructServiceInfoQueryRequest(String serviceId, boolean getDelta) {
private List<EurekaServiceInstanceRequest> constructServiceInfoQueryRequest(String serviceId, boolean getDelta) {
String[] discoveryServiceUrls = discoveryConfigProperties.getLocations();
List<Pair<String, Pair<String, String>>> discoveryPairs = new ArrayList<>(discoveryServiceUrls.length);
List<EurekaServiceInstanceRequest> eurekaServiceInstanceRequests = new ArrayList<>(discoveryServiceUrls.length);
for (String discoveryUrl : discoveryServiceUrls) {
String discoveryServiceLocatorUrl = discoveryUrl + APPS_ENDPOINT;
if (getDelta) {
Expand All @@ -211,29 +216,32 @@ private List<Pair<String, Pair<String, String>>> constructServiceInfoQueryReques
String eurekaUsername = discoveryConfigProperties.getEurekaUserName();
String eurekaUserPassword = discoveryConfigProperties.getEurekaUserPassword();

Pair<String, String> 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;
}

/**
* Create HTTP headers
*
* @return HTTP Headers
*/
private List<Header> createRequestHeader(Pair<String, String> credentials) {
private List<Header> createRequestHeader(EurekaServiceInstanceRequest eurekaServiceInstanceRequest) {
List<Header> 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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -395,11 +396,17 @@ private ApiInfo findApi(List<ApiInfo> 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;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 %sfrom the Discovery Service. Requested URL: %s. Response received: status code: %s, body: %s"
JirkaAichler marked this conversation as resolved.
Show resolved Hide resolved
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
Expand Down
Loading