mirror of
https://github.com/MarginaliaSearch/MarginaliaSearch.git
synced 2025-02-24 05:18:58 +00:00
(control) Node configuration
This commit is contained in:
parent
4baf9527d7
commit
6308a8dfcd
@ -1,5 +1,6 @@
|
|||||||
package nu.marginalia.nodecfg;
|
package nu.marginalia.nodecfg;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
import nu.marginalia.nodecfg.model.NodeConfiguration;
|
import nu.marginalia.nodecfg.model.NodeConfiguration;
|
||||||
|
|
||||||
@ -11,6 +12,7 @@ public class NodeConfigurationService {
|
|||||||
|
|
||||||
private final HikariDataSource dataSource;
|
private final HikariDataSource dataSource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
public NodeConfigurationService(HikariDataSource dataSource) {
|
public NodeConfigurationService(HikariDataSource dataSource) {
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
}
|
}
|
||||||
@ -48,7 +50,9 @@ public class NodeConfigurationService {
|
|||||||
FROM NODE_CONFIGURATION
|
FROM NODE_CONFIGURATION
|
||||||
""")) {
|
""")) {
|
||||||
var rs = qs.executeQuery();
|
var rs = qs.executeQuery();
|
||||||
|
|
||||||
List<NodeConfiguration> ret = new ArrayList<>();
|
List<NodeConfiguration> ret = new ArrayList<>();
|
||||||
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
ret.add(new NodeConfiguration(
|
ret.add(new NodeConfiguration(
|
||||||
rs.getInt("ID"),
|
rs.getInt("ID"),
|
||||||
|
@ -10,6 +10,8 @@ import nu.marginalia.control.node.model.*;
|
|||||||
import nu.marginalia.control.sys.model.EventLogEntry;
|
import nu.marginalia.control.sys.model.EventLogEntry;
|
||||||
import nu.marginalia.control.sys.svc.EventLogService;
|
import nu.marginalia.control.sys.svc.EventLogService;
|
||||||
import nu.marginalia.control.sys.svc.HeartbeatService;
|
import nu.marginalia.control.sys.svc.HeartbeatService;
|
||||||
|
import nu.marginalia.nodecfg.NodeConfigurationService;
|
||||||
|
import nu.marginalia.nodecfg.model.NodeConfiguration;
|
||||||
import nu.marginalia.storage.FileStorageService;
|
import nu.marginalia.storage.FileStorageService;
|
||||||
import nu.marginalia.executor.client.ExecutorClient;
|
import nu.marginalia.executor.client.ExecutorClient;
|
||||||
import nu.marginalia.executor.model.crawl.RecrawlParameters;
|
import nu.marginalia.executor.model.crawl.RecrawlParameters;
|
||||||
@ -37,6 +39,7 @@ public class ControlNodeService {
|
|||||||
private final ExecutorClient executorClient;
|
private final ExecutorClient executorClient;
|
||||||
private final HikariDataSource dataSource;
|
private final HikariDataSource dataSource;
|
||||||
private final ServiceMonitors monitors;
|
private final ServiceMonitors monitors;
|
||||||
|
private final NodeConfigurationService nodeConfigurationService;
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
@ -48,7 +51,7 @@ public class ControlNodeService {
|
|||||||
HeartbeatService heartbeatService,
|
HeartbeatService heartbeatService,
|
||||||
ExecutorClient executorClient,
|
ExecutorClient executorClient,
|
||||||
HikariDataSource dataSource,
|
HikariDataSource dataSource,
|
||||||
ServiceMonitors monitors)
|
ServiceMonitors monitors, NodeConfigurationService nodeConfigurationService)
|
||||||
{
|
{
|
||||||
this.fileStorageService = fileStorageService;
|
this.fileStorageService = fileStorageService;
|
||||||
this.rendererFactory = rendererFactory;
|
this.rendererFactory = rendererFactory;
|
||||||
@ -57,6 +60,7 @@ public class ControlNodeService {
|
|||||||
this.executorClient = executorClient;
|
this.executorClient = executorClient;
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
this.monitors = monitors;
|
this.monitors = monitors;
|
||||||
|
this.nodeConfigurationService = nodeConfigurationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void register() throws IOException {
|
public void register() throws IOException {
|
||||||
@ -82,7 +86,9 @@ public class ControlNodeService {
|
|||||||
Spark.post("/public/nodes/:id/storage/new-specs", this::createNewSpecsAction);
|
Spark.post("/public/nodes/:id/storage/new-specs", this::createNewSpecsAction);
|
||||||
|
|
||||||
Spark.get("/public/nodes/:id/storage/:view", this::nodeStorageListModel, storageListRenderer::render);
|
Spark.get("/public/nodes/:id/storage/:view", this::nodeStorageListModel, storageListRenderer::render);
|
||||||
|
|
||||||
Spark.get("/public/nodes/:id/configuration", this::nodeConfigModel, configRenderer::render);
|
Spark.get("/public/nodes/:id/configuration", this::nodeConfigModel, configRenderer::render);
|
||||||
|
Spark.post("/public/nodes/:id/configuration", this::updateConfigModel, configRenderer::render);
|
||||||
|
|
||||||
Spark.post("/public/nodes/:id/storage/recrawl-auto", this::triggerAutoRecrawl);
|
Spark.post("/public/nodes/:id/storage/recrawl-auto", this::triggerAutoRecrawl);
|
||||||
Spark.post("/public/nodes/:id/storage/process-auto", this::triggerAutoProcess);
|
Spark.post("/public/nodes/:id/storage/process-auto", this::triggerAutoProcess);
|
||||||
@ -284,11 +290,45 @@ public class ControlNodeService {
|
|||||||
"storage", storage);
|
"storage", storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object nodeConfigModel(Request request, Response response) {
|
private Object nodeConfigModel(Request request, Response response) throws SQLException {
|
||||||
int nodeId = Integer.parseInt(request.params("id"));
|
int nodeId = Integer.parseInt(request.params("id"));
|
||||||
|
|
||||||
|
Map<String, Path> storage = new HashMap<>();
|
||||||
|
|
||||||
|
for (var baseType : List.of(FileStorageBaseType.CURRENT, FileStorageBaseType.WORK, FileStorageBaseType.BACKUP, FileStorageBaseType.STORAGE)) {
|
||||||
|
Optional.ofNullable(fileStorageService.getStorageBase(baseType, nodeId))
|
||||||
|
.map(FileStorageBase::asPath)
|
||||||
|
.ifPresent(path -> storage.put(baseType.toString().toLowerCase(), path));
|
||||||
|
}
|
||||||
|
|
||||||
return Map.of(
|
return Map.of(
|
||||||
"node", new IndexNode(nodeId)
|
"node", new IndexNode(nodeId),
|
||||||
|
"config", Objects.requireNonNull(nodeConfigurationService.get(nodeId), "Failed to fetch configuration"),
|
||||||
|
"storage", storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object updateConfigModel(Request request, Response response) throws SQLException {
|
||||||
|
int nodeId = Integer.parseInt(request.params("id"));
|
||||||
|
String act = request.queryParams("act");
|
||||||
|
|
||||||
|
if ("config".equals(act)) {
|
||||||
|
var newConfig = new NodeConfiguration(
|
||||||
|
nodeId,
|
||||||
|
request.queryParams("description"),
|
||||||
|
"on".equalsIgnoreCase(request.queryParams("acceptQueries")),
|
||||||
|
"on".equalsIgnoreCase(request.queryParams("disabled"))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
nodeConfigurationService.save(newConfig);
|
||||||
|
}
|
||||||
|
else if ("storage".equals(act)) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Spark.halt(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeConfigModel(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object nodeOverviewModel(Request request, Response response) throws SQLException {
|
private Object nodeOverviewModel(Request request, Response response) throws SQLException {
|
||||||
|
@ -29,12 +29,39 @@
|
|||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="mt-2">
|
<h1 class="my-5">Node Configuration</h1>
|
||||||
{{> control/partials/processes-table }}
|
|
||||||
|
<div class="m-4 p-4 border">
|
||||||
|
<h2>Settings</h2>
|
||||||
|
|
||||||
|
<form method="post" action="?act=config">
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="description" class="form-label">Description</label>
|
||||||
|
<input class="form-control" type="text" name="description" value="{{config.description}}"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2">
|
|
||||||
{{> control/partials/events-table-summary }}
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" type="checkbox" role="switch" name="acceptQueries" {{#if config.acceptQueries}}checked{{/if}}>
|
||||||
|
<label class="form-check-label" for="acceptQueries">Accept queries</label>
|
||||||
|
|
||||||
|
<div class="form-text">Sets whether queries will be routed to this node</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check form-switch mb-3">
|
||||||
|
<input class="form-check-input" type="checkbox" role="switch" name="disabled" {{#if config.disabled}}checked{{/if}}>
|
||||||
|
<label class="form-check-label" for="disabled">Disabled</label>
|
||||||
|
|
||||||
|
<div class="form-text">Disabling a node is a soft delete that prevents the index and
|
||||||
|
control service from starting</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary">Save</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
Loading…
Reference in New Issue
Block a user