Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add Hosts caching for canProvision()
[FIXES JENKINS-38815]
  • Loading branch information
scoheb committed Oct 13, 2016
1 parent bc170d4 commit bad8752
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 23 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -15,7 +15,7 @@
<artifactId>foreman-node-sharing</artifactId>
<packaging>hpi</packaging>
<name>Foreman Node Sharing Plugin</name>
<version>1.1.1-SNAPSHOT</version>
<version>1.1.2-SNAPSHOT</version>
<description>Attach Foreman Shared Resources as Jenkins Nodes</description>
<url>https://wiki.jenkins-ci.org/display/JENKINS/Foreman+Node+Sharing+Plugin</url>

Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/redhat/foreman/ForemanAPI.java
Expand Up @@ -283,7 +283,7 @@ public String getIPForHost(String hostname) {
* @return list of hosts.
* @throws Exception if occurs.
*/
public Map<String, String> getHostForQuery(String query) throws Exception {
private Map<String, String> getHostForQuery(String query) throws Exception {
Map<String, String> hostsMap = new HashMap<String, String>();
List<String> hostsList = new ArrayList<String>();
WebTarget target = base.path(FOREMAN_HOSTS_PATH)
Expand Down Expand Up @@ -324,7 +324,7 @@ public Map<String, String> getHostForQuery(String query) throws Exception {
* @return list of host names.
* @throws Exception if occurs.
*/
public Map<String, String> getCompatibleHosts() throws Exception {
Map<String, String> getCompatibleHosts() throws Exception {
String query = "has " + FOREMAN_SEARCH_LABELPARAM
+ " and has " + FOREMAN_SEARCH_RESERVEDPARAM
+ " and has " + FOREMAN_REMOTEFS_ROOT;
Expand All @@ -351,4 +351,5 @@ public boolean isHostFree(String host) throws Exception {
String free = getHostParameterValue(host, FOREMAN_SEARCH_RESERVEDPARAMNAME);
return !StringUtils.isEmpty(free) && free.equalsIgnoreCase("false");
}

}
99 changes: 79 additions & 20 deletions src/main/java/com/redhat/foreman/ForemanSharedNodeCloud.java
Expand Up @@ -6,6 +6,7 @@
import hudson.model.Descriptor;
import hudson.model.Label;
import hudson.model.Node;
import hudson.model.PeriodicWork;
import hudson.slaves.AbstractCloudComputer;
import hudson.slaves.Cloud;
import hudson.slaves.CloudRetentionStrategy;
Expand All @@ -31,6 +32,7 @@
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;

import javax.annotation.CheckForNull;
import javax.security.auth.login.LoginException;
Expand Down Expand Up @@ -90,6 +92,8 @@ public class ForemanSharedNodeCloud extends Cloud {

private transient ForemanAPI api = null;
private transient ForemanComputerLauncherFactory launcherFactory = null;
private transient AtomicReference<Map<String, String>> hostsMap
= new AtomicReference<Map<String, String>>(new HashMap<String, String>());

/**
* Constructor with name.
Expand Down Expand Up @@ -153,17 +157,11 @@ ForemanAPI getForemanAPI() {

@Override
public boolean canProvision(Label label) {
Map<String, String> hostsMap = null;
try {
hostsMap = getForemanAPI().getCompatibleHosts();
} catch (Exception e) {
LOGGER.error("Unhandled exception in canProvision: ", e);
e.printStackTrace();
return false;
}
Set<Map.Entry<String, String>> hosts = hostsMap.entrySet();
Map<String, String> mapData = getHostsMapData();

Set<Map.Entry<String, String>> hosts = mapData.entrySet();
for (Map.Entry<String, String> host: hosts) {
if (label == null || label.matches(Label.parse(hostsMap.get(host.getKey())))) {
if (label == null || label.matches(Label.parse(mapData.get(host.getKey())))) {
return true;
}
}
Expand Down Expand Up @@ -304,19 +302,13 @@ private ForemanSharedNode provision(Label label) throws Exception {
*/
@CheckForNull
private String getHostToReserve(Label label) {
Map<String, String> hostsMap = null;
try {
hostsMap = getForemanAPI().getCompatibleHosts();
} catch (Exception e) {
LOGGER.error("Unhandled exception in getHostToReserve: ", e);
e.printStackTrace();
return null;
}
Set<Map.Entry<String, String>> hosts = hostsMap.entrySet();
Map<String, String> mapData = getHostsMapData();

Set<Map.Entry<String, String>> hosts = mapData.entrySet();
for (Map.Entry<String, String> host: hosts) {
try {
if (getForemanAPI().isHostFree(host.getKey())
&& (label == null || label.matches(Label.parse(hostsMap.get(host.getKey()))))) {
&& (label == null || label.matches(Label.parse(mapData.get(host.getKey()))))) {
return host.getKey();
}
} catch (Exception e){
Expand Down Expand Up @@ -430,6 +422,37 @@ public Integer getSshConnectionTimeOut() {
return sshConnectionTimeOut;
}

/**
* Update hosts data
*/
void updateHostData() {
try {
if (hostsMap == null) {
hostsMap = new AtomicReference<Map<String, String>>(new HashMap<String, String>());
}

Map<String, String> testMap = getForemanAPI().getCompatibleHosts();
if (testMap != null) {
hostsMap.set(testMap);
return;
}
} catch (Exception e) {
LOGGER.error(e);
e.printStackTrace();
}
hostsMap.set(new HashMap<String, String>());
}

@CheckForNull
private Map<String, String> getHostsMapData() {
if (hostsMap == null) {
hostsMap = new AtomicReference<Map<String, String>>(new HashMap<String, String>());
}
if (hostsMap.get() == null) {
updateHostData();
}
return hostsMap.get();
}
/**
* Descriptor for Foreman Cloud.
*
Expand Down Expand Up @@ -567,4 +590,40 @@ private static boolean isValidURL(String url) {
return true;
}
}

/**
* Extension to update
*/
@Extension
public static class ForemanSharedNodeWorker extends PeriodicWork {

private final Logger LOGGER =
Logger.getLogger(com.redhat.foreman.ForemanSharedNodeCloud.ForemanSharedNodeWorker.class);

@Override
@SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE")
public void doRun() {
Jenkins instance = Jenkins.getInstance();
if (instance.clouds != null) {
for (Cloud cloud: instance.clouds) {
if (cloud instanceof ForemanSharedNodeCloud) {
ForemanSharedNodeCloud foremanCloud = (ForemanSharedNodeCloud) cloud;
LOGGER.debug("Updating data for ForemanSharedNodeCloud " + foremanCloud.getCloudName());
foremanCloud.updateHostData();
LOGGER.debug("[COMPLETED] Updating data for ForemanSharedNodeCloud " + foremanCloud.getCloudName());
}
}
}
}

@Override
public long getRecurrencePeriod() {
return MIN;
}

@Override
public String toString() {
return "ForemanSharedNodeWorker.Updater";
}
}
}
Expand Up @@ -238,6 +238,7 @@ public void testRoundTrip() throws IOException, URISyntaxException, InterruptedE

fCloud.setLauncherFactory(new ForemanDummyComputerLauncherFactory());
j.getInstance().clouds.add(fCloud);
fCloud.updateHostData();

FreeStyleProject job = j.createFreeStyleProject();
job.setAssignedLabel(new LabelAtom("label1"));
Expand Down Expand Up @@ -276,6 +277,7 @@ public void testWithLossOfConnection() throws Exception {

fCloud.setLauncherFactory(new ForemanDummyComputerLauncherFactory());
j.getInstance().clouds.add(fCloud);
fCloud.updateHostData();

AdministrativeMonitor adminMonitor = j.getInstance().getAdministrativeMonitor("AsyncResourceDisposer");
assertTrue("adminMonitor not null for AsyncResourceDisposer", adminMonitor != null);
Expand Down Expand Up @@ -322,6 +324,7 @@ public void testWithLossOfConnection() throws Exception {
// Simulate Foreman is back online
setupWireMock();
Thread.sleep(1000);
fCloud.updateHostData();
while(cleanedCheckLatch.getCount() >= 0) {
boolean foundOurDisposalItem = false;
for (AsyncResourceDisposer.WorkItem item: disposer.getBacklog()) {
Expand Down

0 comments on commit bad8752

Please sign in to comment.