From add986cff9c8e1a00428122a0d5515e6bd00120f Mon Sep 17 00:00:00 2001
From: Kai Reinhard <K.Reinhard@micromata.de>
Date: Sat, 05 Jan 2019 03:03:04 +0000
Subject: [PATCH] Job monitor...
---
borgbutler-webapp/src/components/views/jobs/JobMonitorPanel.jsx | 47 ++++++++---
borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java | 4
borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/ProgressInfo.java | 11 +-
borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java | 12 +-
borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/queue/JsonJob.java | 41 ++++++----
borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java | 76 ++++++++++++++++++
borgbutler-webapp/src/components/views/jobs/JobQueue.jsx | 42 +++++++--
7 files changed, 178 insertions(+), 55 deletions(-)
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java
index 8fd89f3..72f2aee 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgCommands.java
@@ -172,7 +172,7 @@
.setParams("--json-lines")
.setDescription("Loading list of files of archive '" + archive.getName() + "' of repo '" + repoConfig.getDisplayName() + "'.");
// The returned job might be an already queued or running one!
- final ProgressMessage progressMessage = new ProgressMessage()
+ final ProgressInfo progressInfo = new ProgressInfo()
.setMessage("Getting file list...")
.setCurrent(0);
BorgJob<List<BorgFilesystemItem>> job = BorgQueueExecutor.getInstance().execute(new BorgJob<List<BorgFilesystemItem>>(command) {
@@ -181,7 +181,7 @@
BorgFilesystemItem item = JsonUtils.fromJson(BorgFilesystemItem.class, line);
item.setMtime(DateUtils.format(item.getMtime()));
payload.add(item);
- setProgressMessage(progressMessage.incrementCurrent());
+ setProgressInfo(progressInfo.incrementCurrent());
}
});
job.payload = new ArrayList<>();
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java
index f2e6892..79e78ba 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/BorgJob.java
@@ -5,7 +5,7 @@
import de.micromata.borgbutler.data.Archive;
import de.micromata.borgbutler.jobs.AbstractCommandLineJob;
import de.micromata.borgbutler.json.JsonUtils;
-import de.micromata.borgbutler.json.borg.ProgressMessage;
+import de.micromata.borgbutler.json.borg.ProgressInfo;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
@@ -34,7 +34,7 @@
@Getter
@Setter(AccessLevel.PROTECTED)
- private ProgressMessage progressMessage;
+ private ProgressInfo progressInfo;
public BorgJob(BorgCommand command) {
this.command = command;
@@ -73,9 +73,9 @@
protected void processStdErrLine(String line, int level) {
try {
if (StringUtils.startsWith(line, "{\"message")) {
- ProgressMessage message = JsonUtils.fromJson(ProgressMessage.class, line);
+ ProgressInfo message = JsonUtils.fromJson(ProgressInfo.class, line);
if (message != null) {
- progressMessage = message;
+ progressInfo = message;
return;
}
}
@@ -115,8 +115,8 @@
clone.setStatus(getStatus());
clone.setWorkingDirectory(getWorkingDirectory());
clone.setDescription(getDescription());
- if (progressMessage != null) {
- clone.setProgressMessage(progressMessage.clone());
+ if (progressInfo != null) {
+ clone.setProgressInfo(progressInfo.clone());
}
return clone;
}
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/ProgressMessage.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/ProgressInfo.java
similarity index 86%
rename from borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/ProgressMessage.java
rename to borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/ProgressInfo.java
index 82bab1a..7ab3250 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/ProgressMessage.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/json/borg/ProgressInfo.java
@@ -7,7 +7,7 @@
* Output of borg option <tt>--progress</tt>.
* See https://borgbackup.readthedocs.io/en/stable/internals/frontends.html,
*/
-public class ProgressMessage implements Cloneable {
+public class ProgressInfo implements Cloneable {
// {"message": "Calculating statistics... 0%", "current": 1, "total": 2497, "info": null, "operation": 1, "msgid": null, "type": "progress_percent", "finished": false, "time": 1546640510.116256}
/**
* e. g. Calculating statistics... 5%
@@ -22,6 +22,7 @@
@Setter
private long current;
@Getter
+ @Setter
private long total;
/**
* Array that describes the current item, may be null, contents depend on msgid.
@@ -48,16 +49,16 @@
@Getter
private double time;
- public ProgressMessage incrementCurrent() {
+ public ProgressInfo incrementCurrent() {
++current;
return this;
}
@Override
- public ProgressMessage clone() {
- ProgressMessage clone = null;
+ public ProgressInfo clone() {
+ ProgressInfo clone = null;
try {
- clone = (ProgressMessage) super.clone();
+ clone = (ProgressInfo) super.clone();
} catch (CloneNotSupportedException ex) {
throw new UnsupportedOperationException(this.getClass().getCanonicalName() + " isn't cloneable: " + ex.getMessage(), ex);
}
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java
index 05c5d02..1a10f17 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java
@@ -4,7 +4,9 @@
import de.micromata.borgbutler.BorgQueueExecutor;
import de.micromata.borgbutler.cache.ButlerCache;
import de.micromata.borgbutler.data.Repository;
+import de.micromata.borgbutler.jobs.AbstractJob;
import de.micromata.borgbutler.json.JsonUtils;
+import de.micromata.borgbutler.json.borg.ProgressInfo;
import de.micromata.borgbutler.server.rest.queue.JsonJob;
import de.micromata.borgbutler.server.rest.queue.JsonJobQueue;
import org.apache.commons.collections4.CollectionUtils;
@@ -23,15 +25,20 @@
public class JobsRest {
private static Logger log = LoggerFactory.getLogger(JobsRest.class);
+ private static List<JsonJobQueue> testList;
+
@GET
@Produces(MediaType.APPLICATION_JSON)
/**
- *
+ * @param testMode If true, then a test job list is created.
* @param prettyPrinter If true then the json output will be in pretty format.
* @return Job queues as json string.
* @see JsonUtils#toJson(Object, boolean)
*/
- public String getJobs(@QueryParam("prettyPrinter") boolean prettyPrinter) {
+ public String getJobs(@QueryParam("testMode") boolean testMode, @QueryParam("prettyPrinter") boolean prettyPrinter) {
+ if (testMode) {
+ return returnTestList(prettyPrinter);
+ }
BorgQueueExecutor borgQueueExecutor = BorgQueueExecutor.getInstance();
List<JsonJobQueue> queueList = new ArrayList<>();
for (String repo : borgQueueExecutor.getRepos()) {
@@ -51,4 +58,69 @@
}
return JsonUtils.toJson(queueList, prettyPrinter);
}
+
+ private String returnTestList(boolean prettyPrinter) {
+ if (testList == null) {
+ testList = new ArrayList<>();
+ JsonJobQueue queue = new JsonJobQueue().setRepo("My Computer");
+ addTestJob(queue, "Calculating statistics... ",
+ "Loading info of archive 'my-computer-2018-12-05T23:10:33' of repo 'My-Computer-Cloud'.", 0, 1000);
+ addTestJob(queue, null,
+ "Loading list of files of archive 'my-computer-2018-12-05T23:10:33' of repo 'My-Computer-Cloud'.", 0, 0);
+ testList.add(queue);
+
+ queue = new JsonJobQueue().setRepo("My Server");
+ addTestJob(queue, "Getting file list...",
+ "Loading list of files of archive 'my-server-2018-12-05T23:10:33' of repo 'My-Server-Cloud'.", 0, 0);
+ addTestJob(queue, null,
+ "Loading info of archive 'my-server-2018-12-05T23:10:33' of repo 'My-Server-Cloud'.", 0, 1000);
+ testList.add(queue);
+ } else {
+ for (JsonJobQueue jobQueue : testList) {
+ for (JsonJob job : jobQueue.getJobs()) {
+ if (job.getStatus() != AbstractJob.Status.RUNNING) continue;
+ if (job.getProgressText().startsWith("Calculating")) {
+ long current = job.getProgressInfo().getCurrent();
+ current += Math.random() * 100;
+ if (current > 1000) {
+ current = 0; // Reset to beginning.
+ }
+ job.getProgressInfo().setCurrent(current);
+ job.getProgressInfo().setMessage("Calculating statistics... " + Math.round(current / 10) + "%");
+ } else {
+ long current = job.getProgressInfo().getCurrent();
+ current += Math.random() * 10000;
+ job.getProgressInfo().setCurrent(current);
+ }
+ job.buildProgressText();
+ }
+ }
+ }
+ return JsonUtils.toJson(testList, prettyPrinter);
+ }
+
+
+ private JsonJob addTestJob(JsonJobQueue queue, String message, String description, long current, long total) {
+ ProgressInfo msg = new ProgressInfo()
+ .setMessage(message)
+ .setCurrent(current)
+ .setTotal(total);
+ JsonJob job = new JsonJob()
+ .setProgressInfo(msg)
+ .setDescription(description)
+ .setStatus(AbstractJob.Status.QUEUED)
+ .setCommandLineAsString(description);
+ job.buildProgressText();
+ if (message != null) {
+ job.setStatus(AbstractJob.Status.RUNNING);
+
+ } else {
+ job.setStatus(AbstractJob.Status.QUEUED);
+ }
+ if (queue.getJobs() == null) {
+ queue.setJobs(new ArrayList<>());
+ }
+ queue.getJobs().add(job);
+ return job;
+ }
}
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/queue/JsonJob.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/queue/JsonJob.java
index ef207a1..596e3b6 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/queue/JsonJob.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/queue/JsonJob.java
@@ -2,7 +2,7 @@
import de.micromata.borgbutler.BorgJob;
import de.micromata.borgbutler.jobs.AbstractJob;
-import de.micromata.borgbutler.json.borg.ProgressMessage;
+import de.micromata.borgbutler.json.borg.ProgressInfo;
import de.micromata.borgbutler.server.user.UserUtils;
import lombok.Getter;
import lombok.Setter;
@@ -18,14 +18,16 @@
@Setter
private String title;
@Getter
+ @Setter
private String description;
@Getter
@Setter
private String progressText;
+ @Getter
@Setter
+ private ProgressInfo progressInfo;
@Getter
- private ProgressMessage progressMessage;
- @Getter
+ @Setter
private String commandLineAsString;
public JsonJob() {
@@ -35,35 +37,40 @@
this.cancellationRequested = borgJob.isCancellationRequested();
this.status = borgJob.getStatus();
this.title = borgJob.getTitle();
- ProgressMessage progressMessage = borgJob.getProgressMessage();
- if (progressMessage != null) {
- this.progressMessage = progressMessage;
- this.progressText = progressMessageToString();
+ ProgressInfo progressInfo = borgJob.getProgressInfo();
+ if (progressInfo != null) {
+ this.progressInfo = progressInfo;
+ buildProgressText();
}
this.commandLineAsString = borgJob.getCommandLineAsString();
this.description = borgJob.getDescription();
}
- public String progressMessageToString() {
- if (progressMessage == null) {
+ /**
+ * Builds and sets progressText from the progressInfo object if given.
+ * @return progressText
+ */
+ public String buildProgressText() {
+ if (progressInfo == null) {
return "";
}
StringBuilder sb = new StringBuilder();
- if (progressMessage.getMessage()!= null) {
- sb.append(progressMessage.getMessage());
+ if (progressInfo.getMessage() != null) {
+ sb.append(progressInfo.getMessage());
}
- if (progressMessage.getCurrent() > 0) {
- sb.append(" (").append(UserUtils.formatNumber(progressMessage.getCurrent()));
- if (progressMessage.getTotal() > 0) {
- sb.append("/").append(UserUtils.formatNumber(progressMessage.getTotal()));
+ if (progressInfo.getCurrent() > 0) {
+ sb.append(" (").append(UserUtils.formatNumber(progressInfo.getCurrent()));
+ if (progressInfo.getTotal() > 0) {
+ sb.append("/").append(UserUtils.formatNumber(progressInfo.getTotal()));
}
sb.append(")");
}
- if (progressMessage.isFinished()) {
+ if (progressInfo.isFinished()) {
sb.append(" (finished)");
}
sb.append(".");
- return sb.toString();
+ progressText = sb.toString();
+ return progressText;
}
}
diff --git a/borgbutler-webapp/src/components/views/jobs/JobMonitorPanel.jsx b/borgbutler-webapp/src/components/views/jobs/JobMonitorPanel.jsx
index 085c6c5..777b997 100644
--- a/borgbutler-webapp/src/components/views/jobs/JobMonitorPanel.jsx
+++ b/borgbutler-webapp/src/components/views/jobs/JobMonitorPanel.jsx
@@ -1,24 +1,38 @@
import React from 'react';
-import {getRestServiceUrl} from "../../../utilities/global";
+import {Button} from 'reactstrap';
+import {getRestServiceUrl, isDevelopmentMode} from "../../../utilities/global";
import JobQueue from "./JobQueue";
import ErrorAlert from "../archives/ArchiveView";
class JobMonitorPanel extends React.Component {
state = {
- isFetching: false
+ isFetching: false,
+ testMode: false
};
componentDidMount = () => {
this.fetchArchive();
+ this.interval = setInterval(() => this.fetchArchive(), 2000);
};
+ componentWillUnmount() {
+ clearInterval(this.interval);
+ }
- fetchArchive = (force) => {
+ toggleTestMode() {
+ this.setState({
+ testMode: !this.state.testMode
+ });
+ }
+
+ fetchArchive = () => {
this.setState({
isFetching: true,
failed: false
});
- fetch(getRestServiceUrl('jobs'), {
+ fetch(getRestServiceUrl('jobs', {
+ testMode: this.state.testMode
+ }), {
method: 'GET',
headers: {
'Accept': 'application/json'
@@ -32,7 +46,7 @@
this.setState({
isFetching: false,
queues
- })
+ });
})
.catch(() => this.setState({isFetching: false, failed: true}));
};
@@ -52,13 +66,21 @@
}}
/>;
} else if (this.state.queues) {
- content = <React.Fragment>
- {this.state.queues
- .map((queue) => <JobQueue
- queue={queue}
- key={queue.repo}
- />)}
- </React.Fragment>;
+ if (this.state.queues.length > 0) {
+ content = <React.Fragment>
+ {this.state.queues
+ .map((queue) => <JobQueue
+ queue={queue}
+ key={queue.repo}
+ />)}
+ </React.Fragment>;
+ } else if (isDevelopmentMode()) {
+ content = <React.Fragment>No jobs are running or queued.<br/><br/>
+ <Button color="primary" onClick={this.toggleTestMode}>Test mode</Button>
+ </React.Fragment>
+ } else {
+ content = <React.Fragment>No jobs are running or queued.</React.Fragment>
+ }
}
return <React.Fragment>
@@ -70,6 +92,7 @@
super(props);
this.fetchArchive = this.fetchArchive.bind(this);
+ this.toggleTestMode = this.toggleTestMode.bind(this);
}
}
diff --git a/borgbutler-webapp/src/components/views/jobs/JobQueue.jsx b/borgbutler-webapp/src/components/views/jobs/JobQueue.jsx
index 965b678..58e7711 100644
--- a/borgbutler-webapp/src/components/views/jobs/JobQueue.jsx
+++ b/borgbutler-webapp/src/components/views/jobs/JobQueue.jsx
@@ -1,16 +1,36 @@
import React from 'react';
+import { Collapse, Button, CardBody, Card } from 'reactstrap';
import Job from "./Job";
-function JobQueue({queue}) {
- return (
- <div>
- <h2>{queue.repo}</h2>
- {queue.jobs
- .map((job, index) => <Job
- job={job}
- key={job.commandLineAsString}
- />)}
- </div>
- )
+class JobQueue extends React.Component {
+ constructor(props) {
+ super(props);
+ this.toggle = this.toggle.bind(this);
+ this.state = {collapse: true};
+ }
+
+ toggle() {
+ this.setState({collapse: !this.state.collapse});
+ }
+
+ render() {
+ return (
+ <div>
+ <Button color="primary" onClick={this.toggle} style={{ marginBottom: '1rem' }}>{this.props.queue.repo}</Button>
+ <Collapse isOpen={this.state.collapse}>
+ <Card>
+ <CardBody>
+ {this.props.queue.jobs
+ .map((job, index) => <Job
+ job={job}
+ key={job.commandLineAsString}
+ />)}
+ </CardBody>
+ </Card>
+ </Collapse>
+ </div>
+ );
+ }
}
+
export default JobQueue;
--
Gitblit v1.10.0