dev.galasa.framework.resource.management.internal.ResourceManagement Maven / Gradle / Ivy
The newest version!
/*
* Copyright contributors to the Galasa project
*
* SPDX-License-Identifier: EPL-2.0
*/
package dev.galasa.framework.resource.management.internal;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Properties;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import dev.galasa.framework.FrameworkInitialisation;
import dev.galasa.framework.spi.AbstractManager;
import dev.galasa.framework.spi.DynamicStatusStoreException;
import dev.galasa.framework.spi.FrameworkException;
import dev.galasa.framework.spi.IConfigurationPropertyStoreService;
import dev.galasa.framework.spi.IDynamicStatusStoreService;
import dev.galasa.framework.spi.IFramework;
import dev.galasa.framework.spi.IResourceManagement;
import dev.galasa.framework.spi.IResourceManagementProvider;
import io.prometheus.client.Counter;
import io.prometheus.client.exporter.HTTPServer;
/**
* Run Resource Management
*/
@Component(service = { ResourceManagement.class })
public class ResourceManagement implements IResourceManagement {
private Log logger = LogFactory
.getLog(this.getClass());
private BundleContext bundleContext;
private final ArrayList resourceManagementProviders = new ArrayList<>();
private ScheduledExecutorService scheduledExecutorService;
private boolean shutdown = false;
private boolean shutdownComplete = false;
private Instant lastSuccessfulRun = Instant.now();
private HTTPServer metricsServer;
private Counter successfulRunsCounter;
private ResourceManagementHealth healthServer;
private String serverName;
private String hostname;
/**
* Run Resource Management
* @param bootstrapProperties
* @param overrideProperties
* @throws FrameworkException
*/
public void run(Properties bootstrapProperties, Properties overrideProperties) throws FrameworkException {
// *** Add shutdown hook to allow for orderly shutdown
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
// *** Initialise the framework services
FrameworkInitialisation frameworkInitialisation = null;
try {
frameworkInitialisation = new FrameworkInitialisation(bootstrapProperties, overrideProperties);
} catch (Exception e) {
throw new FrameworkException("Unable to initialise the Framework Services", e);
}
IFramework framework = frameworkInitialisation.getFramework();
IConfigurationPropertyStoreService cps = framework.getConfigurationPropertyService("framework");
IDynamicStatusStoreService dss = framework.getDynamicStatusStoreService("framework");
// *** Now start the Resource Management framework
logger.info("Starting Resource Management");
// *** Calculate servername
this.hostname = "unknown";
try {
this.hostname = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
logger.error("Unable to obtain the host name", e);
}
this.serverName = AbstractManager.nulled(cps.getProperty("server", "name"));
if (this.serverName == null) {
this.serverName = AbstractManager.nulled(System.getenv("framework.server.name"));
if (this.serverName == null) {
String[] split = this.hostname.split("\\.");
if (split.length >= 1) {
this.serverName = split[0];
}
}
}
if (serverName == null) {
this.serverName = "unknown";
}
this.serverName = this.serverName.toLowerCase();
this.hostname = this.hostname.toLowerCase();
this.serverName = this.serverName.replaceAll("\\.", "-");
// *** Setup defaults and properties
int numberOfRunThreads = 5;
int metricsPort = 9010;
int healthPort = 9011;
String threads = AbstractManager.nulled(cps.getProperty("resource.management", "threads"));
if (threads != null) {
numberOfRunThreads = Integer.parseInt(threads);
}
String port = AbstractManager.nulled(cps.getProperty("resource.management.metrics", "port"));
if (port != null) {
metricsPort = Integer.parseInt(port);
}
port = AbstractManager.nulled(cps.getProperty("resource.management.health", "port"));
if (port != null) {
healthPort = Integer.parseInt(port);
}
// *** Setup scheduler
scheduledExecutorService = new ScheduledThreadPoolExecutor(numberOfRunThreads);
// *** Start the metrics server
if (metricsPort > 0) {
try {
this.metricsServer = new HTTPServer(metricsPort);
logger.info("Metrics server running on port " + metricsPort);
} catch (IOException e) {
throw new FrameworkException("Unable to start the metrics server", e);
}
} else {
logger.info("Metrics server disabled");
}
// *** Create metrics
// DefaultExports.initialize() - problem within the the exporter at the moment
// TODO
this.successfulRunsCounter = Counter.build().name("galasa_resource_management_successfull_runs")
.help("The number of successfull resource management runs").register();
// *** Create Health Server
if (healthPort > 0) {
this.healthServer = new ResourceManagementHealth(this, healthPort);
logger.info("Health monitoring on port " + healthPort);
} else {
logger.info("Health monitoring disabled");
}
// *** Locate all the Resource Management providers in the framework
try {
final ServiceReference>[] rmpServiceReference = bundleContext
.getAllServiceReferences(IResourceManagementProvider.class.getName(), null);
if ((rmpServiceReference == null) || (rmpServiceReference.length == 0)) {
logger.info("No additional Resource Manager providers have been found");
} else {
for (final ServiceReference> rmpReference : rmpServiceReference) {
final IResourceManagementProvider rmpStoreRegistration = (IResourceManagementProvider) bundleContext
.getService(rmpReference);
try {
if (rmpStoreRegistration.initialise(framework, this)) {
logger.info(
"Found Resource Management Provider " + rmpStoreRegistration.getClass().getName());
resourceManagementProviders.add(rmpStoreRegistration);
} else {
logger.info("Resource Management Provider " + rmpStoreRegistration.getClass().getName()
+ " opted out of this Resource Management run");
}
} catch (Exception e) {
logger.error("Failed initialisation of Resource Management Provider "
+ rmpStoreRegistration.getClass().getName() + " ignoring", e);
}
}
}
} catch (Exception e) {
throw new FrameworkException("Problem during Resource Manager initialisation", e);
}
// *** Start the providers
for (IResourceManagementProvider provider : resourceManagementProviders) {
provider.start();
}
// *** Start the Run watch thread
ResourceManagementRunWatch runWatch = new ResourceManagementRunWatch(framework, this);
logger.info("Resource Manager has started");
// *** Loop until we are asked to shutdown
long heartbeatExpire = 0;
while (!shutdown) {
if (System.currentTimeMillis() >= heartbeatExpire) {
updateHeartbeat(dss);
heartbeatExpire = System.currentTimeMillis() + 20000;
}
try {
Thread.sleep(500);
} catch (Exception e) {
throw new FrameworkException("Interrupted sleep", e);
}
}
// *** shutdown the scheduler
this.scheduledExecutorService.shutdown();
try {
this.scheduledExecutorService.awaitTermination(30, TimeUnit.SECONDS);
} catch (Exception e) {
logger.error("Unable to shutdown the scheduler");
}
// *** Ask the run watch to terminate
runWatch.shutdown();
// *** shutdown the providers
for (IResourceManagementProvider provider : resourceManagementProviders) {
logger.info("Requesting Resource Management Provider " + provider.getClass().getName() + " shutdown");
provider.shutdown();
}
// *** Stop the metics server
if (metricsPort > 0) {
this.metricsServer.stop();
}
// *** Stop the health server
if (healthPort > 0) {
this.healthServer.shutdown();
}
logger.info("Resource Management shutdown");
shutdownComplete = true;
return;
}
private void updateHeartbeat(IDynamicStatusStoreService dss) {
Instant time = Instant.now();
HashMap props = new HashMap<>();
props.put("servers.resourcemonitor." + serverName + ".heartbeat", time.toString());
props.put("servers.resourcemonitor." + serverName + ".hostname", hostname);
try {
dss.put(props);
} catch (DynamicStatusStoreException e) {
logger.error("Problem logging heartbeat", e);
}
}
@Activate
public void activate(BundleContext context) {
this.bundleContext = context;
}
public void runFinishedOrDeleted(String runName) {
for (IResourceManagementProvider provider : resourceManagementProviders) {
provider.runFinishedOrDeleted(runName);
}
}
@Override
public ScheduledExecutorService getScheduledExecutorService() {
return this.scheduledExecutorService;
}
@Override
public synchronized void resourceManagementRunSuccessful() {
this.lastSuccessfulRun = Instant.now();
this.successfulRunsCounter.inc();
}
protected synchronized Instant getLastSuccessfulRun() {
return this.lastSuccessfulRun;
}
private class ShutdownHook extends Thread {
@Override
public void run() {
ResourceManagement.this.logger.info("Shutdown request received");
ResourceManagement.this.shutdown = true;
while (!shutdownComplete) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
ResourceManagement.this.logger.info("Shutdown wait was interrupted", e);
Thread.currentThread().interrupt();
return;
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy