mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-11 15:04:52 +09:00
Add a request to mark hosts and the controller as needing a restart (#1043)
* Add a request to mark hosts and the controller as needing a restart Not every plugin arrives through PluginInstallRequest. Plugins checked out into external_plugins or installed by hand on the machine never flag a restart, so the web UI shows nothing and tooling that acts on the flag never fires. HostMarkRestartRequiredRequest and ControllerMarkRestartRequiredRequest set config.restartRequired, guarded by the existing restart permissions. They are exposed as "Mark Restart Required" in the control dropdown of the host and controller pages, hidden once the flag is set, and as mark-restart-required ctl commands. The mark shows up on the next system metrics poll. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Cover the mark-restart-required ctl commands Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
commit
2efb53aab1
13 files changed
+112
-1
No files matched your search
@@ -43,6 +43,14 @@ The controller also supports remote updates, following the same logic. The corre
|
||||
ctl> controller update [--restart]
|
||||
controller> config set controller.allow_remote_updates true/false
|
||||
|
||||
### Mark restart required
|
||||
|
||||
ctl> host mark-restart-required <host>
|
||||
|
||||
Marks the host as requiring a restart, the same way a plugin update does. Use it after installing or changing a plugin by other means than `host plugin install`, such as a plugin checked out into `external_plugins`. The mark shows up in the web interface on the next system metrics poll. The controller has the same command:
|
||||
|
||||
ctl> controller mark-restart-required
|
||||
|
||||
## Instances
|
||||
|
||||
### List Instances
|
||||
|
||||
@@ -73,6 +73,9 @@ export default class ControlConnection extends BaseConnection {
|
||||
|
||||
this.handle(lib.ControllerStopRequest, this.handleControllerStopRequest.bind(this));
|
||||
this.handle(lib.ControllerRestartRequest, this.handleControllerRestartRequest.bind(this));
|
||||
this.handle(
|
||||
lib.ControllerMarkRestartRequiredRequest, this.handleControllerMarkRestartRequiredRequest.bind(this)
|
||||
);
|
||||
this.handle(lib.ControllerUpdateRequest, this.handleControllerUpdateRequest.bind(this));
|
||||
this.handle(lib.ControllerConfigGetRequest, this.handleControllerConfigGetRequest.bind(this));
|
||||
this.handle(lib.ControllerConfigSetRequest, this.handleControllerConfigSetRequest.bind(this));
|
||||
@@ -1297,6 +1300,10 @@ export default class ControlConnection extends BaseConnection {
|
||||
return usersToSend;
|
||||
}
|
||||
|
||||
async handleControllerMarkRestartRequiredRequest() {
|
||||
this._controller.config.restartRequired = true;
|
||||
}
|
||||
|
||||
async handleControllerUpdateRequest(request: lib.ControllerUpdateRequest) {
|
||||
if (!this._controller.config.get("controller.allow_remote_updates")) {
|
||||
throw new lib.RequestError("Remote updates are disabled on this machine");
|
||||
|
||||
@@ -25,6 +25,12 @@ controllerCommands.add(new lib.Command({
|
||||
await ctl.send(new lib.ControllerRestartRequest());
|
||||
},
|
||||
}));
|
||||
controllerCommands.add(new lib.Command({
|
||||
definition: ["mark-restart-required", "Mark the controller as requiring a restart"],
|
||||
handler: async function(_args: object, ctl: Ctl) {
|
||||
await ctl.send(new lib.ControllerMarkRestartRequiredRequest());
|
||||
},
|
||||
}));
|
||||
controllerCommands.add(new lib.Command({
|
||||
definition: ["update", "Update the controller", (yargs) => {
|
||||
yargs.option("restart", { alias: "r", type: "boolean", description: "Restart after update" });
|
||||
|
||||
@@ -33,6 +33,16 @@ hostCommands.add(new lib.Command({
|
||||
},
|
||||
}));
|
||||
|
||||
hostCommands.add(new lib.Command({
|
||||
definition: ["mark-restart-required <host>", "Mark the given host as requiring a restart", (yargs) => {
|
||||
yargs.positional("host", { describe: "Host to mark", type: "string" });
|
||||
}],
|
||||
handler: async function(args: { host: string }, ctl: Ctl) {
|
||||
let hostId = await lib.resolveHost(ctl, args.host);
|
||||
await ctl.sendTo({ hostId }, new lib.HostMarkRestartRequiredRequest());
|
||||
},
|
||||
}));
|
||||
|
||||
hostCommands.add(new lib.Command({
|
||||
definition: [["list", "l"], "List hosts connected to the controller"],
|
||||
handler: async function(args: object, ctl: Ctl) {
|
||||
|
||||
@@ -390,6 +390,7 @@ export default class Host extends lib.Link {
|
||||
|
||||
this.handle(lib.HostStopRequest, this.handleHostStopRequest.bind(this));
|
||||
this.handle(lib.HostRestartRequest, this.handleHostRestartRequest.bind(this));
|
||||
this.handle(lib.HostMarkRestartRequiredRequest, this.handleHostMarkRestartRequiredRequest.bind(this));
|
||||
this.handle(lib.HostUpdateRequest, this.handleHostUpdateRequest.bind(this));
|
||||
this.handle(lib.HostConfigGetRequest, this.handleHostConfigGetRequest.bind(this));
|
||||
this.handle(lib.HostConfigSetRequest, this.handleHostConfigSetRequest.bind(this));
|
||||
@@ -511,6 +512,10 @@ export default class Host extends lib.Link {
|
||||
this.shutdown();
|
||||
}
|
||||
|
||||
async handleHostMarkRestartRequiredRequest() {
|
||||
this.config.restartRequired = true;
|
||||
}
|
||||
|
||||
async handleHostConfigGetRequest() {
|
||||
return this.config.toRemote("control");
|
||||
}
|
||||
|
||||
@@ -20,6 +20,14 @@ export class ControllerRestartRequest {
|
||||
static permission = "core.controller.restart" as const;
|
||||
}
|
||||
|
||||
export class ControllerMarkRestartRequiredRequest {
|
||||
declare ["constructor"]: typeof ControllerMarkRestartRequiredRequest;
|
||||
static type = "request" as const;
|
||||
static src = "control" as const;
|
||||
static dst = "controller" as const;
|
||||
static permission = "core.controller.restart" as const;
|
||||
}
|
||||
|
||||
export class ControllerUpdateRequest {
|
||||
declare ["constructor"]: typeof ControllerUpdateRequest;
|
||||
static type = "request" as const;
|
||||
|
||||
@@ -20,6 +20,14 @@ export class HostRestartRequest {
|
||||
static permission = "core.host.restart" as const;
|
||||
}
|
||||
|
||||
export class HostMarkRestartRequiredRequest {
|
||||
declare ["constructor"]: typeof HostMarkRestartRequiredRequest;
|
||||
static type = "request" as const;
|
||||
static src = ["control", "controller"] as const;
|
||||
static dst = "host" as const;
|
||||
static permission = "core.host.restart" as const;
|
||||
}
|
||||
|
||||
export class HostUpdateRequest {
|
||||
declare ["constructor"]: typeof HostUpdateRequest;
|
||||
static type = "request" as const;
|
||||
|
||||
@@ -21,6 +21,7 @@ export const dataClasses: (RequestClass<unknown, unknown> | EventClass<unknown>)
|
||||
|
||||
controller.ControllerStopRequest,
|
||||
controller.ControllerRestartRequest,
|
||||
controller.ControllerMarkRestartRequiredRequest,
|
||||
controller.ControllerUpdateRequest,
|
||||
controller.ControllerConfigGetRequest,
|
||||
controller.ControllerConfigSetRequest,
|
||||
@@ -43,6 +44,7 @@ export const dataClasses: (RequestClass<unknown, unknown> | EventClass<unknown>)
|
||||
|
||||
host.HostStopRequest,
|
||||
host.HostRestartRequest,
|
||||
host.HostMarkRestartRequiredRequest,
|
||||
host.HostUpdateRequest,
|
||||
host.HostConfigGetRequest,
|
||||
host.HostConfigSetRequest,
|
||||
|
||||
@@ -16,7 +16,7 @@ import ControlContext from "./ControlContext";
|
||||
import ControllerConfigTree from "./ControllerConfigTree";
|
||||
import PageHeader from "./PageHeader";
|
||||
import PageLayout from "./PageLayout";
|
||||
import { notifyErrorHandler } from "../util/notify";
|
||||
import notify, { notifyErrorHandler } from "../util/notify";
|
||||
import webUiPackage from "../../package.json";
|
||||
import { hasNpmButtonPermission, NpmButton } from "./NpmButton";
|
||||
import VariableDropdownButton, { VariableDropdownButtonProps } from "./VariableDropdownButton";
|
||||
@@ -47,6 +47,20 @@ function ControllerControlButton({ canRestart, restartRequired }: ControllerCont
|
||||
});
|
||||
}
|
||||
|
||||
if (account.hasPermission("core.controller.restart") && !restartRequired) {
|
||||
actions.push({
|
||||
key: "mark-restart-required",
|
||||
label: "Mark Restart Required",
|
||||
onClick: () => {
|
||||
control.send(
|
||||
new lib.ControllerMarkRestartRequiredRequest()
|
||||
).then(() => {
|
||||
notify("Controller marked as requiring a restart", "success");
|
||||
}).catch(notifyErrorHandler("Error marking controller"));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (account.hasPermission("core.controller.stop")) {
|
||||
actions.push({
|
||||
key: "stop",
|
||||
|
||||
@@ -52,6 +52,21 @@ function HostControlButton({ hostId, canRestart, restartRequired }: HostControlB
|
||||
});
|
||||
}
|
||||
|
||||
if (account.hasPermission("core.host.restart") && !restartRequired) {
|
||||
actions.push({
|
||||
key: "mark-restart-required",
|
||||
label: "Mark Restart Required",
|
||||
onClick: () => {
|
||||
control.sendTo(
|
||||
{ hostId },
|
||||
new lib.HostMarkRestartRequiredRequest()
|
||||
).then(() => {
|
||||
notify("Host marked as requiring a restart", "success");
|
||||
}).catch(notifyErrorHandler("Error marking host"));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (account.hasPermission("core.host.stop")) {
|
||||
actions.push({
|
||||
key: "stop",
|
||||
|
||||
@@ -550,6 +550,12 @@ describe("Integration of Clusterio", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("controller mark-restart-required", function() {
|
||||
it("runs", async function() {
|
||||
await execCtl("controller mark-restart-required");
|
||||
});
|
||||
});
|
||||
|
||||
describe("host list", function() {
|
||||
it("runs", async function() {
|
||||
await execCtl("host list");
|
||||
@@ -635,6 +641,12 @@ describe("Integration of Clusterio", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("host mark-restart-required", function() {
|
||||
it("runs", async function() {
|
||||
await execCtl("host mark-restart-required 4");
|
||||
});
|
||||
});
|
||||
|
||||
describe("host generate-token", function() {
|
||||
it("runs", async function() {
|
||||
await execCtl("host generate-token --id 42");
|
||||
|
||||
@@ -29,6 +29,15 @@ describe("messages/controller", function() {
|
||||
controlConnection = new ControlConnection({ version: "2.0.0" }, connection, controller, user, 1);
|
||||
});
|
||||
|
||||
describe("ControllerMarkRestartRequiredRequest", function() {
|
||||
it("runs", async function() {
|
||||
await controlConnection.handleControllerMarkRestartRequiredRequest(
|
||||
new lib.ControllerMarkRestartRequiredRequest()
|
||||
);
|
||||
assert.equal(controller.config.restartRequired, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ControllerUpdateRequest", function() {
|
||||
it("runs", async function() {
|
||||
controller.config.set("controller.allow_remote_updates", true);
|
||||
|
||||
@@ -32,6 +32,13 @@ describe("messages/host", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("HostMarkRestartRequiredRequest", function() {
|
||||
it("runs", async function() {
|
||||
await host.handleHostMarkRestartRequiredRequest(new lib.HostMarkRestartRequiredRequest());
|
||||
assert.equal(host.config.restartRequired, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("HostConfigGetRequest", function() {
|
||||
it("runs", async function() {
|
||||
const config = await host.handleHostConfigGetRequest(new lib.HostConfigGetRequest());
|
||||
|
||||
Reference in new issue
Block a user