mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 15:14:52 +09:00
Rename Slave to Host
The role of a slave as a host for Factorio servers is not well reflected in its name and has caused confusion among users. Rename slave to host to better reflect its role as a host of Factorio servers.
This commit is contained in:
1 parent
70ad295a89
commit
6fc3abafd5
101 files changed
+1168
-1168
No files matched your search
@@ -31,33 +31,33 @@ class BaseConnection extends libLink.Link {
|
||||
let instance = this._controller.instances.get(message.data.instance_id);
|
||||
if (!instance) { return; }
|
||||
|
||||
let slaveId = instance.config.get("instance.assigned_slave");
|
||||
if (slaveId === null) { return; }
|
||||
let hostId = instance.config.get("instance.assigned_host");
|
||||
if (hostId === null) { return; }
|
||||
|
||||
let connection = this._controller.wsServer.slaveConnections.get(slaveId);
|
||||
let connection = this._controller.wsServer.hostConnections.get(hostId);
|
||||
if (!connection || connection.closing) { return; }
|
||||
if (event.plugin && !connection.plugins.has(event.plugin)) { return; }
|
||||
|
||||
event.send(connection, message.data);
|
||||
}
|
||||
|
||||
async broadcastEventToSlaves(message, event) {
|
||||
for (let slaveConnection of this._controller.wsServer.slaveConnections.values()) {
|
||||
async broadcastEventToHosts(message, event) {
|
||||
for (let hostConnection of this._controller.wsServer.hostConnections.values()) {
|
||||
// Do not broadcast back to the source
|
||||
if (slaveConnection === this) { continue; }
|
||||
if (slaveConnection.connector.closing) { continue; }
|
||||
if (event.plugin && !slaveConnection.plugins.has(event.plugin)) { continue; }
|
||||
if (hostConnection === this) { continue; }
|
||||
if (hostConnection.connector.closing) { continue; }
|
||||
if (event.plugin && !hostConnection.plugins.has(event.plugin)) { continue; }
|
||||
|
||||
event.send(slaveConnection, message.data);
|
||||
event.send(hostConnection, message.data);
|
||||
}
|
||||
}
|
||||
|
||||
async broadcastEventToInstance(message, event) {
|
||||
await this.broadcastEventToSlaves(message, event);
|
||||
await this.broadcastEventToHosts(message, event);
|
||||
}
|
||||
|
||||
async prepareDisconnectRequestHandler(message, request) {
|
||||
await libPlugin.invokeHook(this._controller.plugins, "onPrepareSlaveDisconnect", this);
|
||||
await libPlugin.invokeHook(this._controller.plugins, "onPrepareHostDisconnect", this);
|
||||
this._disconnecting = true;
|
||||
this.connector.setClosing();
|
||||
return await super.prepareDisconnectRequestHandler(message, request);
|
||||
|
||||
@@ -44,9 +44,9 @@ class ControlConnection extends BaseConnection {
|
||||
*/
|
||||
this.user = user;
|
||||
|
||||
this.slaveSubscriptions = {
|
||||
this.hostSubscriptions = {
|
||||
all: false,
|
||||
slave_ids: [],
|
||||
host_ids: [],
|
||||
};
|
||||
|
||||
this.instanceSubscriptions = {
|
||||
@@ -78,7 +78,7 @@ class ControlConnection extends BaseConnection {
|
||||
this.logSubscriptions = {
|
||||
all: false,
|
||||
controller: false,
|
||||
slave_ids: [],
|
||||
host_ids: [],
|
||||
instance_ids: [],
|
||||
};
|
||||
|
||||
@@ -118,65 +118,65 @@ class ControlConnection extends BaseConnection {
|
||||
this._controller.config.setProp(field, prop, value, "control");
|
||||
}
|
||||
|
||||
async listSlavesRequestHandler(message) {
|
||||
async listHostsRequestHandler(message) {
|
||||
let list = [];
|
||||
for (let slave of this._controller.slaves.values()) {
|
||||
for (let host of this._controller.hosts.values()) {
|
||||
list.push({
|
||||
agent: slave.agent,
|
||||
version: slave.version,
|
||||
id: slave.id,
|
||||
name: slave.name,
|
||||
public_address: slave.public_address || null,
|
||||
connected: this._controller.wsServer.slaveConnections.has(slave.id),
|
||||
agent: host.agent,
|
||||
version: host.version,
|
||||
id: host.id,
|
||||
name: host.name,
|
||||
public_address: host.public_address || null,
|
||||
connected: this._controller.wsServer.hostConnections.has(host.id),
|
||||
});
|
||||
}
|
||||
return { list };
|
||||
}
|
||||
|
||||
async setSlaveSubscriptionsRequestHandler(message) {
|
||||
this.slaveSubscriptions = message.data;
|
||||
async setHostSubscriptionsRequestHandler(message) {
|
||||
this.hostSubscriptions = message.data;
|
||||
}
|
||||
|
||||
slaveUpdated(slave, update) {
|
||||
hostUpdated(host, update) {
|
||||
if (
|
||||
this.slaveSubscriptions.all
|
||||
|| this.slaveSubscriptions.slave_ids.includes(slave.id)
|
||||
this.hostSubscriptions.all
|
||||
|| this.hostSubscriptions.host_ids.includes(host.id)
|
||||
) {
|
||||
libLink.messages.slaveUpdate.send(this, update);
|
||||
libLink.messages.hostUpdate.send(this, update);
|
||||
}
|
||||
}
|
||||
|
||||
generateSlaveToken(slaveId) {
|
||||
generateHostToken(hostId) {
|
||||
return jwt.sign(
|
||||
{ aud: "slave", slave: slaveId },
|
||||
{ aud: "host", host: hostId },
|
||||
Buffer.from(this._controller.config.get("controller.auth_secret"), "base64")
|
||||
);
|
||||
}
|
||||
|
||||
async generateSlaveTokenRequestHandler(message) {
|
||||
let slaveId = message.data.slave_id;
|
||||
if (slaveId === null) {
|
||||
slaveId = Math.random() * 2**31 | 0;
|
||||
async generateHostTokenRequestHandler(message) {
|
||||
let hostId = message.data.host_id;
|
||||
if (hostId === null) {
|
||||
hostId = Math.random() * 2**31 | 0;
|
||||
}
|
||||
return { token: this.generateSlaveToken(slaveId) };
|
||||
return { token: this.generateHostToken(hostId) };
|
||||
}
|
||||
|
||||
async createSlaveConfigRequestHandler(message) {
|
||||
let slaveConfig = new libConfig.SlaveConfig("control");
|
||||
await slaveConfig.init();
|
||||
async createHostConfigRequestHandler(message) {
|
||||
let hostConfig = new libConfig.HostConfig("control");
|
||||
await hostConfig.init();
|
||||
|
||||
slaveConfig.set("slave.controller_url", this._controller.getControllerUrl());
|
||||
hostConfig.set("host.controller_url", this._controller.getControllerUrl());
|
||||
if (message.data.id !== null) {
|
||||
slaveConfig.set("slave.id", message.data.id);
|
||||
hostConfig.set("host.id", message.data.id);
|
||||
}
|
||||
if (message.data.name !== null) {
|
||||
slaveConfig.set("slave.name", message.data.name);
|
||||
hostConfig.set("host.name", message.data.name);
|
||||
}
|
||||
if (message.data.generate_token) {
|
||||
this.user.checkPermission("core.slave.generate_token");
|
||||
slaveConfig.set("slave.controller_token", this.generateSlaveToken(slaveConfig.get("slave.id")));
|
||||
this.user.checkPermission("core.host.generate_token");
|
||||
hostConfig.set("host.controller_token", this.generateHostToken(hostConfig.get("host.id")));
|
||||
}
|
||||
return { serialized_config: slaveConfig.serialize() };
|
||||
return { serialized_config: hostConfig.serialize() };
|
||||
}
|
||||
|
||||
async getInstanceRequestHandler(message) {
|
||||
@@ -186,7 +186,7 @@ class ControlConnection extends BaseConnection {
|
||||
return {
|
||||
id,
|
||||
name: instance.config.get("instance.name"),
|
||||
assigned_slave: instance.config.get("instance.assigned_slave"),
|
||||
assigned_host: instance.config.get("instance.assigned_host"),
|
||||
game_port: instance.game_port || null,
|
||||
status: instance.status,
|
||||
};
|
||||
@@ -198,7 +198,7 @@ class ControlConnection extends BaseConnection {
|
||||
list.push({
|
||||
id: instance.config.get("instance.id"),
|
||||
name: instance.config.get("instance.name"),
|
||||
assigned_slave: instance.config.get("instance.assigned_slave"),
|
||||
assigned_host: instance.config.get("instance.assigned_host"),
|
||||
game_port: instance.game_port || null,
|
||||
status: instance.status,
|
||||
});
|
||||
@@ -218,14 +218,14 @@ class ControlConnection extends BaseConnection {
|
||||
libLink.messages.instanceUpdate.send(this, {
|
||||
id: instance.config.get("instance.id"),
|
||||
name: instance.config.get("instance.name"),
|
||||
assigned_slave: instance.config.get("instance.assigned_slave"),
|
||||
assigned_host: instance.config.get("instance.assigned_host"),
|
||||
game_port: instance.game_port || null,
|
||||
status: instance.status,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// XXX should probably add a hook for slave reuqests?
|
||||
// XXX should probably add a hook for host reuqests?
|
||||
async createInstanceRequestHandler(message) {
|
||||
let instanceConfig = new libConfig.InstanceConfig("controller");
|
||||
await instanceConfig.load(message.data.serialized_config);
|
||||
@@ -269,7 +269,7 @@ class ControlConnection extends BaseConnection {
|
||||
|
||||
async deleteInstanceRequestHandler(message, request) {
|
||||
let instance = this._controller.getRequestInstance(message.data.instance_id);
|
||||
if (instance.config.get("instance.assigned_slave") !== null) {
|
||||
if (instance.config.get("instance.assigned_host") !== null) {
|
||||
await this.forwardRequestToInstance(message, request);
|
||||
}
|
||||
this._controller.instances.delete(message.data.instance_id);
|
||||
@@ -288,13 +288,13 @@ class ControlConnection extends BaseConnection {
|
||||
}
|
||||
|
||||
async updateInstanceConfig(instance) {
|
||||
let slaveId = instance.config.get("instance.assigned_slave");
|
||||
if (slaveId !== null) {
|
||||
let connection = this._controller.wsServer.slaveConnections.get(slaveId);
|
||||
let hostId = instance.config.get("instance.assigned_host");
|
||||
if (hostId !== null) {
|
||||
let connection = this._controller.wsServer.hostConnections.get(hostId);
|
||||
if (connection) {
|
||||
await libLink.messages.assignInstance.send(connection, {
|
||||
instance_id: instance.config.get("instance.id"),
|
||||
serialized_config: instance.config.serialize("slave"),
|
||||
serialized_config: instance.config.serialize("host"),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -302,8 +302,8 @@ class ControlConnection extends BaseConnection {
|
||||
|
||||
async setInstanceConfigFieldRequestHandler(message) {
|
||||
let instance = this._controller.getRequestInstance(message.data.instance_id);
|
||||
if (message.data.field === "instance.assigned_slave") {
|
||||
throw new libErrors.RequestError("instance.assigned_slave must be set through the assign-slave interface");
|
||||
if (message.data.field === "instance.assigned_host") {
|
||||
throw new libErrors.RequestError("instance.assigned_host must be set through the assign-host interface");
|
||||
}
|
||||
|
||||
if (message.data.field === "instance.id") {
|
||||
@@ -323,38 +323,38 @@ class ControlConnection extends BaseConnection {
|
||||
}
|
||||
|
||||
async assignInstanceCommandRequestHandler(message, request) {
|
||||
let { slave_id, instance_id } = message.data;
|
||||
let { host_id, instance_id } = message.data;
|
||||
let instance = this._controller.getRequestInstance(instance_id);
|
||||
|
||||
// Check if target slave is connected
|
||||
let newSlaveConnection;
|
||||
if (slave_id !== null) {
|
||||
newSlaveConnection = this._controller.wsServer.slaveConnections.get(slave_id);
|
||||
if (!newSlaveConnection) {
|
||||
// The case of the slave not getting the assign instance message
|
||||
// Check if target host is connected
|
||||
let newHostConnection;
|
||||
if (host_id !== null) {
|
||||
newHostConnection = this._controller.wsServer.hostConnections.get(host_id);
|
||||
if (!newHostConnection) {
|
||||
// The case of the host not getting the assign instance message
|
||||
// still have to be handled, so it's not a requirement that the
|
||||
// target slave be connected to the controller while doing the
|
||||
// target host be connected to the controller while doing the
|
||||
// assignment, but it is IMHO a better user experience if this
|
||||
// is the case.
|
||||
throw new libErrors.RequestError("Target slave is not connected to the controller");
|
||||
throw new libErrors.RequestError("Target host is not connected to the controller");
|
||||
}
|
||||
}
|
||||
|
||||
// Unassign from currently assigned slave if it is connected.
|
||||
let currentAssignedSlave = instance.config.get("instance.assigned_slave");
|
||||
if (currentAssignedSlave !== null && slave_id !== currentAssignedSlave) {
|
||||
let oldSlaveConnection = this._controller.wsServer.slaveConnections.get(currentAssignedSlave);
|
||||
if (oldSlaveConnection && !oldSlaveConnection.connector.closing) {
|
||||
await libLink.messages.unassignInstance.send(oldSlaveConnection, { instance_id });
|
||||
// Unassign from currently assigned host if it is connected.
|
||||
let currentAssignedHost = instance.config.get("instance.assigned_host");
|
||||
if (currentAssignedHost !== null && host_id !== currentAssignedHost) {
|
||||
let oldHostConnection = this._controller.wsServer.hostConnections.get(currentAssignedHost);
|
||||
if (oldHostConnection && !oldHostConnection.connector.closing) {
|
||||
await libLink.messages.unassignInstance.send(oldHostConnection, { instance_id });
|
||||
}
|
||||
}
|
||||
|
||||
// Assign to target
|
||||
instance.config.set("instance.assigned_slave", slave_id);
|
||||
if (slave_id !== null) {
|
||||
await libLink.messages.assignInstance.send(newSlaveConnection, {
|
||||
instance.config.set("instance.assigned_host", host_id);
|
||||
if (host_id !== null) {
|
||||
await libLink.messages.assignInstance.send(newHostConnection, {
|
||||
instance_id,
|
||||
serialized_config: instance.config.serialize("slave"),
|
||||
serialized_config: instance.config.serialize("host"),
|
||||
});
|
||||
} else {
|
||||
instance.status = "unassigned";
|
||||
@@ -383,7 +383,7 @@ class ControlConnection extends BaseConnection {
|
||||
let ready = new Promise((resolve, reject) => {
|
||||
stream.events.on("source", resolve);
|
||||
stream.events.on("timeout", () => reject(
|
||||
new libErrors.RequestError("Timed out establishing stream from slave")
|
||||
new libErrors.RequestError("Timed out establishing stream from host")
|
||||
));
|
||||
});
|
||||
ready.catch(() => {});
|
||||
@@ -411,29 +411,29 @@ class ControlConnection extends BaseConnection {
|
||||
}
|
||||
let sourceInstance = this._controller.getRequestInstance(instance_id);
|
||||
let targetInstance = this._controller.getRequestInstance(target_instance_id);
|
||||
let sourceSlaveId = sourceInstance.config.get("instance.assigned_slave");
|
||||
let targetSlaveId = targetInstance.config.get("instance.assigned_slave");
|
||||
if (sourceSlaveId === null) {
|
||||
throw new libErrors.RequestError("Source instance is not assigned a slave");
|
||||
let sourceHostId = sourceInstance.config.get("instance.assigned_host");
|
||||
let targetHostId = targetInstance.config.get("instance.assigned_host");
|
||||
if (sourceHostId === null) {
|
||||
throw new libErrors.RequestError("Source instance is not assigned a host");
|
||||
}
|
||||
if (targetSlaveId === null) {
|
||||
throw new libErrors.RequestError("Target instance is not assigned a slave");
|
||||
if (targetHostId === null) {
|
||||
throw new libErrors.RequestError("Target instance is not assigned a host");
|
||||
}
|
||||
|
||||
// Let slave handle request if source and target is on the same slave.
|
||||
if (sourceSlaveId === targetSlaveId) {
|
||||
// Let host handle request if source and target is on the same host.
|
||||
if (sourceHostId === targetHostId) {
|
||||
return await this.forwardRequestToInstance(message, request);
|
||||
}
|
||||
|
||||
// Check connectivity
|
||||
let sourceSlaveConnection = this._controller.wsServer.slaveConnections.get(sourceSlaveId);
|
||||
if (!sourceSlaveConnection || sourceSlaveConnection.closing) {
|
||||
throw new libErrors.RequestError("Source slave is not connected to the controller");
|
||||
let sourceHostConnection = this._controller.wsServer.hostConnections.get(sourceHostId);
|
||||
if (!sourceHostConnection || sourceHostConnection.closing) {
|
||||
throw new libErrors.RequestError("Source host is not connected to the controller");
|
||||
}
|
||||
|
||||
let targetSlaveConnection = this._controller.wsServer.slaveConnections.get(targetSlaveId);
|
||||
if (!targetSlaveConnection || targetSlaveConnection.closing) {
|
||||
throw new libErrors.RequestError("Target slave is not connected to the controller");
|
||||
let targetHostConnection = this._controller.wsServer.hostConnections.get(targetHostId);
|
||||
if (!targetHostConnection || targetHostConnection.closing) {
|
||||
throw new libErrors.RequestError("Target host is not connected to the controller");
|
||||
}
|
||||
|
||||
// Create stream to proxy from target to source
|
||||
@@ -448,8 +448,8 @@ class ControlConnection extends BaseConnection {
|
||||
// Ignore errors if not listening for them to avoid crash.
|
||||
stream.events.on("error", () => { /* ignore */ });
|
||||
|
||||
// Establish push from source slave to stream, this is done first to
|
||||
// ensure the file size is known prior to the target slave pull.
|
||||
// Establish push from source host to stream, this is done first to
|
||||
// ensure the file size is known prior to the target host pull.
|
||||
await Promise.all([
|
||||
this._controller.forwardRequestToInstance(libLink.messages.pushSave, {
|
||||
instance_id,
|
||||
@@ -459,7 +459,7 @@ class ControlConnection extends BaseConnection {
|
||||
events.once(stream.events, "source"),
|
||||
]);
|
||||
|
||||
// Establish pull from target slave to stream and wait for completion.
|
||||
// Establish pull from target host to stream and wait for completion.
|
||||
let result = await this._controller.forwardRequestToInstance(libLink.messages.pullSave, {
|
||||
instance_id: target_instance_id,
|
||||
stream_id: stream.id,
|
||||
@@ -668,8 +668,8 @@ class ControlConnection extends BaseConnection {
|
||||
}
|
||||
|
||||
updateLogSubscriptions() {
|
||||
let { all, controller, slave_ids, instance_ids } = this.logSubscriptions;
|
||||
if (all || controller || slave_ids.length || instance_ids.length) {
|
||||
let { all, controller, host_ids, instance_ids } = this.logSubscriptions;
|
||||
if (all || controller || host_ids.length || instance_ids.length) {
|
||||
if (!this.logTransport) {
|
||||
this.logTransport = new libLoggingUtils.LinkTransport({ link: this });
|
||||
this._controller.clusterLogger.add(this.logTransport);
|
||||
@@ -684,10 +684,10 @@ class ControlConnection extends BaseConnection {
|
||||
|
||||
async queryLogRequestHandler(message) {
|
||||
let observeDuration = queryLogTime.startTimer();
|
||||
let { all, controller, slave_ids, instance_ids } = message.data;
|
||||
let { all, controller, host_ids, instance_ids } = message.data;
|
||||
|
||||
let log;
|
||||
if (!all && controller && !slave_ids.length && !instance_ids.length) {
|
||||
if (!all && controller && !host_ids.length && !instance_ids.length) {
|
||||
log = await this._controller.queryControllerLog(message.data);
|
||||
} else {
|
||||
log = await this._controller.queryClusterLog(message.data);
|
||||
@@ -886,7 +886,7 @@ class ControlConnection extends BaseConnection {
|
||||
|
||||
user.isAdmin = admin;
|
||||
this._controller.userUpdated(user);
|
||||
this.broadcastEventToSlaves({ data: { name, admin }}, libLink.messages.adminlistUpdate);
|
||||
this.broadcastEventToHosts({ data: { name, admin }}, libLink.messages.adminlistUpdate);
|
||||
}
|
||||
|
||||
async setUserBannedRequestHandler(message) {
|
||||
@@ -904,7 +904,7 @@ class ControlConnection extends BaseConnection {
|
||||
user.isBanned = banned;
|
||||
user.banReason = reason;
|
||||
this._controller.userUpdated(user);
|
||||
this.broadcastEventToSlaves({ data: { name, banned, reason }}, libLink.messages.banlistUpdate);
|
||||
this.broadcastEventToHosts({ data: { name, banned, reason }}, libLink.messages.banlistUpdate);
|
||||
}
|
||||
|
||||
async setUserWhitelistedRequestHandler(message) {
|
||||
@@ -921,7 +921,7 @@ class ControlConnection extends BaseConnection {
|
||||
|
||||
user.isWhitelisted = whitelisted;
|
||||
this._controller.userUpdated(user);
|
||||
this.broadcastEventToSlaves({ data: { name, whitelisted }}, libLink.messages.whitelistUpdate);
|
||||
this.broadcastEventToHosts({ data: { name, whitelisted }}, libLink.messages.whitelistUpdate);
|
||||
}
|
||||
|
||||
async deleteUserRequestHandler(message) {
|
||||
@@ -935,13 +935,13 @@ class ControlConnection extends BaseConnection {
|
||||
this._controller.userUpdated(user);
|
||||
|
||||
if (user.is_admin) {
|
||||
this.broadcastEventToSlaves({ data: { name, admin: false }}, libLink.messages.adminlistUpdate);
|
||||
this.broadcastEventToHosts({ data: { name, admin: false }}, libLink.messages.adminlistUpdate);
|
||||
}
|
||||
if (user.is_whitelisted) {
|
||||
this.broadcastEventToSlaves({ data: { name, whitelisted: false }}, libLink.messages.whitelistUpdate);
|
||||
this.broadcastEventToHosts({ data: { name, whitelisted: false }}, libLink.messages.whitelistUpdate);
|
||||
}
|
||||
if (user.is_banned) {
|
||||
this.broadcastEventToSlaves({ data: { name, banned: false, reason: "" }}, libLink.messages.banlistUpdate);
|
||||
this.broadcastEventToHosts({ data: { name, banned: false, reason: "" }}, libLink.messages.banlistUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,10 +61,10 @@ class Controller {
|
||||
this.app.locals.streams = new Map();
|
||||
|
||||
/**
|
||||
* Mapping of slave id to slave info
|
||||
* Mapping of host id to host info
|
||||
* @type {Map<number, Object>}
|
||||
*/
|
||||
this.slaves = null;
|
||||
this.hosts = null;
|
||||
|
||||
/**
|
||||
* Mapping of instance id to instance info
|
||||
@@ -145,7 +145,7 @@ class Controller {
|
||||
return (await Promise.all([
|
||||
libFileOps.directorySize(path.join(this.logDirectory, "cluster")),
|
||||
libFileOps.directorySize(path.join(this.logDirectory, "controller")),
|
||||
libFileOps.directorySize(path.join(this.logDirectory, "slave")),
|
||||
libFileOps.directorySize(path.join(this.logDirectory, "host")),
|
||||
])).reduce((a, v) => a + v, 0);
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ class Controller {
|
||||
let databaseDirectory = this.config.get("controller.database_directory");
|
||||
await fs.ensureDir(databaseDirectory);
|
||||
|
||||
this.slaves = await Controller.loadSlaves(path.join(databaseDirectory, "slaves.json"));
|
||||
this.hosts = await Controller.loadHosts(path.join(databaseDirectory, "hosts.json"));
|
||||
this.instances = await Controller.loadInstances(path.join(databaseDirectory, "instances.json"));
|
||||
this.modPacks = await Controller.loadModPacks(path.join(databaseDirectory, "mod-packs.json"));
|
||||
this.userManager = new UserManager(this.config);
|
||||
@@ -313,8 +313,8 @@ class Controller {
|
||||
}
|
||||
|
||||
let databaseDirectory = this.config.get("controller.database_directory");
|
||||
if (this.slaves) {
|
||||
await Controller.saveSlaves(path.join(databaseDirectory, "slaves.json"), this.slaves);
|
||||
if (this.hosts) {
|
||||
await Controller.saveHosts(path.join(databaseDirectory, "hosts.json"), this.hosts);
|
||||
}
|
||||
|
||||
if (this.instances) {
|
||||
@@ -344,7 +344,7 @@ class Controller {
|
||||
logger.info("Goodbye");
|
||||
}
|
||||
|
||||
static async loadSlaves(filePath) {
|
||||
static async loadHosts(filePath) {
|
||||
let serialized;
|
||||
try {
|
||||
serialized = JSON.parse(await fs.readFile(filePath));
|
||||
@@ -365,8 +365,8 @@ class Controller {
|
||||
return new Map(serialized);
|
||||
}
|
||||
|
||||
static async saveSlaves(filePath, slaves) {
|
||||
await libFileOps.safeOutputFile(filePath, JSON.stringify([...slaves.entries()], null, 4));
|
||||
static async saveHosts(filePath, hosts) {
|
||||
await libFileOps.safeOutputFile(filePath, JSON.stringify([...hosts.entries()], null, 4));
|
||||
}
|
||||
|
||||
static async loadInstances(filePath) {
|
||||
@@ -378,7 +378,7 @@ class Controller {
|
||||
for (let serializedConfig of serialized) {
|
||||
let instanceConfig = new libConfig.InstanceConfig("controller");
|
||||
await instanceConfig.load(serializedConfig);
|
||||
let status = instanceConfig.get("instance.assigned_slave") === null ? "unassigned" : "unknown";
|
||||
let status = instanceConfig.get("instance.assigned_host") === null ? "unassigned" : "unknown";
|
||||
let instance = { config: instanceConfig, status };
|
||||
instances.set(instanceConfig.get("instance.id"), instance);
|
||||
}
|
||||
@@ -543,14 +543,14 @@ class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
slaveUpdated(slave) {
|
||||
hostUpdated(host) {
|
||||
let update = {
|
||||
agent: slave.agent,
|
||||
version: slave.version,
|
||||
id: slave.id,
|
||||
name: slave.name,
|
||||
public_address: slave.public_address || null,
|
||||
connected: this.wsServer.slaveConnections.has(slave.id),
|
||||
agent: host.agent,
|
||||
version: host.version,
|
||||
id: host.id,
|
||||
name: host.name,
|
||||
public_address: host.public_address || null,
|
||||
connected: this.wsServer.hostConnections.has(host.id),
|
||||
};
|
||||
|
||||
for (let controlConnection of this.wsServer.controlConnections) {
|
||||
@@ -558,7 +558,7 @@ class Controller {
|
||||
continue;
|
||||
}
|
||||
|
||||
controlConnection.slaveUpdated(slave, update);
|
||||
controlConnection.hostUpdated(host, update);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,9 +801,9 @@ class Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* Forward the given request to the slave contaning the instance
|
||||
* Forward the given request to the host contaning the instance
|
||||
*
|
||||
* Finds the slave which the instance with the given instance ID is
|
||||
* Finds the host which the instance with the given instance ID is
|
||||
* currently assigned to and forwards the request to that instance.
|
||||
* The request data must have an instance_id parameter.
|
||||
*
|
||||
@@ -815,17 +815,17 @@ class Controller {
|
||||
*/
|
||||
async forwardRequestToInstance(request, data) {
|
||||
let instance = this.getRequestInstance(data.instance_id);
|
||||
let slaveId = instance.config.get("instance.assigned_slave");
|
||||
if (slaveId === null) {
|
||||
throw new libErrors.RequestError("Instance is not assigned to a slave");
|
||||
let hostId = instance.config.get("instance.assigned_host");
|
||||
if (hostId === null) {
|
||||
throw new libErrors.RequestError("Instance is not assigned to a host");
|
||||
}
|
||||
|
||||
let connection = this.wsServer.slaveConnections.get(slaveId);
|
||||
let connection = this.wsServer.hostConnections.get(hostId);
|
||||
if (!connection) {
|
||||
throw new libErrors.RequestError("Slave containing instance is not connected");
|
||||
throw new libErrors.RequestError("Host containing instance is not connected");
|
||||
}
|
||||
if (request.plugin && !connection.plugins.has(request.plugin)) {
|
||||
throw new libErrors.RequestError(`Slave containing instance does not have ${request.plugin} plugin`);
|
||||
throw new libErrors.RequestError(`Host containing instance does not have ${request.plugin} plugin`);
|
||||
}
|
||||
|
||||
return await request.send(connection, data);
|
||||
|
||||
+27
-27
@@ -9,14 +9,14 @@ const BaseConnection = require("./BaseConnection");
|
||||
|
||||
|
||||
/**
|
||||
* Represents the connection to a slave
|
||||
* Represents the connection to a host
|
||||
*
|
||||
* @extends module:controller/src/BaseConnection
|
||||
* @alias module:controller/src/SlaveConnection
|
||||
* @alias module:controller/src/HostConnection
|
||||
*/
|
||||
class SlaveConnection extends BaseConnection {
|
||||
class HostConnection extends BaseConnection {
|
||||
constructor(registerData, connector, controller) {
|
||||
super("slave", connector, controller);
|
||||
super("host", connector, controller);
|
||||
|
||||
this._agent = registerData.agent;
|
||||
this._id = registerData.id;
|
||||
@@ -25,7 +25,7 @@ class SlaveConnection extends BaseConnection {
|
||||
this.plugins = new Map(Object.entries(registerData.plugins));
|
||||
this._checkPluginVersions();
|
||||
|
||||
this._controller.slaves.set(this._id, {
|
||||
this._controller.hosts.set(this._id, {
|
||||
agent: this._agent,
|
||||
id: this._id,
|
||||
name: this._name,
|
||||
@@ -38,15 +38,15 @@ class SlaveConnection extends BaseConnection {
|
||||
// eslint-disable-next-line no-loop-func
|
||||
this.connector.on(event, () => {
|
||||
for (let plugin of this._controller.plugins.values()) {
|
||||
plugin.onSlaveConnectionEvent(this, event);
|
||||
plugin.onHostConnectionEvent(this, event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.connector.on("close", () => {
|
||||
// Update status to unknown for instances on this slave.
|
||||
// Update status to unknown for instances on this host.
|
||||
for (let instance of this._controller.instances.values()) {
|
||||
if (instance.config.get("instance.assigned_slave") !== this._id) {
|
||||
if (instance.config.get("instance.assigned_host") !== this._id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -63,13 +63,13 @@ class SlaveConnection extends BaseConnection {
|
||||
for (let [name, version] of this.plugins) {
|
||||
let info = pluginInfos.get(name);
|
||||
if (!info) {
|
||||
logger.warn(`Slave ${this._name} has plugin ${name} ${version} which the controller does not have`);
|
||||
logger.warn(`Host ${this._name} has plugin ${name} ${version} which the controller does not have`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (info.version !== version) {
|
||||
logger.warn(
|
||||
`Slave ${this._name} has plugin ${name} ${version} which does not match the version of this ` +
|
||||
`Host ${this._name} has plugin ${name} ${version} which does not match the version of this ` +
|
||||
`plugin on the controller (${info.version})`
|
||||
);
|
||||
}
|
||||
@@ -77,15 +77,15 @@ class SlaveConnection extends BaseConnection {
|
||||
|
||||
for (let [name, info] of pluginInfos) {
|
||||
if (!this.plugins.has(name)) {
|
||||
logger.warn(`Slave ${this._name} is missing plugin ${name} ${info.version}`);
|
||||
logger.warn(`Host ${this._name} is missing plugin ${name} ${info.version}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the slave this connection is connected to
|
||||
* ID of the host this connection is connected to
|
||||
*
|
||||
* @returns {number} slave ID.
|
||||
* @returns {number} host ID.
|
||||
*/
|
||||
get id() {
|
||||
return this._id;
|
||||
@@ -95,17 +95,17 @@ class SlaveConnection extends BaseConnection {
|
||||
let instance = this._controller.instances.get(message.data.instance_id);
|
||||
|
||||
// It's possible to get updates from an instance that does not exist
|
||||
// or is not assigned to the slave it originated from if it was
|
||||
// reassigned or deleted while the connection to the slave it was
|
||||
// or is not assigned to the host it originated from if it was
|
||||
// reassigned or deleted while the connection to the host it was
|
||||
// originally on was down at the time.
|
||||
if (!instance || instance.config.get("instance.assigned_slave") !== this._id) {
|
||||
if (!instance || instance.config.get("instance.assigned_host") !== this._id) {
|
||||
logger.warn(`Got bogus update for instance id ${message.data.instance_id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// We may receive status changed where the status hasn't changed
|
||||
// from our perspective if the connection was down at the time it
|
||||
// changed. Slaves also send status updates on assignInstance which
|
||||
// changed. Hosts also send status updates on assignInstance which
|
||||
// for hacky reason is also used to push config changes and
|
||||
// restablish status after a connection loss.
|
||||
if (instance.status === message.data.status) {
|
||||
@@ -123,23 +123,23 @@ class SlaveConnection extends BaseConnection {
|
||||
async updateInstancesRequestHandler(message) {
|
||||
// Push updated instance configs
|
||||
for (let instance of this._controller.instances.values()) {
|
||||
if (instance.config.get("instance.assigned_slave") === this._id) {
|
||||
if (instance.config.get("instance.assigned_host") === this._id) {
|
||||
await libLink.messages.assignInstance.send(this, {
|
||||
instance_id: instance.config.get("instance.id"),
|
||||
serialized_config: instance.config.serialize("slave"),
|
||||
serialized_config: instance.config.serialize("host"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Assign instances the slave has but controller does not
|
||||
// Assign instances the host has but controller does not
|
||||
for (let instanceData of message.data.instances) {
|
||||
let instanceConfig = new libConfig.InstanceConfig("controller");
|
||||
await instanceConfig.load(instanceData.serialized_config, "slave");
|
||||
await instanceConfig.load(instanceData.serialized_config, "host");
|
||||
|
||||
let controllerInstance = this._controller.instances.get(instanceConfig.get("instance.id"));
|
||||
if (controllerInstance) {
|
||||
// Check if this instance is assigned somewhere else.
|
||||
if (controllerInstance.config.get("instance.assigned_slave") !== this._id) {
|
||||
if (controllerInstance.config.get("instance.assigned_host") !== this._id) {
|
||||
await libLink.messages.unassignInstance.send(this, {
|
||||
instance_id: controllerInstance.config.get("instance.id"),
|
||||
});
|
||||
@@ -159,13 +159,13 @@ class SlaveConnection extends BaseConnection {
|
||||
continue;
|
||||
}
|
||||
|
||||
instanceConfig.set("instance.assigned_slave", this._id);
|
||||
instanceConfig.set("instance.assigned_host", this._id);
|
||||
let newInstance = { config: instanceConfig, status: instanceData.status };
|
||||
this._controller.instances.set(instanceConfig.get("instance.id"), newInstance);
|
||||
this._controller.addInstanceHooks(newInstance);
|
||||
await libLink.messages.assignInstance.send(this, {
|
||||
instance_id: instanceConfig.get("instance.id"),
|
||||
serialized_config: instanceConfig.serialize("slave"),
|
||||
serialized_config: instanceConfig.serialize("host"),
|
||||
});
|
||||
await libPlugin.invokeHook(this._controller.plugins, "onInstanceStatusChanged", newInstance, null);
|
||||
}
|
||||
@@ -197,8 +197,8 @@ class SlaveConnection extends BaseConnection {
|
||||
async logMessageEventHandler(message) {
|
||||
this._controller.clusterLogger.log({
|
||||
...message.data.info,
|
||||
slave_id: this._id,
|
||||
slave_name: this._name,
|
||||
host_id: this._id,
|
||||
host_name: this._name,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -224,4 +224,4 @@ class SlaveConnection extends BaseConnection {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SlaveConnection;
|
||||
module.exports = HostConnection;
|
||||
@@ -9,7 +9,7 @@ const libSchema = require("@clusterio/lib/schema");
|
||||
|
||||
const ControlConnection = require("./ControlConnection");
|
||||
const packageVersion = require("../package").version;
|
||||
const SlaveConnection = require("./SlaveConnection");
|
||||
const HostConnection = require("./HostConnection");
|
||||
const WsServerConnector = require("./WsServerConnector");
|
||||
|
||||
|
||||
@@ -41,8 +41,8 @@ class WsServer {
|
||||
|
||||
/** @type {Array<module:controller/src/ControlConnection>} */
|
||||
this.controlConnections = [];
|
||||
/** @type {Map<number, module:controller/src/SlaveConnection>} */
|
||||
this.slaveConnections = new Map();
|
||||
/** @type {Map<number, module:controller/src/HostConnection>} */
|
||||
this.hostConnections = new Map();
|
||||
/** @type {Map<number, module:controller/src/WsServerConnector>} */
|
||||
this.activeConnectors = new Map();
|
||||
/** @type {Set<module:ws>} */
|
||||
@@ -68,8 +68,8 @@ class WsServer {
|
||||
disconnectTasks.push(controlConnection.disconnect(1001, "Server Quit"));
|
||||
}
|
||||
|
||||
for (let slaveConnection of this.slaveConnections.values()) {
|
||||
disconnectTasks.push(slaveConnection.disconnect(1001, "Server Quit"));
|
||||
for (let hostConnection of this.hostConnections.values()) {
|
||||
disconnectTasks.push(hostConnection.disconnect(1001, "Server Quit"));
|
||||
}
|
||||
|
||||
logger.info(`WsServer | Waiting for ${disconnectTasks.length} connectors to close`);
|
||||
@@ -212,15 +212,15 @@ ${err.stack}`
|
||||
// Validate token
|
||||
let user;
|
||||
try {
|
||||
if (type === "register_slave") {
|
||||
if (type === "register_host") {
|
||||
let tokenPayload = jwt.verify(
|
||||
data.token,
|
||||
Buffer.from(this.controller.config.get("controller.auth_secret"), "base64"),
|
||||
{ audience: "slave" }
|
||||
{ audience: "host" }
|
||||
);
|
||||
|
||||
if (tokenPayload.slave !== data.id) {
|
||||
throw new Error("missmatched slave id");
|
||||
if (tokenPayload.host !== data.id) {
|
||||
throw new Error("missmatched host id");
|
||||
}
|
||||
|
||||
} else if (type === "register_control") {
|
||||
@@ -262,34 +262,34 @@ ${err.stack}`
|
||||
});
|
||||
|
||||
let additionalReadyData = {};
|
||||
if (type === "register_slave") {
|
||||
let connection = this.slaveConnections.get(data.id);
|
||||
if (type === "register_host") {
|
||||
let connection = this.hostConnections.get(data.id);
|
||||
if (connection) {
|
||||
logger.verbose(`WsServer | disconnecting existing connection for slave ${data.id}`);
|
||||
logger.verbose(`WsServer | disconnecting existing connection for host ${data.id}`);
|
||||
await connection.disconnect(1008, "Registered from another connection");
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`WsServer | registered slave ${data.name} (${data.id}) using agent ${data.agent} ${data.version}`
|
||||
`WsServer | registered host ${data.name} (${data.id}) using agent ${data.agent} ${data.version}`
|
||||
);
|
||||
if (data.agent === "Clusterio Slave" && data.version !== packageVersion) {
|
||||
if (data.agent === "Clusterio Host" && data.version !== packageVersion) {
|
||||
logger.warn(
|
||||
`Host ${data.name} (${data.id}) connected using version ${data.version} which does not match the ` +
|
||||
`version of the controller is currently running (${packageVersion}). It may not work as expected.`
|
||||
);
|
||||
}
|
||||
|
||||
connection = new SlaveConnection(data, connector, this.controller);
|
||||
connection = new HostConnection(data, connector, this.controller);
|
||||
connector.on("close", () => {
|
||||
if (this.slaveConnections.get(data.id) === connection) {
|
||||
this.slaveConnections.delete(data.id);
|
||||
this.controller.slaveUpdated(this.controller.slaves.get(data.id));
|
||||
if (this.hostConnections.get(data.id) === connection) {
|
||||
this.hostConnections.delete(data.id);
|
||||
this.controller.hostUpdated(this.controller.hosts.get(data.id));
|
||||
} else {
|
||||
logger.warn("Unlisted SlaveConnection closed");
|
||||
logger.warn("Unlisted HostConnection closed");
|
||||
}
|
||||
});
|
||||
this.slaveConnections.set(data.id, connection);
|
||||
this.controller.slaveUpdated(this.controller.slaves.get(data.id));
|
||||
this.hostConnections.set(data.id, connection);
|
||||
this.controller.hostUpdated(this.controller.hosts.get(data.id));
|
||||
|
||||
|
||||
} else if (type === "register_control") {
|
||||
|
||||
@@ -49,14 +49,14 @@ async function getMetrics(req, res, next) {
|
||||
|
||||
let requests = [];
|
||||
let timeout = req.app.locals.controller.config.get("controller.metrics_timeout") * 1000;
|
||||
for (let slaveConnection of req.app.locals.controller.wsServer.slaveConnections.values()) {
|
||||
if (!slaveConnection.connected) {
|
||||
for (let hostConnection of req.app.locals.controller.wsServer.hostConnections.values()) {
|
||||
if (!hostConnection.connected) {
|
||||
continue;
|
||||
}
|
||||
requests.push(libHelpers.timeout(
|
||||
libLink.messages.getMetrics.send(slaveConnection).catch(err => {
|
||||
libLink.messages.getMetrics.send(hostConnection).catch(err => {
|
||||
if (!(err instanceof libErrors.SessionLost)) {
|
||||
logger.error(`Unexpected error gathering metrics from slave:\n${err.stack}`);
|
||||
logger.error(`Unexpected error gathering metrics from host:\n${err.stack}`);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
@@ -80,7 +80,7 @@ async function getMetrics(req, res, next) {
|
||||
resultMap.set(result.metric.name, result);
|
||||
|
||||
} else {
|
||||
// Merge metrics received by multiple slaves
|
||||
// Merge metrics received by multiple hosts
|
||||
mergeSamples(resultMap.get(result.metric.name), result);
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ function getPlugins(req, res) {
|
||||
res.send(plugins);
|
||||
}
|
||||
|
||||
function validateSlaveToken(req, res, next) {
|
||||
function validateHostToken(req, res, next) {
|
||||
let token = req.header("x-access-token");
|
||||
if (!token) {
|
||||
res.sendStatus(401);
|
||||
@@ -134,7 +134,7 @@ function validateSlaveToken(req, res, next) {
|
||||
jwt.verify(
|
||||
token,
|
||||
Buffer.from(req.app.locals.controller.config.get("controller.auth_secret"), "base64"),
|
||||
{ audience: "slave" }
|
||||
{ audience: "host" }
|
||||
);
|
||||
|
||||
} catch (err) {
|
||||
@@ -356,7 +356,7 @@ async function uploadSave(req, res) {
|
||||
let timeout = new Promise((_, reject) => {
|
||||
proxyStream.events.on("timeout", () => {
|
||||
stream.resume();
|
||||
reject(new Error("Timed out establishing stream to slave"));
|
||||
reject(new Error("Timed out establishing stream to host"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -609,7 +609,7 @@ function addRouteHandlers(app) {
|
||||
app.get("/metrics", (req, res, next) => getMetrics(req, res, next).catch(next));
|
||||
app.get("/api/plugins", getPlugins);
|
||||
app.put("/api/upload-export",
|
||||
validateSlaveToken,
|
||||
validateHostToken,
|
||||
(req, res, next) => uploadExport(req, res).catch(next)
|
||||
);
|
||||
app.put("/api/stream/:id", (req, res, next) => putStream(req, res).catch(next));
|
||||
@@ -628,8 +628,8 @@ function addRouteHandlers(app) {
|
||||
const webRoutes = [
|
||||
"/",
|
||||
"/controller",
|
||||
"/slaves",
|
||||
"/slaves/:id/view",
|
||||
"/hosts",
|
||||
"/hosts/:id/view",
|
||||
"/instances",
|
||||
"/instances/:id/view",
|
||||
"/mods",
|
||||
|
||||
Reference in new issue
Block a user