72 lines
4.0 KiB
Java
72 lines
4.0 KiB
Java
package eu.openaire.urls_controller.services;
|
|
|
|
import eu.openaire.urls_controller.controllers.UrlsController;
|
|
import eu.openaire.urls_controller.util.UriBuilder;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
import org.springframework.http.HttpStatus;
|
|
import org.springframework.http.ResponseEntity;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.web.client.HttpServerErrorException;
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
|
import java.net.ConnectException;
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
@Service
|
|
public class ShutdownServiceImpl implements ShutdownService {
|
|
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(ShutdownServiceImpl.class);
|
|
|
|
// Private Addresses, according to RFC 1918: https://www.rfc-editor.org/rfc/rfc1918
|
|
private static final Pattern PRIVATE_IP_ADDRESSES_RFC_1918 = Pattern.compile("(?:10.|172.(?:1[6-9]|2[0-9]|3[0-1])|192.168.)[0-9.]+");
|
|
|
|
|
|
public ResponseEntity<?> passSecurityChecks(String remoteAddr, String initMsg)
|
|
{
|
|
// In case the Controller is running inside a docker container, and we want to send the "shutdownServiceRequest" from the terminal (with curl), without entering inside the container,
|
|
// then the request will appear coming from a local (private) IP, instead of localhost.
|
|
if ( ! (remoteAddr.equals("127.0.0.1") || remoteAddr.equals(UriBuilder.ip) || PRIVATE_IP_ADDRESSES_RFC_1918.matcher(remoteAddr).matches()) ) {
|
|
logger.error(initMsg + "The request came from another IP: " + remoteAddr + " | while the Controller has the IP: " + UriBuilder.ip);
|
|
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
|
|
}
|
|
return null; // The checks are passing.
|
|
}
|
|
|
|
|
|
private static final RestTemplate restTemplate = new RestTemplate();
|
|
|
|
public boolean postShutdownOrCancelRequestToWorker(String workerId, String workerIp, boolean shouldCancel)
|
|
{
|
|
String url = "http://" + workerIp + ":1881/api/" + (shouldCancel ? "cancelShutdownWorker" : "shutdownWorker");
|
|
try {
|
|
ResponseEntity<?> responseEntity = restTemplate.postForEntity(url, null, String.class);
|
|
int responseCode = responseEntity.getStatusCodeValue();
|
|
if ( responseCode != HttpStatus.OK.value() ) {
|
|
logger.error("HTTP-Connection problem with the submission of the \"postShutdownOrCancelRequestToWorker\" of worker \"" + workerId + "\"! Error-code was: " + responseCode);
|
|
return false;
|
|
} else
|
|
return true;
|
|
} catch (HttpServerErrorException hsee) {
|
|
logger.error("The Worker \"" + workerId + "\" failed to handle the \"postShutdownOrCancelRequestToWorker\": " + hsee.getMessage());
|
|
return false;
|
|
} catch (Exception e) {
|
|
// The Spring RestTemplate may return a "ResourceAccessException", but the actual cause will has to be identified, in order to set the worker as shutdown.
|
|
Throwable cause = e.getCause(); // No need to check explicitly for null.
|
|
if ( cause instanceof ConnectException ) { // This includes the "ConnectException".
|
|
logger.error("Got a \"ConnectException\" when doing a \"postShutdownOrCancelRequestToWorker\", to the Worker: \"" + workerId + "\". | Will register this worker as \"shutdown\".\n" + cause.getMessage());
|
|
UrlsController.workersInfoMap.get(workerId).setHasShutdown(true);
|
|
} else {
|
|
logger.error("Error for \"postShutdownOrCancelRequestToWorker\", to the Worker: " + workerId, e);
|
|
// TODO - What should we do? If there was some error from the Controller, side, it does not mean that the worker has shutdown..
|
|
// For now, let's handle that case manually, by check with that specific worker and sending it a shutdownRequest from inside its VM.
|
|
// Then the Worker will automatically send a "shutdownReport" to the Controller, causing it to shutdown (when all other workers have shutdown as well).
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|