mirror of https://github.com/jenkinsci/jenkins.git
This commit is contained in:
commit
70c1c98da4
|
@ -2186,12 +2186,14 @@ public class Functions {
|
|||
/**
|
||||
* Generate a series of {@code <script>} tags to include {@code script.js}
|
||||
* from {@link ConsoleAnnotatorFactory}s and {@link ConsoleAnnotationDescriptor}s.
|
||||
*
|
||||
* @see hudson.console.ConsoleAnnotatorFactory.RootAction
|
||||
*/
|
||||
public static String generateConsoleAnnotationScriptAndStylesheet() {
|
||||
String cp = Stapler.getCurrentRequest2().getContextPath() + Jenkins.RESOURCE_PATH;
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (ConsoleAnnotatorFactory f : ConsoleAnnotatorFactory.all()) {
|
||||
String path = cp + "/extensionList/" + ConsoleAnnotatorFactory.class.getName() + "/" + f.getClass().getName();
|
||||
String path = cp + "/" + ConsoleAnnotatorFactory.class.getName() + "/" + f.getClass().getName();
|
||||
if (f.hasScript())
|
||||
buf.append("<script src='").append(path).append("/script.js'></script>");
|
||||
if (f.hasStylesheet())
|
||||
|
|
|
@ -27,6 +27,7 @@ package hudson.console;
|
|||
import hudson.Extension;
|
||||
import hudson.ExtensionList;
|
||||
import hudson.ExtensionPoint;
|
||||
import hudson.model.InvisibleAction;
|
||||
import hudson.model.Run;
|
||||
import jakarta.servlet.ServletException;
|
||||
import java.io.IOException;
|
||||
|
@ -35,6 +36,8 @@ import java.lang.reflect.Type;
|
|||
import java.net.URL;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.jvnet.tiger_types.Types;
|
||||
import org.kohsuke.accmod.Restricted;
|
||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
import org.kohsuke.stapler.StaplerRequest2;
|
||||
import org.kohsuke.stapler.StaplerResponse2;
|
||||
import org.kohsuke.stapler.WebMethod;
|
||||
|
@ -129,4 +132,24 @@ public abstract class ConsoleAnnotatorFactory<T> implements ExtensionPoint {
|
|||
public static ExtensionList<ConsoleAnnotatorFactory> all() {
|
||||
return ExtensionList.lookup(ConsoleAnnotatorFactory.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This action makes {@link hudson.console.ConsoleAnnotatorFactory} instances accessible via HTTP.
|
||||
*
|
||||
* @see hudson.Functions#generateConsoleAnnotationScriptAndStylesheet
|
||||
* @see ConsoleAnnotatorFactory#hasStylesheet()
|
||||
* @see ConsoleAnnotatorFactory#hasScript()
|
||||
*/
|
||||
@Restricted(NoExternalUse.class)
|
||||
@Extension
|
||||
public static class RootAction extends InvisibleAction implements hudson.model.RootAction {
|
||||
@Override
|
||||
public String getUrlName() {
|
||||
return ConsoleAnnotatorFactory.class.getName();
|
||||
}
|
||||
|
||||
public ConsoleAnnotatorFactory<?> getDynamic(String className) {
|
||||
return all().getDynamic(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2025, 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.diagnosis;
|
||||
|
||||
import hudson.Extension;
|
||||
import hudson.ExtensionList;
|
||||
import hudson.diagnosis.MemoryUsageMonitor;
|
||||
import hudson.model.InvisibleAction;
|
||||
import hudson.model.RootAction;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.kohsuke.accmod.Restricted;
|
||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
|
||||
/**
|
||||
* Expose {@link hudson.diagnosis.MemoryUsageMonitor#heap} at the {@code /hudson.diagnosis.MemoryUsageMonitor/heap} URL.
|
||||
*
|
||||
* @since TODO
|
||||
*/
|
||||
@Extension
|
||||
@Restricted(NoExternalUse.class)
|
||||
public class MemoryUsageMonitorAction extends InvisibleAction implements RootAction {
|
||||
@Override
|
||||
public String getUrlName() {
|
||||
return MemoryUsageMonitorAction.class.getName();
|
||||
}
|
||||
|
||||
public MemoryUsageMonitor.MemoryGroup getHeap() {
|
||||
Jenkins.get().checkAnyPermission(Jenkins.SYSTEM_READ, Jenkins.MANAGE);
|
||||
return ExtensionList.lookupSingleton(MemoryUsageMonitor.class).heap;
|
||||
}
|
||||
}
|
|
@ -2825,11 +2825,13 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
|
|||
}
|
||||
|
||||
/**
|
||||
* Used to bind {@link ExtensionList}s to URLs.
|
||||
* Formerly used to bind {@link ExtensionList}s to URLs.
|
||||
* <p>
|
||||
* Currently handled by {@link jenkins.telemetry.impl.HttpExtensionList.ExtensionListRootAction}.
|
||||
* </p>
|
||||
*
|
||||
* @since 1.349
|
||||
*/
|
||||
@StaplerDispatchable
|
||||
public ExtensionList getExtensionList(String extensionType) throws ClassNotFoundException {
|
||||
return getExtensionList(pluginManager.uberClassLoader.loadClass(extensionType));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2025, 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.telemetry.impl;
|
||||
|
||||
import static java.util.logging.Level.FINE;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.NonNull;
|
||||
import hudson.Extension;
|
||||
import hudson.ExtensionList;
|
||||
import hudson.model.InvisibleAction;
|
||||
import hudson.model.RootAction;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Logger;
|
||||
import jenkins.model.Jenkins;
|
||||
import jenkins.telemetry.Telemetry;
|
||||
import net.sf.json.JSONObject;
|
||||
import org.kohsuke.accmod.Restricted;
|
||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
import org.kohsuke.stapler.Stapler;
|
||||
import org.kohsuke.stapler.StaplerRequest2;
|
||||
|
||||
/**
|
||||
* Collect information about which URLs in {@code /extensionList/} are being accessed.
|
||||
*
|
||||
* @since TODO
|
||||
*/
|
||||
@Extension
|
||||
@Restricted(NoExternalUse.class)
|
||||
public class HttpExtensionList extends Telemetry {
|
||||
private final Map<String, Integer> calls = new ConcurrentHashMap<>();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Extension List access via HTTP";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public LocalDate getStart() {
|
||||
return LocalDate.of(2025, 4, 5);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public LocalDate getEnd() {
|
||||
return LocalDate.of(2025, 7, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized JSONObject createContent() {
|
||||
JSONObject info = new JSONObject();
|
||||
info.put("components", buildComponentInformation());
|
||||
|
||||
Map<String, Integer> currentRequests = new TreeMap<>(calls);
|
||||
calls.clear();
|
||||
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.putAll(currentRequests);
|
||||
|
||||
info.put("dispatches", payload);
|
||||
return info;
|
||||
}
|
||||
|
||||
public synchronized void record(String path) {
|
||||
String[] parts = path.split("/");
|
||||
if (parts.length > 1) {
|
||||
// Record just extension point + implementation class
|
||||
path = parts[0] + '/' + parts[1];
|
||||
}
|
||||
calls.compute(path, (p, v) -> v == null ? 1 : v + 1);
|
||||
}
|
||||
|
||||
@Extension
|
||||
@Restricted(NoExternalUse.class)
|
||||
public static class ExtensionListRootAction extends InvisibleAction implements RootAction {
|
||||
private static final Logger LOGGER = Logger.getLogger(ExtensionListRootAction.class.getName());
|
||||
|
||||
@Override
|
||||
public String getUrlName() {
|
||||
return "extensionList";
|
||||
}
|
||||
|
||||
public ExtensionList getDynamic(String extensionType) throws ClassNotFoundException {
|
||||
StaplerRequest2 req = Stapler.getCurrentRequest2();
|
||||
if (req != null && extensionType != null) {
|
||||
try {
|
||||
final HttpExtensionList telemetry = ExtensionList.lookupSingleton(HttpExtensionList.class);
|
||||
if (telemetry.isActivePeriod()) {
|
||||
telemetry.record(extensionType + req.getRestOfPath());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOGGER.log(FINE, "Failed to record telemetry for " + HttpExtensionList.class.getName(), ex);
|
||||
}
|
||||
}
|
||||
return Jenkins.get().getExtensionList(extensionType);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core">
|
||||
<p>
|
||||
${%blurb}
|
||||
</p>
|
||||
<p>
|
||||
${%blurb2}
|
||||
</p>
|
||||
</j:jelly>
|
|
@ -0,0 +1,4 @@
|
|||
blurb = This trial records uses of an HTTP endpoint granting direct access to extensions, the building blocks of Jenkins's extensibility through plugins. \
|
||||
It is expected that there are few legitimate uses of this endpoint, and this trial informs plans for its eventual removal.
|
||||
blurb2 = Additionally, this trial collects the list of installed plugins, their version, and the version of Jenkins. \
|
||||
This data will be used to understand the environments that Jenkins is running in.
|
|
@ -10,7 +10,7 @@ graphHost.style.aspectRatio = `${imageWidth} / ${imageHeight}`;
|
|||
timespanSelect.addEventListener("change", () => {
|
||||
const rootURL = document.head.dataset.rooturl;
|
||||
const type = timespanSelect.value;
|
||||
graphHost.innerHTML = `<img src="${rootURL}/extensionList/hudson.diagnosis.MemoryUsageMonitor/0/heap/graph?type=${type}&width=${imageWidth}&height=${imageHeight}" srcset="${rootURL}/extensionList/hudson.diagnosis.MemoryUsageMonitor/0/heap/graph?type=${type}&width=${imageWidth}&height=${imageHeight}&scale=2 2x" loading="lazy" style="width: 100%" alt="Memory usage graph"/>`;
|
||||
graphHost.innerHTML = `<img src="${rootURL}/jenkins.diagnosis.MemoryUsageMonitorAction/heap/graph?type=${type}&width=${imageWidth}&height=${imageHeight}" srcset="${rootURL}/jenkins.diagnosis.MemoryUsageMonitorAction/heap/graph?type=${type}&width=${imageWidth}&height=${imageHeight}&scale=2 2x" loading="lazy" style="width: 100%" alt="Memory usage graph"/>`;
|
||||
});
|
||||
|
||||
// Dispatch a change event to insert a graph on page load
|
||||
|
|
Loading…
Reference in New Issue