Skip to content
Merged
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
24be93a
Allow custom message and more user information for safe restarts
meiswjn Nov 10, 2022
dbf0194
Merge branch 'master' into feature/improve-safe-restart-messages
meiswjn Nov 10, 2022
3c4b989
Fix linting
meiswjn Nov 11, 2022
4beaa7b
Merge branch 'feature/improve-safe-restart-messages' of https://githu…
meiswjn Nov 11, 2022
7121f6d
Fix linter issues and deprecations
meiswjn Nov 11, 2022
9980d18
Minor changes to formulations and style
meiswjn Nov 11, 2022
feaf3a1
Minor changes to formulations and style
meiswjn Nov 11, 2022
4fc22a2
Fix CI issues
meiswjn Nov 16, 2022
b5b35f5
Merge branch 'master' into feature/improve-safe-restart-messages
meiswjn Nov 16, 2022
650eed0
Use TODO tag in javadoc since-param
meiswjn Nov 16, 2022
a344b08
Merge branch 'jenkinsci:master' into feature/improve-safe-restart-mes…
meiswjn Nov 16, 2022
99d5ed6
Merge branch 'feature/improve-safe-restart-messages' of https://githu…
meiswjn Nov 16, 2022
c7f7795
Merge branch 'master' into feature/improve-safe-restart-messages
meiswjn Nov 18, 2022
bcbffe1
Restrict isPreparingSafeRestart()
meiswjn Nov 18, 2022
8635553
Merge branch 'master' into feature/improve-safe-restart-messages
NotMyFault Jan 13, 2023
fb4eecd
Merge branch 'master' into feature/improve-safe-restart-messages
meiswjn Jan 16, 2023
402b30c
Remove duplicate code
meiswjn Jan 16, 2023
6e1b715
Merge branch 'feature/improve-safe-restart-messages' of https://githu…
meiswjn Jan 16, 2023
d4fe2b7
Add conditional jelly tag for safe restart
meiswjn Jan 17, 2023
5abd8c0
Adapt translation
meiswjn Jan 17, 2023
0f1fba9
Merge branch 'master' into feature/improve-safe-restart-messages
meiswjn Jan 17, 2023
8a4ff7c
Fix spotbugs and checkstyle
meiswjn Jan 17, 2023
ea7bc73
Merge branch 'feature/improve-safe-restart-messages' of https://githu…
meiswjn Jan 17, 2023
b0178b1
Another try for spotbugs null path
meiswjn Jan 18, 2023
25ce12e
Another try for spotbugs null path
meiswjn Jan 18, 2023
12e0483
Apply suggestions from code review
meiswjn Jan 18, 2023
09243fc
Adapt comments, messages and translations
meiswjn Jan 18, 2023
1e5074e
Adapt translation
meiswjn Jan 18, 2023
989d836
Update translations and move messages to dedicated file
meiswjn Jan 19, 2023
7f792a3
Apply suggestions from @timja
meiswjn Feb 2, 2023
5c4b20f
Merge branch 'feature/improve-safe-restart-messages' of https://githu…
meiswjn Feb 2, 2023
0ec3323
Fix message display logic
meiswjn Feb 2, 2023
75710c0
Use pre-defined colors
meiswjn Feb 2, 2023
612aa46
Update core/src/main/resources/hudson/util/HudsonIsRestarting/index_d…
meiswjn Feb 2, 2023
f961cd7
Replace br tag with css
meiswjn Feb 2, 2023
6b16167
Merge branch 'master' into feature/improve-safe-restart-messages
meiswjn Feb 2, 2023
33681e1
Use pre-defined color
meiswjn Feb 2, 2023
c9dd18d
Merge branch 'feature/improve-safe-restart-messages' of https://githu…
meiswjn Feb 2, 2023
326ebfb
Apply yarn fix
meiswjn Feb 2, 2023
67b92a2
Fix spotbugs
meiswjn Feb 2, 2023
9446037
Add SafeRestart CLI Command
meiswjn Feb 13, 2023
c6ffe16
Merge branch 'master' into feature/improve-safe-restart-messages
meiswjn Feb 13, 2023
ebb285d
Fix spotbugs issues
meiswjn Feb 14, 2023
bd250a2
Merge branch 'feature/improve-safe-restart-messages' of https://githu…
meiswjn Feb 14, 2023
4779b46
Update SafeRestartCommand.java
meiswjn Feb 21, 2023
459ec06
Update SafeRestartCommand.java
meiswjn Feb 21, 2023
8571d73
Merge branch 'master' into feature/improve-safe-restart-messages
meiswjn Feb 21, 2023
773b1bd
Update SafeRestartCommand.java
meiswjn Feb 21, 2023
2d82089
Merge branch 'master' into feature/improve-safe-restart-messages
NotMyFault Mar 25, 2023
7730051
Merge branch 'master' into feature/improve-safe-restart-messages
timja Apr 21, 2023
f11d5eb
Merge branch 'master' into feature/improve-safe-restart-messages
daniel-beck May 12, 2023
66900a3
Merge branch 'jenkinsci:master' into feature/improve-safe-restart-mes…
meiswjn May 22, 2023
de78fce
chore: answer review comments
meiswjn May 22, 2023
1553c03
fix: undo translation change
meiswjn May 23, 2023
b80928c
Improve UI
timja May 23, 2023
b6f78bb
UI improvements (and simplified translating of page)
timja May 23, 2023
e177791
Merge branch 'master' into feature/improve-safe-restart-messages
NotMyFault Jun 8, 2023
8b657f4
Merge branch 'master' into feature/improve-safe-restart-messages
meiswjn Jun 23, 2023
85dc1bd
chore: fix description
meiswjn Jun 29, 2023
23107ec
Merge branch 'master' into feature/improve-safe-restart-messages
NotMyFault Jun 30, 2023
1bee860
Merge branch 'master' into feature/improve-safe-restart-messages
meiswjn Jul 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions core/src/main/java/hudson/util/HudsonIsRestarting.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,29 @@
* @author Kohsuke Kawaguchi
*/
public class HudsonIsRestarting {
private boolean safeRestart;

/**
* @since TODO
*/
public HudsonIsRestarting(boolean safeRestart) {
this.safeRestart = safeRestart;
}

@Deprecated
public HudsonIsRestarting() {
this.safeRestart = false;
}
Comment thread
meiswjn marked this conversation as resolved.

public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
rsp.setStatus(SC_SERVICE_UNAVAILABLE);
req.getView(this, "index.jelly").forward(req, rsp);
}

/**
* @since TODO
*/
public boolean isSafeRestart() {
return safeRestart;
}
}
59 changes: 59 additions & 0 deletions core/src/main/java/jenkins/cli/SafeRestartCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* The MIT License
*
* Copyright (c) 2023, Jan Meiswinkel
*
* 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.cli;
Comment thread
meiswjn marked this conversation as resolved.

import hudson.Extension;
import hudson.cli.CLICommand;
import hudson.cli.Messages;
import java.util.logging.Logger;
import jenkins.model.Jenkins;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.args4j.Option;

/**
* Safe Restart Jenkins - do not accept any new jobs and try to pause existing.
*
* @since TODO
*/
@Extension
Comment thread
meiswjn marked this conversation as resolved.
@Restricted(NoExternalUse.class)
public class SafeRestartCommand extends CLICommand {
private static final Logger LOGGER = Logger.getLogger(SafeRestartCommand.class.getName());

@Option(name = "-message", usage = "Message for safe restart that will be visible to users")
public String message = null;

@Override
public String getShortDescription() {
return Messages.SafeRestartCommand_ShortDescription();
}

@Override
protected int run() throws Exception {
Jenkins.get().doSafeRestart(null, message);
return 0;
}
}
115 changes: 94 additions & 21 deletions core/src/main/java/jenkins/model/Jenkins.java
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve

@CheckForNull
private transient volatile QuietDownInfo quietDownInfo;

Comment thread
meiswjn marked this conversation as resolved.
private transient volatile boolean terminating;
@GuardedBy("Jenkins.class")
private transient boolean cleanUpStarted;
Expand Down Expand Up @@ -2943,6 +2944,20 @@ public boolean isQuietingDown() {
return quietDownInfo != null;
}

/**
* Returns if the quietingDown is a safe restart.
* @since TODO
*/
@Restricted(NoExternalUse.class)
@NonNull
public boolean isPreparingSafeRestart() {
Comment thread
meiswjn marked this conversation as resolved.
QuietDownInfo quietDownInfo = this.quietDownInfo;
if (quietDownInfo != null) {
return quietDownInfo.isSafeRestart();
}
return false;
}

/**
* Returns quiet down reason if it was indicated.
* @return
Expand All @@ -2953,7 +2968,7 @@ public boolean isQuietingDown() {
@CheckForNull
public String getQuietDownReason() {
final QuietDownInfo info = quietDownInfo;
return info != null ? info.reason : null;
return info != null ? info.message : null;
}

/**
Expand Down Expand Up @@ -4093,7 +4108,7 @@ public synchronized HttpRedirect doQuietDown() {
*
* @param block Block until the system really quiets down and no builds are running
* @param timeout If non-zero, only block up to the specified number of milliseconds
* @deprecated since 2.267; use {@link #doQuietDown(boolean, int, String)} instead.
* @deprecated since 2.267; use {@link #doQuietDown(boolean, int, String, boolean)} instead.
Comment thread
meiswjn marked this conversation as resolved.
*/
@Deprecated
public synchronized HttpRedirect doQuietDown(boolean block, int timeout) {
Expand All @@ -4109,16 +4124,34 @@ public synchronized HttpRedirect doQuietDown(boolean block, int timeout) {
*
* @param block Block until the system really quiets down and no builds are running
* @param timeout If non-zero, only block up to the specified number of milliseconds
* @param reason Quiet reason that will be visible to user
* @since 2.267
* @param message Quiet reason that will be visible to user
* @deprecated use {@link #doQuietDown(boolean, int, String, boolean)} instead.
*/
@Deprecated(since = "TODO")
public HttpRedirect doQuietDown(boolean block,
int timeout,
@CheckForNull String message) throws InterruptedException, IOException {

return doQuietDown(block, timeout, message, false);
}

/**
* Quiet down Jenkins - preparation for a restart
*
* @param block Block until the system really quiets down and no builds are running
* @param timeout If non-zero, only block up to the specified number of milliseconds
* @param message Quiet reason that will be visible to user
* @param safeRestart If the quietDown is for a safeRestart
* @since TODO
*/
@RequirePOST
public HttpRedirect doQuietDown(@QueryParameter boolean block,
@QueryParameter int timeout,
@QueryParameter @CheckForNull String reason) throws InterruptedException, IOException {
@QueryParameter @CheckForNull String message,
@QueryParameter boolean safeRestart) throws InterruptedException, IOException {
synchronized (this) {
checkPermission(MANAGE);
quietDownInfo = new QuietDownInfo(reason);
quietDownInfo = new QuietDownInfo(message, safeRestart);
}
if (block) {
long waitUntil = timeout;
Expand Down Expand Up @@ -4513,20 +4546,35 @@ public void doRestart(StaplerRequest req, StaplerResponse rsp) throws IOExceptio
}

/**
* Queues up a restart of Jenkins for when there are no builds running, if we can.
* Queues up a safe restart of Jenkins.
* Builds that cannot continue while the controller is not running have to finish or pause before it can proceed.
* No new builds will be started. No new jobs are accepted.
*
* This first replaces "app" to {@link HudsonIsRestarting}
* @deprecated use {@link #doSafeRestart(StaplerRequest, String)} instead.
*
* @since 1.332

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please keep

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@meiswjn ⬆️

*/
@CLIMethod(name = "safe-restart")
@Deprecated(since = "TODO")
public HttpResponse doSafeRestart(StaplerRequest req) throws IOException, ServletException, RestartNotSupportedException {
return doSafeRestart(req, null);
}

/**
* Queues up a safe restart of Jenkins. Jobs have to finish or pause before it can proceed. No new jobs are accepted.
*
* @since TODO
*/
public HttpResponse doSafeRestart(StaplerRequest req, @QueryParameter("message") String message) throws IOException, ServletException, RestartNotSupportedException {
checkPermission(MANAGE);
if (req != null && req.getMethod().equals("GET"))
if (req != null && req.getMethod().equals("GET")) {
return HttpResponses.forwardToView(this, "_safeRestart.jelly");
}

if (req != null && req.getParameter("cancel") != null) {
return doCancelQuietDown();
}

if (req == null || req.getMethod().equals("POST")) {
safeRestart();
safeRestart(message);
}

return HttpResponses.redirectToDot();
Expand Down Expand Up @@ -4572,11 +4620,22 @@ public void run() {
/**
* Queues up a restart to be performed once there are no builds currently running.
* @since 1.332
Comment thread
meiswjn marked this conversation as resolved.
* @deprecated use {@link #safeRestart(String)} instead.
*/
@Deprecated(since = "TODO")
public void safeRestart() throws RestartNotSupportedException {
safeRestart(null);
}

/**
* Queues up a restart to be performed once there are no builds currently running.
* @param message the message to show to users in the shutdown banner.
* @since TODO
*/
public void safeRestart(String message) throws RestartNotSupportedException {
final Lifecycle lifecycle = restartableLifecycle();
// Quiet down so that we won't launch new builds.
quietDownInfo = new QuietDownInfo();
quietDownInfo = new QuietDownInfo(message, true);

new Thread("safe-restart thread") {
final String exitUser = getAuthentication2().getName();
Expand All @@ -4585,11 +4644,10 @@ public void run() {
try (ACLContext ctx = ACL.as2(ACL.SYSTEM2)) {

// Wait 'til we have no active executors.
doQuietDown(true, 0, null);

doQuietDown(true, 0, message, true);
// Make sure isQuietingDown is still true.
if (isQuietingDown()) {
servletContext.setAttribute("app", new HudsonIsRestarting());
servletContext.setAttribute("app", new HudsonIsRestarting(true));
// give some time for the browser to load the "reloading" page
lifecycle.onStatusUpdate("Restart in 10 seconds");
Thread.sleep(TimeUnit.SECONDS.toMillis(10));
Expand Down Expand Up @@ -5761,16 +5819,31 @@ private static void _setJenkinsJVM(boolean jenkinsJVM) {
}

private static final class QuietDownInfo {

@CheckForNull
final String reason;
final String message;

private boolean safeRestart;

QuietDownInfo() {
this(null);
this(null, false);
}

QuietDownInfo(final String message) {
this(message, false);
}

QuietDownInfo(final String message, final boolean safeRestart) {
this.message = message;
this.safeRestart = safeRestart;
}


boolean isSafeRestart() {
return safeRestart;
}

QuietDownInfo(final String reason) {
this.reason = reason;
void setSafeRestart(boolean safeRestart) {
this.safeRestart = safeRestart;
}
}
}
1 change: 1 addition & 0 deletions core/src/main/resources/hudson/cli/Messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ ReloadConfigurationCommand.ShortDescription=Discard all the loaded data in memor
ConnectNodeCommand.ShortDescription=Reconnect to a node(s)
DisconnectNodeCommand.ShortDescription=Disconnects from a node.
QuietDownCommand.ShortDescription=Quiet down Jenkins, in preparation for a restart. Don’t start any builds.
SafeRestartCommand.ShortDescription=Safe Restart Jenkins. Don't start any builds and try to existing.
Comment thread
meiswjn marked this conversation as resolved.
Outdated
CancelQuietDownCommand.ShortDescription=Cancel the effect of the "quiet-down" command.
OfflineNodeCommand.ShortDescription=Stop using a node for performing builds temporarily, until the next "online-node" command.
WaitNodeOnlineCommand.ShortDescription=Wait for a node to become online.
Expand Down
1 change: 1 addition & 0 deletions core/src/main/resources/hudson/cli/Messages_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ ListPluginsCommand.ShortDescription=Gibt eine Liste installierter Plugins aus.
OfflineNodeCommand.ShortDescription=Knoten wird bis zum nächsten "online-node"-Kommando für keine neuen Builds verwendet.
OnlineNodeCommand.ShortDescription=Knoten wird wieder für neue Builds verwendet. Hebt ein vorausgegangenes "offline-node"-Kommando auf.
QuietDownCommand.ShortDescription=Keine neuen Builds mehr starten, z.B. zur Vorbereitung eines Neustarts.
SafeRestartCommand.ShortDescription=Sicheren Neustart einleiten. Keine neuen Builds mehr starten und versuchen, laufende zu pausieren.
ReloadConfigurationCommand.ShortDescription=Alle Daten im Speicher verwerfen und Konfiguration neu von Festplatte laden. Dies ist nützlich, wenn Sie Änderungen direkt im Dateisystem vorgenommen haben.
ReloadJobCommand.ShortDescription=Lädt ein Element neu.
RemoveJobFromViewCommand.ShortDescription=Entfernt Elemente aus einer Ansicht
Expand Down
11 changes: 11 additions & 0 deletions core/src/main/resources/hudson/util/HudsonIsRestarting/index.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ THE SOFTWARE.
<p class="restarting">
${%Your browser will reload automatically when Jenkins is ready.}
</p>
<j:if test="${it.safeRestart}">
<div class="safe-restarting">
<p>
<strong>${%Safe Restart}</strong>
</p>
<p>
${%Builds on agents can usually continue.}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth pointing out that this applies only to Pipeline builds, not to other project types?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea!
"Pipeline builds on agents can usually continue."

What would you think about that?

</p>
</div>
</j:if>

</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
Please\ wait\ while\ Jenkins\ is\ restarting=Jenkins wird neu gestartet. Bitte warten
Please\ wait\ while\ Jenkins\ is\ restarting=Jenkins wird neu gestartet. Bitte warten.
Your\ browser\ will\ reload\ automatically\ when\ Jenkins\ is\ ready.=Der Webbrowser wird diese Seite automatisch neu laden, sobald Jenkins hochgefahren ist.
Safe\ Restart=Sicherer Neustart
Builds\ on\ agents\ can\ usually\ continue.=Builds auf Agenten laufen in der Regel weiter.
Restart=Neustarten
Cancel=Abbrechen
25 changes: 18 additions & 7 deletions core/src/main/resources/jenkins/model/Jenkins/_safeRestart.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,30 @@ THE SOFTWARE.
<!-- Delete view -->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<l:layout title="Safely Restart Jenkins">
<l:layout title="${%Safe restart}">
<st:include page="sidepanel.jelly" />
<l:breadcrumb title="${%Safe Restart}" />
<l:breadcrumb title="${%Safe restart}" />
<l:main-panel>
<l:app-bar title="${%Safe restart}" />
<j:choose>
<j:when test="${app.lifecycle.canRestart()}">
<form method="post" action="safeRestart">
${%confirmRestart}
<f:submit value="${%Yes}" />
</form>
<p>${%restartWarning}</p>

<form method="post" action="safeRestart">
<f:entry title="${%Jenkins is restarting banner}"
description="${%description}">
<f:textbox name="message" value="${app.quietDownReason ?: null}"/>
</f:entry>
<f:bottomButtonBar>
<f:submit clazz="jenkins-!-destructive-color" value="${%Restart}"/>
<j:if test="${app.isQuietingDown()}">
<f:submit name="cancel" primary="false" value="${%Cancel}"/>
</j:if>
</f:bottomButtonBar>
</form>
</j:when>
<j:otherwise>
${%Jenkins cannot restart itself as currently configured.}
${%cannotRestart}
</j:otherwise>
</j:choose>
</l:main-panel>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

confirmRestart=\
Are you sure you want to restart Jenkins? \
Jenkins will restart once all running jobs are finished. \
cannotRestart=Jenkins cannot restart itself as currently configured.
description=This will be displayed on most Jenkins pages, you can use it to let users know what is happening. A default message will be added if you don't supply one.
restartWarning=Jenkins will try to pause jobs and restart once all running jobs are either finished or paused. \
(Pipeline builds may prevent Jenkins from restarting for a short period of time in some cases, but if so, they will be paused at the next available opportunity and then resumed after Jenkins restarts.)
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,5 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

Jenkins\ cannot\ restart\ itself\ as\ currently\ configured.=\
cannotRestart=\
С текущите си настройки Jenkins не може да се рестартира.
Yes=\
Да
Loading