Skip to content
This repository has been archived by the owner on Jun 6, 2024. It is now read-only.

[Rest Server] Refactor storage by leveraging persistent volumes #4157

Merged
merged 13 commits into from
Mar 8, 2020
371 changes: 68 additions & 303 deletions src/rest-server/docs/swagger.yaml

Large diffs are not rendered by default.

139 changes: 139 additions & 0 deletions src/rest-server/src/controllers/v2/storage-deprecated.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// module dependencies
const asyncHandler = require('@pai/middlewares/v2/asyncHandler');
const {get, list} = require('@pai/models/v2/storage');
const {getUserStorages} = require('@pai/models/v2/user');


const convertConfig = (storage, userDefaultStorages) => {
const config = {
name: storage.name,
default: (storage.name in userDefaultStorages),
servers: [storage.volumeName],
mountInfos: [],
};
if (storage.share === 'false') {
config.mountInfos = [
{
mountPoint: '/data',
path: 'data',
server: storage.volumeName,
permission: 'rw',
},
{
mountPoint: '/home',
path: 'users/${PAI_USER_NAME}',
server: storage.volumeName,
permission: 'rw',
},
];
} else {
config.mountInfos = [
{
mountPoint: `/mnt/${storage.name}`,
path: 'data',
server: storage.volumeName,
permission: 'rw',
},
];
}
return config;
};

const convertServer = async (storage) => {
const detail = await get(storage.name);
const server = {
spn: storage.volumeName,
type: detail.type.toLowerCase(),
data: {},
extension: {},
};
if (server.type === 'nfs') {
server.data = {
address: detail.data.server,
rootPath: detail.data.path,
};
} else if (server.type === 'samba') {
const address = detail.data.address.replace(/^\/\//, '');
server.data = {
address: address.substr(0, address.indexOf('/')),
rootPath: address.substr(1 + address.indexOf('/')),
userName: detail.data.username,
password: detail.data.password,
domain: '',
};
} else if (server.type === 'azurefile') {
server.data = {
dataStore: `${detail.data.accountName}.file.core.windows.net`,
fileShare: detail.data.shareName,
accountName: detail.data.accountName,
key: detail.data.accountKey,
};
} else if (server.type === 'azureblob') {
server.data = {
dataStore: '',
containerName: detail.data.containerName,
accountName: detail.data.accountName,
key: detail.data.accountKey,
};
}
return server;
};

const getConfig = asyncHandler(async (req, res) => {
let name = null;
if (req.params.name) {
name = req.params.name;
} else if (req.query.names) {
name = req.query.names;
}

const userName = req.user.username;
const admin = req.user.admin;
const userDefaultStorages = await getUserStorages(userName, true);
const storages = (await list(admin ? undefined : userName)).storages
.filter((item) => name ? item.name === name : true)
.map((item) => convertConfig(item, userDefaultStorages));

res.json(storages);
});

const getServer = asyncHandler(async (req, res) => {
let name = null;
if (req.params.name) {
name = req.params.name;
} else if (req.query.names) {
name = req.query.names;
}

const userName = req.user.username;
const admin = req.user.admin;
const storages = await Promise.all(
(await list(admin ? undefined : userName)).storages
.filter((item) => name ? item.volumeName === name : true)
.map(convertServer));

res.json(storages);
});

// module exports
module.exports = {
getConfig,
getServer,
};
213 changes: 17 additions & 196 deletions src/rest-server/src/controllers/v2/storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,206 +16,27 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// module dependencies
const createError = require('@pai/utils/error');
const storageModel = require('@pai/models/v2/storage');
const {isArray, isEmpty} = require('lodash');
const asyncHandler = require('@pai/middlewares/v2/asyncHandler');
const storage = require('@pai/models/v2/storage');

const getStorageServer = async (req, res, next) => {
try {
const name = req.params.name;
const storageServerInfo = await storageModel.getStorageServer(name);
return res.status(200).json(storageServerInfo);
} catch (error) {
return next(createError.unknown(error));
}
};

const getStorageServers = async (req, res, next) => {
try {
const names = isEmpty(req.query.names)
? []
: isArray(req.query.names)
? req.query.names
: [req.query.names];
const storageServerList = await storageModel.getStorageServers(names);
return res.status(200).json(storageServerList);
} catch (error) {
return next(createError.unknown(error));
}
};
const list = asyncHandler(async (req, res) => {
const userName = req.user.username;
const admin = req.user.admin;
const data = await storage.list(admin ? undefined : userName);
res.json(data);
});

const getStorageConfig = async (req, res, next) => {
try {
const name = req.params.name;
const storageConfigInfo = await storageModel.getStorageConfig(name);
return res.status(200).json(storageConfigInfo);
} catch (error) {
return next(createError.unknown(error));
}
};

const getStorageConfigs = async (req, res, next) => {
try {
const names = isEmpty(req.query.names)
? []
: isArray(req.query.names)
? req.query.names
: [req.query.names];
const storageConfigList = await storageModel.getStorageConfigs(names);
return res.status(200).json(storageConfigList);
} catch (error) {
return next(createError.unknown(error));
}
};

const createStorageServer = async (req, res, next) => {
try {
if (!req.user.admin) {
next(
createError(
'Forbidden',
'ForbiddenUserError',
`Non-admin is not allow to do this operation.`
)
);
}
const name = req.body.spn;
const value = {
spn: req.body.spn,
type: req.body.type,
data: req.body.data,
};
await storageModel.createStorageServer(name, value);
return res.status(201).json({
message: 'Storage Server is created successfully',
});
} catch (error) {
return next(createError.unknown(error));
}
};

const updateStorageServer = async (req, res, next) => {
try {
if (!req.user.admin) {
next(
createError(
'Forbidden',
'ForbiddenUserError',
`Non-admin is not allow to do this operation.`
)
);
}
const name = req.body.spn;
const value = {
spn: req.body.spn,
type: req.body.type,
data: req.body.data,
};
await storageModel.updateStorageServer(name, value);
return res.status(201).json({
message: 'Storage Server is updated successfully',
});
} catch (error) {
return next(createError.unknown(error));
}
};

const deleteStorageServer = async (req, res, next) => {
try {
if (!req.user.admin) {
next(
createError(
'Forbidden',
'ForbiddenUserError',
`Non-admin is not allow to do this operation.`
)
);
}
const name = req.params.name;
await storageModel.deleteStorageServer(name);
return res.status(201).json({
message: 'Storage Server is deleted successfully',
});
} catch (error) {
return next(createError.unknown(error));
}
};

const createStorageConfig = async (req, res, next) => {
try {
if (!req.user.admin) {
next(
createError(
'Forbidden',
'ForbiddenUserError',
`Non-admin is not allow to do this operation.`
)
);
}
const name = req.body.name;
const value = req.body;
await storageModel.createStorageConfig(name, value);
return res.status(201).json({
message: 'Storage Config is created successfully',
});
} catch (error) {
return next(createError.unknown(error));
}
};

const updateStorageConfig = async (req, res, next) => {
try {
if (!req.user.admin) {
next(
createError(
'Forbidden',
'ForbiddenUserError',
`Non-admin is not allow to do this operation.`
)
);
}
const name = req.body.name;
const value = req.body;
await storageModel.updateStorageConfig(name, value);
return res.status(201).json({
message: 'Storage Config is updated successfully',
});
} catch (error) {
return next(createError.unknown(error));
}
};

const deleteStorageConfig = async (req, res, next) => {
try {
if (!req.user.admin) {
next(
createError(
'Forbidden',
'ForbiddenUserError',
`Non-admin is not allow to do this operation.`
)
);
}
const name = req.params.name;
await storageModel.deleteStorageConfig(name);
return res.status(201).json({
message: 'Storage Config is deleted successfully',
});
} catch (error) {
return next(createError.unknown(error));
}
};
const get = asyncHandler(async (req, res) => {
const storageName = req.params.storageName;
const userName = req.user.username;
const admin = req.user.admin;
const data = await storage.get(storageName, admin ? undefined : userName);
res.json(data);
});

// module exports
module.exports = {
getStorageServer,
getStorageServers,
getStorageConfig,
getStorageConfigs,
createStorageServer,
updateStorageServer,
deleteStorageServer,
createStorageConfig,
updateStorageConfig,
deleteStorageConfig,
list,
get,
};
11 changes: 0 additions & 11 deletions src/rest-server/src/controllers/v2/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,6 @@ const getUserVCs = async (username) => {
return [...virtualClusters];
};

const getUserStorageConfigs = async (username) => {
const userInfo = await userModel.getUser(username);
let storageConfigs = new Set();
for (const group of userInfo.grouplist) {
const groupStorageConfigs = await groupModel.getGroupStorageConfigs(group);
storageConfigs = new Set([...storageConfigs, ...groupStorageConfigs]);
}
return [...storageConfigs];
};

const getUser = async (req, res, next) => {
try {
const username = req.params.username;
Expand Down Expand Up @@ -472,5 +462,4 @@ module.exports = {
updateUserPassword,
createUser,
getUserVCs,
getUserStorageConfigs,
};
Loading