mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
incremental work on ui
This commit is contained in:
parent
9717487db4
commit
1d6e4f29a6
@ -11,6 +11,9 @@ package io.nosqlbench.docsys.api;
|
|||||||
* .io/documentation/latest/jaxrs-resources.html#d0e2040">Jersey jax-rs
|
* .io/documentation/latest/jaxrs-resources.html#d0e2040">Jersey jax-rs
|
||||||
* resources documentation</A>
|
* resources documentation</A>
|
||||||
*
|
*
|
||||||
|
* @see <A href="https://repo1.maven.org/maven2/org/glassfish/jersey/jersey-documentation/2.5
|
||||||
|
* .1/jersey-documentation-2.5.1-user-guide.pdf">Jersey 2.5.1 user guide</a>
|
||||||
|
*
|
||||||
* @see <A href="https://github.com/jax-rs/spec/blob/master/spec
|
* @see <A href="https://github.com/jax-rs/spec/blob/master/spec
|
||||||
* .pdf">JAX-RS: Java™ API for RESTful Web Services Version 2.1
|
* .pdf">JAX-RS: Java™ API for RESTful Web Services Version 2.1
|
||||||
* Proposed Final Draft June 9, 2017</A>
|
* Proposed Final Draft June 9, 2017</A>
|
||||||
|
@ -1,22 +1,77 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container fluid>
|
<v-container>
|
||||||
<v-select :items="workspaces" label="default workspace"></v-select>
|
<v-text-field dense
|
||||||
|
label="Name of new workspace"
|
||||||
|
v-if="mode=='adding'"
|
||||||
|
v-model="new_workspace"
|
||||||
|
ref="new_workspace_input"
|
||||||
|
hint="workspace name"
|
||||||
|
@blur="commitWorkspace(new_workspace)"
|
||||||
|
@keydown.enter="commitWorkspace(new_workspace)"
|
||||||
|
></v-text-field>
|
||||||
|
<v-select dense
|
||||||
|
label="workspace"
|
||||||
|
v-if="mode=='showing'"
|
||||||
|
v-model="workspace"
|
||||||
|
:items="workspaces"
|
||||||
|
item-text="name"
|
||||||
|
item-value="name"
|
||||||
|
>
|
||||||
|
<template v-slot:append-item>
|
||||||
|
<v-list-item>
|
||||||
|
<v-btn @click="addWorkspace()">+ Add Workspace</v-btn>
|
||||||
|
</v-list-item>
|
||||||
|
</template>
|
||||||
|
</v-select>
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'WorkspaceSelector',
|
name: 'workspace-selector',
|
||||||
data(context) {
|
data(context) {
|
||||||
let data = {
|
let data = {
|
||||||
workspaces: [],
|
new_workspace: "",
|
||||||
workspace: 'default',
|
mode: "showing",
|
||||||
|
workspaces: [{name: 'default'}],
|
||||||
|
workspace: {name: 'default'},
|
||||||
enabled: false
|
enabled: false
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
addWorkspace: function (evt) {
|
||||||
|
this.mode = "adding";
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.new_workspace_input.$el.focus()
|
||||||
|
});
|
||||||
|
console.log("add evt:" + JSON.stringify(evt));
|
||||||
|
},
|
||||||
|
commitWorkspace: function (evt) {
|
||||||
|
console.log("commit evt:" + JSON.stringify(evt));
|
||||||
|
let committed = this.$axios.$get("/services/workspaces/" + evt)
|
||||||
|
.then(res => {
|
||||||
|
return res;
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log("create: error: " + e)
|
||||||
|
});
|
||||||
|
console.log("committed: " + JSON.stringify(committed))
|
||||||
|
this.workspaces = this.$axios.$get("/services/workspaces/")
|
||||||
|
.then(res => {
|
||||||
|
console.log("workspaces async:" + JSON.stringify(res));
|
||||||
|
return res;
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log("refresh error: " + e)
|
||||||
|
});
|
||||||
|
this.workspace = evt;
|
||||||
|
this.mode = "showing"
|
||||||
|
this.$forceUpdate();
|
||||||
|
}
|
||||||
|
},
|
||||||
async asyncData({$axios, store}) {
|
async asyncData({$axios, store}) {
|
||||||
let enabled = await $axios.$get("/services/nb/enabled")
|
let enabled = await $axios.$get("/services/status")
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
justify-center
|
justify-center
|
||||||
align-center>
|
align-center>
|
||||||
|
|
||||||
<v-content>
|
<v-main>
|
||||||
<v-container fluid>
|
<v-container fluid>
|
||||||
<v-layout row>
|
<v-layout row>
|
||||||
<v-flex>
|
<v-flex>
|
||||||
@ -53,7 +53,7 @@
|
|||||||
|
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|
||||||
</v-content>
|
</v-main>
|
||||||
</v-layout>
|
</v-layout>
|
||||||
|
|
||||||
<v-footer app dark color="secondary">
|
<v-footer app dark color="secondary">
|
||||||
@ -251,7 +251,7 @@
|
|||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
async asyncData({ $axios, store }) {
|
async asyncData({ $axios, store }) {
|
||||||
let enabled = await $axios.$get("/services/nb/enabled")
|
let enabled = await $axios.$get("/services/status")
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
<v-toolbar-title>NoSQLBench - Workspaces</v-toolbar-title>
|
<v-toolbar-title>NoSQLBench - Workspaces</v-toolbar-title>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-toolbar-items>
|
<v-toolbar-items>
|
||||||
<v-btn title="start a new workspace">
|
<workspace-selector></workspace-selector>
|
||||||
|
|
||||||
|
<v-btn title="start a new workspace" @click="startNewWorkspace()">
|
||||||
<v-icon>mdi-folder-plus-outline</v-icon>
|
<v-icon>mdi-folder-plus-outline</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn title="upload a workspace zip file">
|
<v-btn title="upload a workspace zip file">
|
||||||
@ -35,9 +37,9 @@
|
|||||||
]
|
]
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<v-main justify-start align-start class="pa-4">
|
<v-main justify-start align-start class="d-flex pa-4 ma-4">
|
||||||
<v-main>
|
<v-main>
|
||||||
<v-card max-width="344" v-for="(workspace,w) in workspaces" :key="w" class="pa-4">
|
<v-card max-width="344" v-for="(workspace,w) in workspaces" :key="w" class="pa-4 ma-4">
|
||||||
<v-card-title title="workspace name">{{ workspace.name }}</v-card-title>
|
<v-card-title title="workspace name">{{ workspace.name }}</v-card-title>
|
||||||
<v-card-subtitle title="last change">{{ abbrev(workspace.summary.last_changed_filename) }}</v-card-subtitle>
|
<v-card-subtitle title="last change">{{ abbrev(workspace.summary.last_changed_filename) }}</v-card-subtitle>
|
||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
@ -51,6 +53,10 @@
|
|||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
|
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
|
<v-btn title="view details of workspace">
|
||||||
|
<v-icon>mdi-magnify</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
<v-btn title="use this workspace">
|
<v-btn title="use this workspace">
|
||||||
<v-icon>mdi-play</v-icon>
|
<v-icon>mdi-play</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
@ -58,12 +64,13 @@
|
|||||||
<v-btn title="download zipped workspace">
|
<v-btn title="download zipped workspace">
|
||||||
<v-icon>mdi-folder-download</v-icon>
|
<v-icon>mdi-folder-download</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn title="add one or more files">
|
|
||||||
<v-icon>mdi-file-plus</v-icon>
|
<v-spacer></v-spacer>
|
||||||
</v-btn>
|
|
||||||
<v-btn title="view details of workspace">
|
<v-btn title="purge workspace">
|
||||||
<v-icon>mdi-magnify</v-icon>
|
<v-icon @click="purgeWorkspace(workspace.name)">mdi-trash-can</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-card>
|
</v-card>
|
||||||
@ -74,8 +81,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
import WorkspaceSelector from "~/components/WorkspaceSelector";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "workspaces.vue",
|
name: "workspaces.vue",
|
||||||
|
components: {
|
||||||
|
WorkspaceSelector
|
||||||
|
},
|
||||||
data(context) {
|
data(context) {
|
||||||
let data = {
|
let data = {
|
||||||
workspaces: [
|
workspaces: [
|
||||||
@ -89,10 +102,22 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
abbrev(name) {
|
abbrev(name) {
|
||||||
return name;
|
return name;
|
||||||
|
},
|
||||||
|
purgeWorkspace: function(ws) {
|
||||||
|
console.log("purging " + ws);
|
||||||
|
this.$axios.$delete("/services/workspaces/" + ws)
|
||||||
|
.then(res => { return res })
|
||||||
|
.catch((e) => {
|
||||||
|
console.log("error: " + e)
|
||||||
|
});
|
||||||
|
this.$forceUpdate();
|
||||||
|
},
|
||||||
|
startNewWorkspace() {
|
||||||
|
console.log("starting new workspace");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async asyncData({$axios, store}) {
|
async asyncData({$axios, store}) {
|
||||||
let enabled = await $axios.$get("/services/nb/enabled")
|
let enabled = await $axios.$get("/services/status")
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res
|
return res
|
||||||
})
|
})
|
||||||
|
@ -12,6 +12,8 @@ import io.nosqlbench.engine.rest.services.WorkspaceService;
|
|||||||
import io.nosqlbench.engine.rest.transfertypes.RunScenarioRequest;
|
import io.nosqlbench.engine.rest.transfertypes.RunScenarioRequest;
|
||||||
import io.nosqlbench.engine.rest.transfertypes.ScenarioInfo;
|
import io.nosqlbench.engine.rest.transfertypes.ScenarioInfo;
|
||||||
import io.nosqlbench.nb.annotations.Service;
|
import io.nosqlbench.nb.annotations.Service;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import javax.ws.rs.*;
|
import javax.ws.rs.*;
|
||||||
@ -27,6 +29,7 @@ import java.util.*;
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Path("/services/executor/")
|
@Path("/services/executor/")
|
||||||
public class ScenarioExecutorEndpoint implements WebServiceObject {
|
public class ScenarioExecutorEndpoint implements WebServiceObject {
|
||||||
|
private final static Logger logger = LogManager.getLogger(ScenarioExecutorEndpoint.class);
|
||||||
|
|
||||||
private ScenariosExecutor executor = new ScenariosExecutor("executor-service", 1);
|
private ScenariosExecutor executor = new ScenariosExecutor("executor-service", 1);
|
||||||
|
|
||||||
|
@ -39,12 +39,30 @@ public class WorkspacesEndpoint implements WebServiceObject {
|
|||||||
return Response.ok(wsviews).build();
|
return Response.ok(wsviews).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("{workspace}")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Response deleteWorkspace(@PathParam("workspace") String workspace,
|
||||||
|
@QueryParam("deleteCount") String deleteCount) {
|
||||||
|
try {
|
||||||
|
int dc = deleteCount!=null ? Integer.valueOf(deleteCount):0;
|
||||||
|
getSvc().purgeWorkspace(workspace,dc);
|
||||||
|
return Response.ok("removed workspace " + workspace).build();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Response.serverError().entity(e.getMessage()).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("{workspace}")
|
@Path("{workspace}")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Response getWorkspaceInfo(@PathParam("workspace") String workspace) {
|
public Response getWorkspaceInfo(@PathParam("workspace") String workspace) {
|
||||||
WorkspaceView workpaceView = getSvc().getWorkspaceView(workspace);
|
try {
|
||||||
return Response.ok(workpaceView).build();
|
WorkspaceView workpaceView = getSvc().getWorkspaceView(workspace);
|
||||||
|
return Response.ok(workpaceView).build();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Response.serverError().entity(e.getMessage()).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
|
@ -2,6 +2,8 @@ package io.nosqlbench.engine.rest.services;
|
|||||||
|
|
||||||
import io.nosqlbench.engine.rest.domain.WorkSpace;
|
import io.nosqlbench.engine.rest.domain.WorkSpace;
|
||||||
import io.nosqlbench.engine.rest.transfertypes.WorkspaceView;
|
import io.nosqlbench.engine.rest.transfertypes.WorkspaceView;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import javax.ws.rs.core.Configuration;
|
import javax.ws.rs.core.Configuration;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
@ -9,9 +11,13 @@ import java.io.IOException;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class WorkspaceService {
|
public class WorkspaceService {
|
||||||
|
private final static Logger logger = LogManager.getLogger(WorkspaceService.class);
|
||||||
|
|
||||||
private final Path root;
|
private final Path root;
|
||||||
public static String DEFAULT = "default";
|
public static String DEFAULT = "default";
|
||||||
public static final String WORKSPACE_ROOT = "workspaces_root";
|
public static final String WORKSPACE_ROOT = "workspaces_root";
|
||||||
@ -65,13 +71,12 @@ public class WorkspaceService {
|
|||||||
|
|
||||||
public WorkSpace getWorkspace(String workspaceName) {
|
public WorkSpace getWorkspace(String workspaceName) {
|
||||||
assertLegalWorkspaceName(workspaceName);
|
assertLegalWorkspaceName(workspaceName);
|
||||||
return new WorkSpace(this.root,workspaceName);
|
return new WorkSpace(this.root, workspaceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void assertLegalWorkspaceName(String workspaceName) {
|
public static void assertLegalWorkspaceName(String workspaceName) {
|
||||||
if (!workspaceName.matches("[a-zA-Z][a-zA-Z0-9]+")) {
|
if (!workspaceName.matches("[a-zA-Z0-9]+")) {
|
||||||
throw new RuntimeException("Workspaces must start with an alphabetic" +
|
throw new RuntimeException("Workspace names must contain only letters and numbers.");
|
||||||
" character, and contain only letters and numbers.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +119,47 @@ public class WorkspaceService {
|
|||||||
return root.resolve(workspaceName);
|
return root.resolve(workspaceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void purgeWorkspace(String workspaceName, int deleteCount) {
|
||||||
|
assertLegalWorkspaceName(workspaceName);
|
||||||
|
Path path = workspacePath(workspaceName);
|
||||||
|
if (Files.exists(path)) {
|
||||||
|
try (Stream<Path> counter = Files.walk(path)) {
|
||||||
|
long foundFiles = counter.count();
|
||||||
|
if (foundFiles > 100 && deleteCount != foundFiles) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"To delete " + foundFiles + " files, you must provide a deleteCount=<count> " +
|
||||||
|
"parameter that matches. This is a safety mechanism."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
logger.debug("found " + foundFiles + " to delete.");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path relativize = root.relativize(path);
|
||||||
|
if (relativize.toString().contains("..")) {
|
||||||
|
throw new RuntimeException("Illegal path to delete: " + path.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try (Stream<Path> walk = Files.walk(path)) {
|
||||||
|
walk.sorted(Comparator.reverseOrder())
|
||||||
|
.map(Path::toFile)
|
||||||
|
// .peek(System.out::println)
|
||||||
|
.forEach(f -> {
|
||||||
|
logger.debug("deleting '" + f.toString() + "'");
|
||||||
|
if (!f.delete()) {
|
||||||
|
throw new RuntimeException("Unable to delete " + f.toString());
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final static class FileInfo {
|
public final static class FileInfo {
|
||||||
private final Path path;
|
private final Path path;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user