@@ -53,32 +53,32 @@
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/dashboard/src/views/volumes.js b/dashboard/src/views/volumes.js
index 5738dda07..2cab4e723 100644
--- a/dashboard/src/views/volumes.js
+++ b/dashboard/src/views/volumes.js
@@ -88,7 +88,8 @@ angular.module('Application').controller('VolumesController', ['$scope', '$locat
remoteDir: '',
username: '',
password: '',
- diskPath: '',
+ diskPath: {}, // { path, type }
+ customDiskPath: '',
user: '',
seal: false,
port: 22,
@@ -104,7 +105,7 @@ angular.module('Application').controller('VolumesController', ['$scope', '$locat
$scope.volumeAdd.remoteDir = '';
$scope.volumeAdd.username = '';
$scope.volumeAdd.password = '';
- $scope.volumeAdd.diskPath = '';
+ $scope.volumeAdd.diskPath = {};
$scope.volumeAdd.customDiskPath = '';
$scope.volumeAdd.user = '';
$scope.volumeAdd.seal = false;
@@ -130,7 +131,7 @@ angular.module('Application').controller('VolumesController', ['$scope', '$locat
result.forEach(function (d) { d.label = d.path; });
// add custom fake option
- result.push({ path: 'custom', label: 'Custom' });
+ result.push({ path: 'custom', label: 'Custom Path' });
$scope.blockDevices = result;
$scope.volumeAdd.diskPath = $scope.blockDevices[0];
@@ -170,16 +171,13 @@ angular.module('Application').controller('VolumesController', ['$scope', '$locat
mountOptions = {
diskPath: $scope.volumeAdd.diskPath === 'custom' ? $scope.volumeAdd.customDiskPath : $scope.volumeAdd.diskPath
};
+ } else if ($scope.volumeAdd.mountType === 'mountpoint' || $scope.volumeAdd.mountType === 'filesystem') {
+ mountOptions = {
+ hostPath: $scope.volumeAdd.hostPath
+ };
}
- var hostPath;
- if ($scope.volumeAdd.mountType === 'mountpoint' || $scope.volumeAdd.mountType === 'filesystem') {
- hostPath = $scope.volumeAdd.hostPath;
- } else {
- hostPath = null;
- }
-
- Client.addVolume($scope.volumeAdd.name, $scope.volumeAdd.mountType, hostPath, mountOptions, function (error) {
+ Client.addVolume($scope.volumeAdd.name, $scope.volumeAdd.mountType, mountOptions, function (error) {
$scope.volumeAdd.busy = false;
if (error) {
$scope.volumeAdd.error = error.message;
diff --git a/migrations/schema.sql b/migrations/schema.sql
index 394079df6..a49a8828a 100644
--- a/migrations/schema.sql
+++ b/migrations/schema.sql
@@ -280,7 +280,7 @@ CREATE TABLE IF NOT EXISTS appPasswords(
CREATE TABLE IF NOT EXISTS volumes(
id VARCHAR(128) NOT NULL UNIQUE,
name VARCHAR(256) NOT NULL UNIQUE,
- hostPath VARCHAR(1024) NOT NULL UNIQUE,
+ hostPath VARCHAR(1024) NOT NULL UNIQUE, // computed hostPath
creationTime TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
mountType VARCHAR(16) DEFAULT "noop",
mountOptionsJson TEXT,
diff --git a/src/mounts.js b/src/mounts.js
index f849b9a06..c32fd000d 100644
--- a/src/mounts.js
+++ b/src/mounts.js
@@ -34,6 +34,7 @@ function validateMountOptions(type, options) {
switch (type) {
case 'filesystem':
case 'mountpoint':
+ if (typeof options.hostPath !== 'string') return new BoxError(BoxError.BAD_FIELD, 'hostPath is not a string');
return null;
case 'cifs':
if (typeof options.username !== 'string') return new BoxError(BoxError.BAD_FIELD, 'username is not a string');
diff --git a/src/routes/volumes.js b/src/routes/volumes.js
index 4833a54da..f271ee3fd 100644
--- a/src/routes/volumes.js
+++ b/src/routes/volumes.js
@@ -33,9 +33,7 @@ async function add(req, res, next) {
if (typeof req.body.name !== 'string') return next(new HttpError(400, 'name must be a string'));
if (typeof req.body.mountType !== 'string') return next(new HttpError(400, 'mountType must be a string'));
- if (typeof req.body.mountOptions !== 'object') return next(new HttpError(400, 'mountOptions must be a object'));
-
- if ('hostPath' in req.body && typeof req.body.hostPath !== 'string') return next(new HttpError(400, 'hostPath must be a string'));
+ if (!req.body.mountOptions || typeof req.body.mountOptions !== 'object') return next(new HttpError(400, 'mountOptions must be a non-null object'));
req.clearTimeout(); // waiting for mount can take time
diff --git a/src/volumes.js b/src/volumes.js
index b6130a151..459737e5f 100644
--- a/src/volumes.js
+++ b/src/volumes.js
@@ -81,21 +81,24 @@ async function add(volume, auditSource) {
const id = uuid.v4().replace(/-/g, ''); // to make systemd mount file names more readable
+ let hostPath;
if (mountType === 'mountpoint' || mountType === 'filesystem') {
- error = validateHostPath(volume.hostPath, mountType);
+ error = validateHostPath(mountOptions.hostPath, mountType);
if (error) throw error;
+ hostPath = mountOptions.hostPath;
} else {
- volume.hostPath = path.join(paths.VOLUMES_MOUNT_DIR, id);
- await mounts.tryAddMount(volume, { timeout: 10 }); // 10 seconds
+ hostPath = path.join(paths.VOLUMES_MOUNT_DIR, id);
+ const mount = { name, hostPath, mountType, mountOptions };
+ await mounts.tryAddMount(mount, { timeout: 10 }); // 10 seconds
}
- [error] = await safe(database.query('INSERT INTO volumes (id, name, hostPath, mountType, mountOptionsJson) VALUES (?, ?, ?, ?, ?)', [ id, name, volume.hostPath, mountType, JSON.stringify(mountOptions) ]));
+ [error] = await safe(database.query('INSERT INTO volumes (id, name, hostPath, mountType, mountOptionsJson) VALUES (?, ?, ?, ?, ?)', [ id, name, hostPath, mountType, JSON.stringify(mountOptions) ]));
if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('name') !== -1) throw new BoxError(BoxError.ALREADY_EXISTS, 'name already exists');
if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('hostPath') !== -1) throw new BoxError(BoxError.ALREADY_EXISTS, 'hostPath already exists');
if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('PRIMARY') !== -1) throw new BoxError(BoxError.ALREADY_EXISTS, 'id already exists');
if (error) throw error;
- await eventlog.add(eventlog.ACTION_VOLUME_ADD, auditSource, { id, name, hostPath: volume.hostPath });
+ await eventlog.add(eventlog.ACTION_VOLUME_ADD, auditSource, { id, name, hostPath });
// in theory, we only need to do this mountpoint volumes. but for some reason a restart is required to detect new "mounts"
safe(services.rebuildService('sftp', auditSource), { debug });