[JENKINS-27177] Add strategies to disable plugins. Move process to core

Move the process to core to be reusable, not only for the cli command.
Add optionalDependants list to PluginWrapper to process them easily.

Replace (depreacate) the disable method without checks by this one with
strategies.

Improve messages and tests
This commit is contained in:
M Ramon Leon authored and Ramon Leon committed 2018-10-15 10:06:21 +02:00
1 parent 18be1960d1
commit fe8d0d5e7c
9 files changed
+686 -182

No files matched your search

+65 -78
View File
@@ -25,47 +25,29 @@ package hudson;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.security.ACLContext;
import jenkins.ExtensionRefreshException;
import jenkins.util.SystemProperties;
import hudson.PluginWrapper.Dependency;
import hudson.init.InitMilestone;
import hudson.init.InitStrategy;
import hudson.init.InitializerFinder;
import hudson.model.AbstractItem;
import hudson.model.AbstractModelObject;
import hudson.model.AdministrativeMonitor;
import hudson.model.Api;
import hudson.model.Descriptor;
import hudson.model.Failure;
import hudson.model.ItemGroupMixIn;
import hudson.model.UpdateCenter;
import hudson.model.UpdateSite;
import hudson.model.*;
import hudson.model.UpdateCenter.DownloadJob;
import hudson.model.UpdateCenter.InstallationJob;
import hudson.security.ACL;
import hudson.security.ACLContext;
import hudson.security.Permission;
import hudson.security.PermissionScope;
import hudson.util.CyclicGraphDetector;
import hudson.util.*;
import hudson.util.CyclicGraphDetector.CycleDetectedException;
import hudson.util.PersistedList;
import hudson.util.Service;
import hudson.util.VersionNumber;
import hudson.util.XStream2;
import jenkins.ClassLoaderReflectionToolkit;
import jenkins.InitReactorRunner;
import jenkins.MissingDependencyException;
import jenkins.RestartRequiredException;
import jenkins.YesNoMaybe;
import jenkins.*;
import jenkins.install.InstallState;
import jenkins.install.InstallUtil;
import jenkins.model.Jenkins;
import jenkins.security.CustomClassFilter;
import jenkins.util.SystemProperties;
import jenkins.util.io.OnMaster;
import jenkins.util.xml.RestrictiveEntityResolver;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.acegisecurity.Authentication;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
@@ -78,23 +60,19 @@ import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.LogFactory;
import org.jenkinsci.Symbol;
import org.jenkinsci.bytecode.Transformer;
import org.jvnet.hudson.reactor.Executable;
import org.jvnet.hudson.reactor.Reactor;
import org.jvnet.hudson.reactor.ReactorException;
import org.jvnet.hudson.reactor.TaskBuilder;
import org.jvnet.hudson.reactor.TaskGraphBuilder;
import org.jvnet.hudson.reactor.*;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.stapler.HttpRedirect;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.*;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerOverridable;
import org.kohsuke.stapler.StaplerProxy;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import org.kohsuke.stapler.interceptor.RequirePOST;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -102,60 +80,24 @@ import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import java.io.Closeable;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.net.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.function.Supplier;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import static hudson.init.InitMilestone.*;
import hudson.model.DownloadService;
import hudson.util.FormValidation;
import java.io.ByteArrayInputStream;
import java.net.JarURLConnection;
import java.net.URLConnection;
import java.util.ServiceLoader;
import java.util.function.Supplier;
import java.util.jar.JarEntry;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.SEVERE;
import static java.util.logging.Level.WARNING;
import jenkins.security.CustomClassFilter;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import static java.util.logging.Level.*;
/**
* Manages {@link PluginWrapper}s.
@@ -935,8 +877,15 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
@Restricted(NoExternalUse.class)
public synchronized void resolveDependantPlugins() {
for (PluginWrapper plugin : plugins) {
// Set of optional dependants plugins of plugin
Set<String> optionalDependants = new HashSet<>();
Set<String> dependants = new HashSet<>();
for (PluginWrapper possibleDependant : plugins) {
// No need to check if plugin is dependant of itself
if(possibleDependant.getShortName().equals(plugin.getShortName())) {
continue;
}
// The plugin could have just been deleted. If so, it doesn't
// count as a dependant.
if (possibleDependant.isDeleted()) {
@@ -946,10 +895,20 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
for (Dependency dependency : dependencies) {
if (dependency.shortName.equals(plugin.getShortName())) {
dependants.add(possibleDependant.getShortName());
// If, in addition, the dependency is optional, add to the optionalDependants list
if (dependency.optional) {
optionalDependants.add(possibleDependant.getShortName());
}
// already know possibleDependant depends on plugin, no need to continue with the rest of
// dependencies. We continue with the next possibleDependant
break;
}
}
}
plugin.setDependants(dependants);
plugin.setOptionalDependants(optionalDependants);
}
}
@@ -1829,6 +1788,34 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas
return new MetadataCache();
}
/**
* Disable a list of plugins using a strategy for its dependants plugins.
* @param strategy the strategy regarding how the dependant plugins are processed
* @param plugins the list of plugins
* @return the list of results for every plugin and its dependant plugins.
* @throws IOException see {@link PluginWrapper#disable()}
*/
public List<PluginWrapper.PluginDisableResult> disablePlugins(PluginWrapper.PluginDisableStrategy strategy, List<String> plugins) throws IOException {
// Where we store the results of each plugin disablement
List<PluginWrapper.PluginDisableResult> results = new ArrayList<>(plugins.size());
// Disable all plugins passed
for (String pluginName : plugins) {
PluginWrapper plugin = this.getPlugin(pluginName);
if (plugin == null) {
PluginWrapper.PluginDisableResult result = new PluginWrapper.PluginDisableResult(pluginName);
result.setMessage(Messages.PluginWrapper_NoSuchPlugin(pluginName));
result.setStatus(PluginWrapper.PluginDisableStatus.NO_SUCH_PLUGIN);
results.add(result);
} else {
results.add(plugin.disable(strategy));
}
}
return results;
}
@Restricted(NoExternalUse.class) // table.jelly
public static final class MetadataCache {
private final Map<String, Object> data = new HashMap<>();