Skip to content
Snippets Groups Projects
Commit 26ebc4d5 authored by Alexander Lovett's avatar Alexander Lovett
Browse files

Merge branch 'feature/LGR-72' into 'develop'

[LGR-72] - Bug fixes

See merge request alexander.lovett/looking-glass-service!11
parents e0d59acc de0d23b2
No related branches found
No related tags found
No related merge requests found
Showing
with 91 additions and 23 deletions
# 2.0.14
* [LGR-73](https://jira.software.geant.org/browse/LGR-73) - Remove router endpoint
* [LGR-72](https://jira.software.geant.org/browse/LGR-72) - Check user is authenticated prior to executing commands on internal routers
# 2.0.13
* [LGR-70](https://jira.software.geant.org/browse/LGR-70) - Pull UI out of jar
......
......@@ -145,8 +145,7 @@
<line>After=syslog.target</line>
<line>[Service]</line>
<line>User=${artifactId}</line>
<line>ExecStart=/opt/${artifactId}/latest/bin/${artifactId}.${project.packaging}
--spring.config.location=file:/opt/${artifactId}/${version}/config/application.yml
<line>ExecStart=/opt/${artifactId}/latest/bin/${artifactId}.${project.packaging} --spring.config.location=file:/opt/${artifactId}/${version}/config/application.yml
</line>
<line>StandardOutput=syslog</line>
<line>StandardError=syslog</line>
......
package org.geant.lgservice;
import org.geant.lgservice.infrastructure.rest.inventoryprovider.Config;
import org.geant.lgservice.infrastructure.rest.inventoryprovider.InventoryProviderConfig;
import org.geant.lgservice.infrastructure.ssh.SSHConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
@SpringBootApplication
@Import({
org.geant.lgservice.infrastructure.rest.inventoryprovider.Config.class,
org.geant.lgservice.infrastructure.ssh.Config.class
InventoryProviderConfig.class,
SSHConfig.class
})
public class LookingGlassServiceApplication {
......
package org.geant.lgservice.infrastructure.rest.inventoryprovider;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.geant.lgservice.domain.RouterRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
@Configuration
public class Config {
public class InventoryProviderConfig {
@Bean
public RouterRepository routerRepository(@Value("${inventoryprovider.baseUrl}")String baseUrl) {
return InventoryProviderRouterRepository.builder().baseUrl(baseUrl).build();
return InventoryProviderRouterRepository.builder().baseUrl(baseUrl)
.client(new OkHttpClient.Builder().addInterceptor(new OkHttpLogger()).build()).build();
}
@Slf4j
private static class OkHttpLogger implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
log.info("Making request to {} with headers {}", request.url().toString(), request.headers());
Response response = chain.proceed(request);
long contentLength = response.body().contentLength();
log.info("Response recieved with status {} and body {}", response.code(), response.peekBody(contentLength >= 0 ? contentLength : Long.MAX_VALUE).string());
return response;
}
}
}
......@@ -7,7 +7,9 @@ import com.google.common.collect.ImmutableMap;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.geant.lgservice.domain.Router;
import org.geant.lgservice.domain.RouterRepository;
import org.geant.lgservice.exceptions.TechnicalException;
......@@ -23,8 +25,11 @@ import retrofit2.http.GET;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.nio.charset.Charset.defaultCharset;
import static org.geant.lgservice.domain.Router.Access.INTERNAL;
......@@ -63,9 +68,22 @@ public class InventoryProviderRouterRepository implements RouterRepository {
@Builder
public InventoryProviderRouterRepository(String baseUrl, OkHttpClient client) {
OkHttpClient.Builder builder =
(client != null ? client.newBuilder() : new OkHttpClient.Builder());
List<Interceptor> existingInterceptors = builder.interceptors();
List<Interceptor> interceptors = Stream.concat(
Stream.of((Interceptor.Chain chain) -> chain.proceed(chain.request().newBuilder()
.addHeader("Accept", "application/json")
.build())),
existingInterceptors.stream()).collect(Collectors.toList());
existingInterceptors.removeIf(interceptors::contains);
existingInterceptors.addAll(interceptors);
this.inventoryProvider = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(client != null ? client : new OkHttpClient())
.client(builder.build())
.addConverterFactory(JacksonConverterFactory.create())
.build()
.create(InventoryProvider.class);
......
......@@ -30,7 +30,7 @@ public class ConnectionFactory {
} catch (IOException e) {
throw new TechnicalException(e);
}
log.info("Connection for {} created");
log.info("Connection for {} created", hostname);
return connection;
}
}
......@@ -8,6 +8,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static org.geant.lgservice.infrastructure.ssh.SSHHost.ConnectionStateListener.State.DISCONNECTED;
import static org.geant.lgservice.infrastructure.ssh.SSHHost.ConnectionStateListener.State.ERROR;
@Slf4j
@Component
......@@ -35,9 +36,11 @@ public class ConnectionManager implements SSHHost.ConnectionStateListener {
@Override
public void stateChanged(SSHHost host, State state) {
synchronized (this) {
if (state.equals(DISCONNECTED)) {
log.info("host [{}] state changed to [{}]", host, state);
if (state.equals(DISCONNECTED) || state.equals(ERROR)) {
hosts.remove(host);
}
log.info("currently active connections: [{}]", hosts.keySet());
}
}
}
......@@ -7,7 +7,7 @@ import org.springframework.context.annotation.Configuration;
import java.io.File;
@Configuration
public class Config {
public class SSHConfig {
@Bean
public ConnectionFactory connectionFactory(
......
......@@ -12,10 +12,11 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.HashSet;
import java.util.Optional;
import java.util.stream.Collectors;
import static ch.ethz.ssh2.ChannelCondition.EXIT_STATUS;
import static org.geant.lgservice.infrastructure.ssh.SSHHost.ConnectionStateListener.State.DISCONNECTED;
import static org.geant.lgservice.infrastructure.ssh.SSHHost.ConnectionStateListener.State.ERROR;
@Slf4j
public class SSHHost implements ConnectionMonitor {
......@@ -38,25 +39,25 @@ public class SSHHost implements ConnectionMonitor {
public String execute(String command) {
Session session = null;
try {
log.debug("opening session on connection [{}] with host [{}]", connection, hostname());
session = connection.openSession();
log.debug("Session [{}] opened", session);
log.debug("sending command [{}] to host [{}]", command, hostname());
session.execCommand(command);
log.debug("command [{}] sent to host [{}]", command, hostname());
session.waitForCondition(EXIT_STATUS, 0);
int exitStatus = session.getExitStatus();
int exitStatus = Optional.of(session).map(Session::getExitStatus).orElse(0);
log.debug("Exit status [{}] recieved", exitStatus);
InputStream response = exitStatus == 0 ? session.getStdout() : session.getStderr();
InputStream response = exitStatus != 0 ? session.getStderr() : session.getStdout();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(response))) {
return reader.lines().collect(Collectors.joining("\n"));
}
} catch (IOException e) {
triggerStateChangeListeners(ERROR);
connection.close();
throw new TechnicalException(e);
} finally {
if (session != null) {
session.close();
}
}
}
......@@ -69,18 +70,23 @@ public class SSHHost implements ConnectionMonitor {
return this;
}
private void triggerStateChangeListeners(ConnectionStateListener.State state) {
connectionStateListeners
.forEach(connectionStateListener -> connectionStateListener.stateChanged(this, state));
}
@Override
public void connectionLost(Throwable reason) {
log.warn("Host [{}] lost connection: ", connection.getHostname(), reason);
connectionStateListeners
.forEach(connectionStateListener -> connectionStateListener.stateChanged(this, DISCONNECTED));
triggerStateChangeListeners(DISCONNECTED);
}
@FunctionalInterface
public interface ConnectionStateListener {
enum State {
DISCONNECTED
DISCONNECTED,
ERROR
}
void stateChanged(SSHHost host, State state);
......
package org.geant.lgservice.interfaces.rest;
import lombok.extern.slf4j.Slf4j;
import org.geant.lgservice.exceptions.BusinessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
......@@ -7,13 +8,13 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@Slf4j
@ControllerAdvice
public class BusinessExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(BusinessException.class)
protected ResponseEntity<Object> handleBusinessException (BusinessException ex) {
log.info("Business error: {}", ex.getMessage());
return ResponseEntity.status(HttpStatus.valueOf(ex.getReason().name())).build();
}
}
......@@ -6,11 +6,11 @@ import lombok.Setter;
@NoArgsConstructor
@Setter
@Getter
public class Command {
private String name;
@Getter
private String value;
private String description;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment