Add sample parksmap app and grid template.

This commit is contained in:
2024-03-14 10:50:09 +13:00
parent 3154613dad
commit 162f9477db
55 changed files with 32549 additions and 1 deletions

View File

@ -0,0 +1,18 @@
package com.openshift.evg.roadshow;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
/**
* Created by jmorales on 24/08/16.
*/
@SpringBootApplication
@ComponentScan(basePackages = "com.openshift.evg.roadshow.rest")
public class ParksMapApplication {
public static void main(String[] args) {
SpringApplication.run(ParksMapApplication.class, args);
}
}

View File

@ -0,0 +1,146 @@
package com.openshift.evg.roadshow.rest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.openshift.evg.roadshow.rest.gateway.helpers.EndpointRegistrar;
import com.openshift.evg.roadshow.rest.gateway.helpers.EndpointWatcher;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.openshift.client.DefaultOpenShiftClient;
import io.fabric8.openshift.client.OpenShiftClient;
public abstract class AbstractResourceWatcher<T extends HasMetadata> implements Watcher<T> {
private static final Logger logger = LoggerFactory.getLogger(AbstractResourceWatcher.class);
private String currentNamespace = null;
private Watch watch;
private OpenShiftClient client = new DefaultOpenShiftClient();;
private EndpointRegistrar endpointRegistrar;
private Map<String, EndpointWatcher> endpointsWatchers = new HashMap<String, EndpointWatcher>();
@Override
public void eventReceived(Action action, T t) {
logger.info("Action: {}, Resource: {}", action, t);
String resourceName = t.getMetadata().getName();
// }
if (action == Action.ADDED) {
logger.info("Resource {} added", resourceName);
EndpointWatcher epW = endpointsWatchers.get(resourceName);
if (epW == null) {
epW = new EndpointWatcher(endpointRegistrar, client, currentNamespace, resourceName);
endpointsWatchers.put(resourceName, epW);
}
} else if (action == Action.DELETED) {
logger.info("Resource {} deleted", resourceName);
EndpointWatcher epW = endpointsWatchers.get(resourceName);
if (epW != null) {
epW.close();
endpointRegistrar.unregister(resourceName);
endpointsWatchers.remove(resourceName);
}
} else if (action == Action.MODIFIED) {
// TODO: Modification of a resource is cumbersome. Look into how to
// best implement this
EndpointWatcher epW = endpointsWatchers.get(resourceName);
endpointsWatchers.remove(resourceName);
endpointRegistrar.unregister(resourceName);
epW = new EndpointWatcher(endpointRegistrar, client, currentNamespace, resourceName);
endpointsWatchers.put(resourceName, epW);
} else if (action == Action.ERROR) {
logger.error("Resource ERRORED");
EndpointWatcher epW = endpointsWatchers.get(resourceName);
endpointsWatchers.remove(resourceName);
epW = new EndpointWatcher(endpointRegistrar, client, currentNamespace, resourceName);
endpointsWatchers.put(resourceName, epW);
}
}
/**
* This will get notified when Kubernetes client is closed
*
* @param e
*/
@Override
public void onClose(KubernetesClientException e) {
if (e != null) {
// This is when the client is closed
logger.error("[ERROR] There was an error in the client {}", e.getMessage());
init(endpointRegistrar);
} else {
logger.info("Closing this Watcher");
}
}
private void cleanUp() {
if (watch != null)
watch.close();
// If this watch has been closed, we create complete set of new watches
for (EndpointWatcher epWatcher : endpointsWatchers.values()) {
epWatcher.close();
}
endpointsWatchers.clear();
}
public void init(EndpointRegistrar endpointRegistrar) {
cleanUp();
// BackendsController
if (this.endpointRegistrar == null) {
this.endpointRegistrar = endpointRegistrar;
}
if (currentNamespace == null) {
currentNamespace = client.getNamespace();
}
logger.info("[INFO] {} is watching for resources started in namespace {} ", this.getClass().getName(),
currentNamespace);
try {
List<T> resources = listWatchedResources();
for (T resource : resources) {
String resourceName = resource.getMetadata().getName();
EndpointWatcher endpointWatcher = endpointsWatchers.get(resourceName);
if (endpointWatcher == null) {
endpointWatcher = new EndpointWatcher(endpointRegistrar, client, currentNamespace, resourceName);
endpointsWatchers.put(resourceName, endpointWatcher);
}
}
watch = doInit();
} catch (KubernetesClientException e) {
// If there is no proper permission, don't fail misserably
logger.error(
"Error initialiting application. Probably you need the appropriate permissions to view this namespace {}. {}",
currentNamespace, e.getMessage());
}
}
protected OpenShiftClient getOpenShiftClient() {
return client;
}
protected String getNamespace() {
return currentNamespace;
}
protected abstract List<T> listWatchedResources();
protected abstract Watch doInit();
protected abstract String getUrl(String resourceName);
}

View File

@ -0,0 +1,124 @@
package com.openshift.evg.roadshow.rest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.openshift.evg.roadshow.rest.gateway.ApiGatewayController;
import com.openshift.evg.roadshow.rest.gateway.DataGatewayController;
import com.openshift.evg.roadshow.rest.gateway.helpers.EndpointRegistrar;
import com.openshift.evg.roadshow.rest.gateway.model.Backend;
/**
* Backend controller. Every time a backend appears/dissapears in OpenShift
* it will send a notification to the web to show/hide the appropriate layer/map
* <p>
* Created by jmorales on 24/08/16.
*/
@RestController
@RequestMapping("/ws/backends")
public class BackendsController implements EndpointRegistrar {
private static final Logger logger = LoggerFactory.getLogger(BackendsController.class);
@Value("${test}")
private Boolean test;
@Autowired
private SimpMessagingTemplate messagingTemplate;
@Autowired
private ApiGatewayController apiGateway;
@Autowired
private DataGatewayController dataGateway;
@Autowired
private ServiceWatcher serviceWatcher;
@Autowired
private RouteWatcher routeWatcher;
private Map<String, Backend> registeredBackends = new HashMap<String, Backend>();
/**
* This method is used to start monitoring for services
*/
@RequestMapping(method = RequestMethod.GET, value = "/init")
@PostConstruct
public void init() {
routeWatcher.init(this);
serviceWatcher.init(this);
}
/**
* @param
* @return
*/
@RequestMapping(method = RequestMethod.GET, value = "/register", produces = "application/json")
public List<Backend> register(@RequestParam(value = "endpoint") String endpoint) {
logger.info("Backends.register endpoint at ({})", endpoint);
Backend newBackend = null;
String endpointUrl = routeWatcher.getUrl(endpoint); // try to find a route for endpoint
if (endpointUrl == null || endpointUrl.trim().equals("")) {
endpointUrl = serviceWatcher.getUrl(endpoint); // otherwise, find a service for endpoint
}
// Query for backend data.
if (endpoint != null) {
if ((newBackend = apiGateway.getFromRemote(endpointUrl)) != null) {
// TODO: BackendId should not be fetched from remote. For now I replace the remote one with the local one.
newBackend.setId(endpoint);
// Register the new backend
apiGateway.add(endpoint, endpointUrl);
dataGateway.add(endpoint, endpointUrl);
registeredBackends.put(endpoint, newBackend);
logger.info("Backend from server: ({}) ", newBackend);
// Notify web
messagingTemplate.convertAndSend("/topic/add", newBackend);
} else {
logger.info("Backend with provided id ({}) already registered", endpoint);
}
}
return new ArrayList<Backend>(registeredBackends.values());
}
@RequestMapping(method = RequestMethod.GET, value = "/unregister", produces = "application/json")
public List<Backend> unregister(@RequestParam(value = "endpointName") String endpointName) {
logger.info("Backends.unregister service at ({})", endpointName);
Backend backend = null;
if ((backend = registeredBackends.get(endpointName)) != null) {
messagingTemplate.convertAndSend("/topic/remove", backend); // Notify web
registeredBackends.remove(endpointName);
apiGateway.remove(endpointName);
dataGateway.remove(endpointName);
} else {
logger.info("No backend at ({})", endpointName);
}
return new ArrayList<Backend>(registeredBackends.values());
}
@RequestMapping(method = RequestMethod.GET, value = "/list", produces = "application/json")
public List<Backend> getAll() {
logger.info("Backends: getAll");
return new ArrayList<Backend>(registeredBackends.values());
}
}

View File

@ -0,0 +1,20 @@
package com.openshift.evg.roadshow.rest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* Healthz endpoint for liveness and readiness of the application
*
* Created by jmorales on 11/08/16.
*/
@RestController
@RequestMapping("/ws/healthz")
public class Healthz {
@RequestMapping(method = RequestMethod.GET, value = "/")
public String healthz() {
return "OK";
}
}

View File

@ -0,0 +1,53 @@
package com.openshift.evg.roadshow.rest;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.openshift.api.model.Route;
@Component
public class RouteWatcher extends AbstractResourceWatcher<Route> {
private static final Logger logger = LoggerFactory.getLogger(ServiceWatcher.class);
private static final String PARKSMAP_BACKEND_LABEL = "type=parksmap-backend";
@Override
protected List<Route> listWatchedResources() {
return getOpenShiftClient().routes().inNamespace(getNamespace()).withLabel(PARKSMAP_BACKEND_LABEL).list()
.getItems();
}
@Override
protected Watch doInit() {
return getOpenShiftClient().routes().inNamespace(getNamespace()).withLabel(PARKSMAP_BACKEND_LABEL).watch(this);
}
@Override
protected String getUrl(String routeName) {
List<Route> routes = getOpenShiftClient().routes().inNamespace(getNamespace()).withLabel(PARKSMAP_BACKEND_LABEL)
.withField("metadata.name", routeName).list().getItems();
if (routes.isEmpty()) {
return null;
}
Route route = routes.get(0);
String routeUrl = "";
try {
String protocol = "http://";
if((route.getSpec().getTls()!=null)&&(route.getSpec().getTls().getTermination()!=null)){
protocol = "https://";
}
routeUrl = protocol + route.getSpec().getHost();
} catch (Exception e) {
logger.error("Route {} does not have a port assigned", routeName);
}
logger.info("[INFO] Computed route URL: {}", routeUrl);
return routeUrl;
}
}

View File

@ -0,0 +1,51 @@
package com.openshift.evg.roadshow.rest;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.client.Watch;
@Component
public class ServiceWatcher extends AbstractResourceWatcher<Service> {
private static final Logger logger = LoggerFactory.getLogger(ServiceWatcher.class);
private static final String PARKSMAP_BACKEND_LABEL = "type=parksmap-backend";
@Override
protected List<Service> listWatchedResources() {
return getOpenShiftClient().services().inNamespace(getNamespace()).withLabel(PARKSMAP_BACKEND_LABEL).list()
.getItems();
}
@Override
protected Watch doInit() {
return getOpenShiftClient().services().inNamespace(getNamespace()).withLabel(PARKSMAP_BACKEND_LABEL).watch(this);
}
@Override
protected String getUrl(String serviceName) {
List<Service> services = getOpenShiftClient().services().inNamespace(getNamespace())
.withLabel(PARKSMAP_BACKEND_LABEL).withField("metadata.name", serviceName).list().getItems();
if (services.isEmpty()) {
return null;
}
Service service = services.get(0);
String serviceURL = "";
int port = 8080;
try {
port = service.getSpec().getPorts().get(0).getPort();
} catch (Exception e) {
logger.error("Service {} does not have a port assigned", serviceName);
}
serviceURL = "http://" + serviceName + ":" + port;
logger.info("[INFO] Computed service URL: {}", serviceURL);
return serviceURL;
}
}

View File

@ -0,0 +1,31 @@
package com.openshift.evg.roadshow.rest;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
/**
* This class provides support for websockets communication with the web Web
* will use t2 topics: /topic/add Notification that there is a new backend
* /topic/remove Notification of removal of backend
* <p>
* Created by jmorales on 26/08/16.
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socks-backends").withSockJS();
}
}

View File

@ -0,0 +1,101 @@
package com.openshift.evg.roadshow.rest.gateway;
import com.openshift.evg.roadshow.rest.gateway.api.BackendServiceRemote;
import com.openshift.evg.roadshow.rest.gateway.helpers.CustomErrorDecoder;
import com.openshift.evg.roadshow.rest.gateway.model.Backend;
import feign.Feign;
import feign.Retryer;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.jaxrs.JAXRSContract;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import java.util.HashMap;
import java.util.Map;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* API Gateway. It will dispatch connections to the appropriate backend
* <p>
* Created by jmorales on 24/08/16.
*/
@Controller
public class ApiGatewayController {
private static final Logger logger = LoggerFactory.getLogger(ApiGatewayController.class);
private Map<String, BackendServiceRemote> remoteServices = new HashMap<String, BackendServiceRemote>();
/**
*
*
* @param backendId
* @param url
*/
public final void add(String backendId, String url) {
if (remoteServices.get(backendId) == null) {
remoteServices.put(backendId, Feign.builder().client(CustomFeignClient.getClient()).contract(new JAXRSContract()).encoder(new JacksonEncoder())
.decoder(new JacksonDecoder()).target(BackendServiceRemote.class, url));
logger.info("Backend ({}) added to the API Gateway", backendId);
} else {
logger.error("This backend ({}) did already exist in the API Gateway", backendId);
}
}
/**
*
*
* @param backendId
*/
public final void remove(String backendId) {
if (remoteServices.get(backendId) != null) {
remoteServices.remove(backendId);
logger.info("Backend ({}) removed from the API Gateway", backendId);
} else {
logger.error("This backend ({}) did NOT exist in the API Gateway", backendId);
}
}
/**
*
*
* @param backendId
* @return
*/
public Backend getFromLocal(String backendId) {
BackendServiceRemote backend = null;
if ((backend = remoteServices.get(backendId)) != null) {
logger.info("Calling remote service {}", backendId);
try {
return backend.get();
} catch (Exception e) {
logger.error("Error connecting to backend server {}", e.getMessage());
}
}
return null;
}
/**
*
*
* @param remoteURL
* @return
*/
public Backend getFromRemote(String remoteURL) {
logger.info("Calling remote service at {}", remoteURL);
try {
return Feign.builder().client(CustomFeignClient.getClient()).contract(new JAXRSContract()).encoder(new JacksonEncoder()).decoder(new JacksonDecoder())
.retryer(new Retryer.Default(200, SECONDS.toMillis(1), 5)).errorDecoder(new CustomErrorDecoder())
.target(BackendServiceRemote.class, remoteURL).get();
} catch (Exception e) {
logger.error("Error connecting to backend server {}", e.getMessage());
logger.error("Error message",e);
}
return null;
}
}

View File

@ -0,0 +1,64 @@
package com.openshift.evg.roadshow.rest.gateway;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import feign.Client;
class CustomFeignClient {
private static final Logger logger = LoggerFactory.getLogger(CustomFeignClient.class);
/**
* This method should not be used in production!! It is only in a poof of
* concept!
*
* @return
*/
private static SSLSocketFactory getSSLSocketFactory() {
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[] { new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
logger.info("checkClientTrusted");
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
logger.info("checkClientTrusted");
}
public X509Certificate[] getAcceptedIssuers() {
logger.info("checkClientTrusted");
return new X509Certificate[0];
}
} }, new SecureRandom());
logger.warn("Ignoring certification errors! Don't use in production!");
return context.getSocketFactory();
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
public static Client getClient() {
return new Client.Default(getSSLSocketFactory(), getHostNameVerifier());
}
private static HostnameVerifier getHostNameVerifier() {
HostnameVerifier hostnameVerifier= new HostnameVerifier(){
public boolean verify(String hostname,
javax.net.ssl.SSLSession sslSession) {
logger.warn("Ignoring hostname verification errors! Don't use in production!");
return true;
}
};
return hostnameVerifier;
}
}

View File

@ -0,0 +1,86 @@
package com.openshift.evg.roadshow.rest.gateway;
import com.openshift.evg.roadshow.rest.gateway.api.DataServiceRemote;
import com.openshift.evg.roadshow.rest.gateway.model.DataPoint;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.jaxrs.JAXRSContract;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* API Gateway. It will dispatch connections to the appropriate backend
*
* Created by jmorales on 24/08/16.
*/
@RestController
@RequestMapping("/ws/data")
public class DataGatewayController {
private static final Logger logger = LoggerFactory.getLogger(DataGatewayController.class);
private Map<String, DataServiceRemote> remoteServices = new HashMap<String, DataServiceRemote>();
public DataGatewayController() {
}
/**
*
* @param backendId
* @param url
*/
public final void add(String backendId, String url) {
if (remoteServices.get(backendId) == null) {
remoteServices.put(backendId, Feign.builder().client(CustomFeignClient.getClient()).contract(new JAXRSContract()).encoder(new JacksonEncoder())
.decoder(new JacksonDecoder()).target(DataServiceRemote.class, url));
logger.info("Backend ({}) added to the Data Gateway", backendId);
} else {
logger.error("This backend ({}) did already exist in the Data Gateway", backendId);
}
}
/**
*
* @param backendId
*/
public final void remove(String backendId) {
if (remoteServices.get(backendId) != null) {
remoteServices.remove(backendId);
logger.info("Backend ({}) removed from the Data Gateway", backendId);
} else {
logger.error("This backend ({}) did NOT exist in the Data Gateway", backendId);
}
}
@RequestMapping(method = RequestMethod.GET, value = "/all", produces = "application/json")
public List<DataPoint> getAll(@RequestParam(value = "service") String serviceURL) {
DataServiceRemote remote = remoteServices.get(serviceURL);
if (remote != null) {
logger.info("[WEB-CALL] Calling remote service for {}", serviceURL);
return remote.getAll();
} else {
logger.error("[WEB-CALL] No remote service for {}", serviceURL);
return null;
}
}
@RequestMapping(method = RequestMethod.GET, value = "/within", produces = "application/json")
public List<DataPoint> getWithin(@RequestParam(value = "service") String serviceURL, @RequestParam("lat1") float lat1,
@RequestParam("lon1") float lon1, @RequestParam("lat2") float lat2, @RequestParam("lon2") float lon2) {
DataServiceRemote remote = remoteServices.get(serviceURL);
if (remote != null) {
logger.info("[WEB-CALL] Calling remote service for {}", serviceURL);
return remote.findWithin(lat1, lon1, lat2, lon2);
} else {
logger.error("[WEB-CALL] No remote service for {}", serviceURL);
return null;
}
}
}

View File

@ -0,0 +1,21 @@
package com.openshift.evg.roadshow.rest.gateway.api;
import com.openshift.evg.roadshow.rest.gateway.model.Backend;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
/**
* Contract to use in the backends to provide backend information
*
* Created by jmorales on 26/09/16.
*/
@Path("/ws/info")
public interface BackendServiceRemote {
@GET
@Path("/")
@Produces(MediaType.APPLICATION_JSON)
public Backend get();
}

View File

@ -0,0 +1,35 @@
package com.openshift.evg.roadshow.rest.gateway.api;
import com.openshift.evg.roadshow.rest.gateway.model.DataPoint;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import java.util.List;
/**
* Created by jmorales on 28/09/16.
*/
@RequestMapping("/ws/data")
@Path("/ws/data")
@RestController
public interface DataServiceRemote {
@RequestMapping(method = RequestMethod.GET, value = "/", produces = "application/json")
@GET()
@Path("/all")
@Produces("application/json")
public List<DataPoint> getAll();
@RequestMapping(method = RequestMethod.GET, value = "/within", produces = "application/json")
@GET()
@Path("/within")
@Produces("application/json")
public List<DataPoint> findWithin(@RequestParam("lat1") @QueryParam("lat1") float lat1,
@RequestParam("lon1") @QueryParam("lon1") float lon1, @RequestParam("lat2") @QueryParam("lat2") float lat2,
@RequestParam("lon2") @QueryParam("lon2") float lon2);
}

View File

@ -0,0 +1,20 @@
package com.openshift.evg.roadshow.rest.gateway.helpers;
import feign.Response;
import feign.RetryableException;
import feign.codec.ErrorDecoder;
import static feign.FeignException.errorStatus;
/**
* Created by jmorales on 04/10/16.
*/
public class CustomErrorDecoder implements ErrorDecoder {
@Override
public Exception decode(String s, Response response) {
if (response.status() == 503)
return new RetryableException("Error 503 from server. Let's retry", null);
else
return errorStatus(s, response);
}
}

View File

@ -0,0 +1,13 @@
package com.openshift.evg.roadshow.rest.gateway.helpers;
import java.util.List;
import com.openshift.evg.roadshow.rest.gateway.model.Backend;
public interface EndpointRegistrar {
List<Backend> register(String endpointName);
List<Backend> unregister(String endpointName);
void init();
}

View File

@ -0,0 +1,104 @@
package com.openshift.evg.roadshow.rest.gateway.helpers;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.fabric8.kubernetes.api.model.Endpoints;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.kubernetes.client.Watcher;
/**
*
* Created by jmorales on 04/10/16.
*/
public class EndpointWatcher implements Watcher<Endpoints> {
private static final Logger logger = LoggerFactory.getLogger(EndpointWatcher.class);
private Watch watch;
private String namespace;
private String endpointName;
private KubernetesClient client;
private AtomicInteger endpointsAvailable = new AtomicInteger(0);
private EndpointRegistrar callback;
public EndpointWatcher(EndpointRegistrar callback, KubernetesClient client, String namespace, String endpointName) {
this.client = client;
this.namespace = namespace;
this.endpointName = endpointName;
this.callback = callback;
logger.info("EndpointWatcher created for: endpoints/{} -n {}", endpointName, namespace);
if (hasEndpoints()) {
callback.register(endpointName);
} else {
callback.unregister(endpointName);
}
// Create the watch
watch = client.endpoints().inNamespace(namespace).withName(endpointName).watch(this);
}
private boolean hasEndpoints() {
return hasEndpoints(client.endpoints().inNamespace(namespace).withName(endpointName).get());
}
private boolean hasEndpoints(Endpoints endpoints) {
int size = getEndpointsAddressSize(endpoints);
if (size > 0) {
endpointsAvailable.set(size);
return size > 0;
} else
return false;
}
private int getEndpointsAddressSize(Endpoints endpoints) {
if (endpoints.getSubsets().size() > 0)
return endpoints.getSubsets().get(0).getAddresses().size();
else
return 0;
}
@Override
public void eventReceived(Action action, Endpoints endpoints) {
int current = getEndpointsAddressSize(endpoints);
int previous = endpointsAvailable.getAndSet(current);
if (previous != current) {
logger.info("Endpoints changed, from {} to {}", previous, current);
if (previous == 0) {
if (current > 0) {
logger.info("There are endpoints for {} available. Registering", endpointName);
callback.register(endpointName);
}
}
if (current == 0) {
if (previous > 0) {
logger.info("There's no endpoints for {}. Unregistering", endpointName);
callback.unregister(endpointName);
}
}
} else {
logger.info("Endpoints changes ignored");
}
}
@Override
public void onClose(KubernetesClientException e) {
callback.init();
}
public void close() {
if (watch != null)
watch.close();
}
}

View File

@ -0,0 +1,121 @@
package com.openshift.evg.roadshow.rest.gateway.model;
/**
* This represents a backend. Once a backend is registered, a call to the
* backend to get this information about it will be issued.
*
* Created by jmorales on 24/08/16.
*/
public class Backend {
public static final String BACKEND_TYPE_MARKER = "marker";
public static final String BACKEND_TYPE_CLUSTER = "cluster";
public static final String BACKEND_TYPE_TEMP = "temp";
public static final String BACKEND_TYPE_HEATMAP = "heatmap";
public static final String BACKEND_SCOPE_ALL = "all";
public static final String BACKEND_SCOPE_WITHIN = "within";
private String id;
private String displayName;
private Coordinates center = new Coordinates("0", "0");
private int zoom = 1;
private int maxZoom = 1;
private String type = BACKEND_TYPE_CLUSTER;
private boolean visible = true;
private String scope = BACKEND_SCOPE_ALL;
public Backend() {
}
public Backend(String id, String displayName, String service) {
this.id = id;
this.displayName = displayName;
}
public Backend(String id, String displayName, Coordinates center, int zoom) {
this.id = id;
this.displayName = displayName;
this.center = center;
this.zoom = zoom;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public Coordinates getCenter() {
return center;
}
public void setCenter(Coordinates center) {
this.center = center;
}
public int getZoom() {
return zoom;
}
public void setZoom(int zoom) {
this.zoom = zoom;
}
public int getMaxZoom() {
return maxZoom;
}
public void setMaxZoom(int maxzoom) {
this.maxZoom = maxzoom;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
@Override
public String toString() {
return "Backend{" +
"id='" + id + '\'' +
", displayName='" + displayName + '\'' +
", center='" + center + '\'' +
", zoom='" + zoom + '\'' +
", type='" + type + '\'' +
", scope='" + scope + '\'' +
", visible='" + visible + '\'' +
", maxZoom='" + maxZoom + '\'' +
'}';
}
}

View File

@ -0,0 +1,52 @@
package com.openshift.evg.roadshow.rest.gateway.model;
import java.util.List;
/**
* TODO: Remove???
* <p>
* Created by jmorales on 18/08/16.
*/
public class Coordinates {
private String latitude;
private String longitude;
public Coordinates() {
}
public Coordinates(String lat, String lng) {
this.latitude = lat;
this.longitude = lng;
}
public Coordinates(List<?> position) {
if (position.size() > 0)
this.latitude = position.get(0).toString();
if (position.size() > 1)
this.longitude = position.get(1).toString();
}
public String getLatitude() {
return latitude;
}
public void setLatitude(String lat) {
this.latitude = lat;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String lng) {
this.longitude = lng;
}
@Override
public String toString() {
return "Coordinates{" +
"lat='" + latitude + '\'' +
", lng='" + longitude + '\'' +
'}';
}
}

View File

@ -0,0 +1,72 @@
package com.openshift.evg.roadshow.rest.gateway.model;
public class DataPoint {
private String id;
private String name;
private Coordinates position;
private String longitude;
private String latitude;
private String info;
public DataPoint() {
}
public DataPoint(String id, String name) {
this.id = id;
this.name = name;
}
public Object getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Coordinates getPosition() {
return position;
}
public void setPosition(Coordinates position) {
this.position = position;
}
public Object getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public Object getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "NationalPark{" +
"id=" + id +
", name=" + name +
", coordinates=" + position +
", info=" + info +
'}';
}
}