Skip to content

Commit

Permalink
Merge pull request #2792 from jglick/SYSTEM-JENKINS-42556
Browse files Browse the repository at this point in the history
[JENKINS-42556] Run more system threads as SYSTEM
  • Loading branch information
jglick committed Mar 14, 2017
2 parents 12a4177 + 3d071b9 commit dd0d578
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 3 deletions.
@@ -0,0 +1,77 @@
/*
* The MIT License
*
* Copyright 2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package jenkins.security;

import hudson.security.ACL;
import hudson.security.ACLContext;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import jenkins.util.InterceptingExecutorService;
import org.acegisecurity.Authentication;

/**
* Uses {@link ACL#impersonate(Authentication)} for all tasks.
* @see SecurityContextExecutorService
* @since FIXME
*/
public final class ImpersonatingExecutorService extends InterceptingExecutorService {

private final Authentication authentication;

/**
* Creates a wrapper service.
* @param base the base service
* @param authentication for example {@link ACL#SYSTEM}
*/
public ImpersonatingExecutorService(ExecutorService base, Authentication authentication) {
super(base);
this.authentication = authentication;
}

@Override
protected Runnable wrap(final Runnable r) {
return new Runnable() {
@Override
public void run() {
try (ACLContext ctxt = ACL.as(authentication)) {
r.run();
}
}
};
}

@Override
protected <V> Callable<V> wrap(final Callable<V> r) {
return new Callable<V>() {
@Override
public V call() throws Exception {
try (ACLContext ctxt = ACL.as(authentication)) {
return r.call();
}
}
};
}

}
@@ -0,0 +1,76 @@
/*
* The MIT License
*
* Copyright 2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package jenkins.security;

import hudson.security.ACL;
import hudson.security.ACLContext;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import jenkins.util.InterceptingScheduledExecutorService;
import org.acegisecurity.Authentication;

/**
* Variant of {@link ImpersonatingExecutorService} for scheduled services.
* @since FIXME
*/
public final class ImpersonatingScheduledExecutorService extends InterceptingScheduledExecutorService {

private final Authentication authentication;

/**
* Creates a wrapper service.
* @param base the base service
* @param authentication for example {@link ACL#SYSTEM}
*/
public ImpersonatingScheduledExecutorService(ScheduledExecutorService base, Authentication authentication) {
super(base);
this.authentication = authentication;
}

@Override
protected Runnable wrap(final Runnable r) {
return new Runnable() {
@Override
public void run() {
try (ACLContext ctxt = ACL.as(authentication)) {
r.run();
}
}
};
}

@Override
protected <V> Callable<V> wrap(final Callable<V> r) {
return new Callable<V>() {
@Override
public V call() throws Exception {
try (ACLContext ctxt = ACL.as(authentication)) {
return r.call();
}
}
};
}

}
12 changes: 10 additions & 2 deletions core/src/main/java/jenkins/util/AtmostOneTaskExecutor.java
Expand Up @@ -2,13 +2,17 @@

import com.google.common.util.concurrent.SettableFuture;
import hudson.remoting.AtmostOneThreadExecutor;
import hudson.security.ACL;
import hudson.util.DaemonThreadFactory;
import hudson.util.NamingThreadFactory;

import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import jenkins.security.ImpersonatingExecutorService;

/**
* {@link Executor}-like class that executes a single task repeatedly, in such a way that a single execution
Expand Down Expand Up @@ -41,6 +45,9 @@
* @see AtmostOneThreadExecutor
*/
public class AtmostOneTaskExecutor<V> {

private static final Logger LOGGER = Logger.getLogger(AtmostOneTaskExecutor.class.getName());

/**
* The actual executor that executes {@link #task}
*/
Expand All @@ -65,10 +72,10 @@ public AtmostOneTaskExecutor(ExecutorService base, Callable<V> task) {
}

public AtmostOneTaskExecutor(Callable<V> task) {
this(new AtmostOneThreadExecutor(new NamingThreadFactory(
this(new ImpersonatingExecutorService(new AtmostOneThreadExecutor(new NamingThreadFactory(
new DaemonThreadFactory(),
String.format("AtmostOneTaskExecutor[%s]", task)
)),
)), ACL.SYSTEM),
task
);
}
Expand Down Expand Up @@ -100,6 +107,7 @@ public Void call() throws Exception {
try {
inprogress.set(task.call());
} catch (Throwable t) {
LOGGER.log(Level.WARNING, null, t);
inprogress.setException(t);
} finally {
synchronized (AtmostOneTaskExecutor.this) {
Expand Down
@@ -0,0 +1,67 @@
/*
* The MIT License
*
* Copyright 2017 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package jenkins.util;

import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
* Generalization of {@link InterceptingExecutorService} to scheduled services.
* @since FIXME
*/
public abstract class InterceptingScheduledExecutorService extends InterceptingExecutorService implements ScheduledExecutorService {

protected InterceptingScheduledExecutorService(ScheduledExecutorService base) {
super(base);
}

@Override
protected ScheduledExecutorService delegate() {
return (ScheduledExecutorService) super.delegate();
}

@Override
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
return delegate().schedule(wrap(command), delay, unit);
}

@Override
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
return delegate().schedule(wrap(callable), delay, unit);
}

@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
return delegate().scheduleAtFixedRate(wrap(command), initialDelay, period, unit);
}

@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
return delegate().scheduleWithFixedDelay(wrap(command), initialDelay, delay, unit);
}

}
5 changes: 4 additions & 1 deletion core/src/main/java/jenkins/util/Timer.java
@@ -1,9 +1,11 @@
package jenkins.util;

import hudson.security.ACL;
import hudson.util.DaemonThreadFactory;
import hudson.util.NamingThreadFactory;
import javax.annotation.Nonnull;
import java.util.concurrent.ScheduledExecutorService;
import jenkins.security.ImpersonatingScheduledExecutorService;

/**
* Holds the {@link ScheduledExecutorService} for running all background tasks in Jenkins.
Expand Down Expand Up @@ -39,7 +41,8 @@ public static synchronized ScheduledExecutorService get() {
if (executorService == null) {
// corePoolSize is set to 10, but will only be created if needed.
// ScheduledThreadPoolExecutor "acts as a fixed-sized pool using corePoolSize threads"
executorService = new ErrorLoggingScheduledThreadPoolExecutor(10, new NamingThreadFactory(new DaemonThreadFactory(), "jenkins.util.Timer"));
// TODO consider also wrapping in ContextResettingExecutorService
executorService = new ImpersonatingScheduledExecutorService(new ErrorLoggingScheduledThreadPoolExecutor(10, new NamingThreadFactory(new DaemonThreadFactory(), "jenkins.util.Timer")), ACL.SYSTEM);
}
return executorService;
}
Expand Down

0 comments on commit dd0d578

Please sign in to comment.