egg.js+mongodb+openstack 公有云计费系统(三)OpenStack 对接 blcokStorage(1)

磁盘备份
控制器
'use strict';

const Controller = require('egg').Controller;

class OPBlcokStorageVolumeBackupsController extends Controller {
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.QPFN = ctx.helper.queryParamFn;
this.DUFN = ctx.helper.deleteUndefined;
this.snapshotMODEL = ctx.model.Openstack.BlcokStorage.Snapshot;
this.backupSERVICE = ctx.service.openstack.blcokStorage.backup;
}
/**
* @name 磁盘备份列表
*
* @param {String} ctx.query 不需要参数
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/blcokstorage/volume
*
*/
async index() {
const { ctx } = this;
// const datas = !!ctx.isAdmin() ? await this.snapshotMODEL.getAll(this.QPFN(ctx.query)) : await this.snapshotMODEL.getUsers(this.auth.id, this.QPFN(ctx.query));
const datas = await this.backupSERVICE.list(this.QPFN(ctx.query), this.auth.id, ctx.isAdmin())
ctx.body = datas;
}
/**
* @name 获取单一磁盘备份
*
* @description
*
* @example GET /openstack/blcokstorage/snapshot/{id}
*
*/
async show() {
const ctx = this.ctx;
const datas = await this.backupSERVICE.show(ctx.params.id, this.auth.id);
ctx.body = datas;
}
/**
* @name 创建磁盘备份
*
* @param {String} name Optional 磁盘备份名称
* @param {String} description Optional 备注
* @param {String} volume_id 磁盘ID
* @param {Boolean} force Optional 是否备份
* @param {Object} metadata Optional One or more metadata key and value pairs for the snapshot.
*
* @description
*
* @example POST /openstack/blcokstorage/snapshot
*
*/
async create() {
const ctx = this.ctx;
const { name, description, volume_id, force, metadata } = ctx.request.body;
const BODYS = this.DUFN({ name, description, volume_id, force, metadata });
const datas = await this.snapshotMODEL.createOne(this.auth.id, BODYS);
ctx.body = datas
}
/**
* @name 删除备份
*
* @param {*} snapshot_id 备份ID
*
*/
async destroy() {
const ctx = this.ctx;
const datas = await this.backupSERVICE.destroy(this.auth.id, this.auth.ProjectID, ctx.params.id);
ctx.body = datas
}
}

module.exports = OPBlcokStorageVolumeBackupsController;
service
'use strict';
const ServerIndex = require('../index')
//
class VolumeSnapshotService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.adminprojectID = this.config.openstack.projectID.default
this.actions = ':8776/v3'
};
// 获取磁盘备份
async list(query, _ucid, isAdmin) {
const detail = Object.keys(query).includes('detail');
delete query.detail
try {
const datas = await this.OSAJax(`${this.actions}/${!!isAdmin ? this.adminprojectID : await this.getProject(_ucid)}/backups${detail ? '/detail' : ''}`, {
...!isAdmin && { _ucid },
body: { ...isAdmin && { 'all_tenants': true } },
full: true
});
return {
data: {
result: datas,
// totalCount: datas.snapshots.length
}
};
} catch (error) {
return error
}
};
// 获取磁盘备份详情
async show(id, _ucid) {
try {
const datas = await this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/backups/${id}`, { _ucid });
return { data: datas.snapshot };
} catch (error) {
return error
}
}
// 创建磁盘备份
async create(_ucid, bodys, type = 'manual') {
try {
const datas = await this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/backups`, {
body: {
'backups': {
... {
"name": `${!bodys.name && `backups-${type}-${Math.random().toString(36).slice(2, 8)}`}`,
"force": true,
"metadata": null
},
...bodys
}
},
method: 'POST',
_ucid
});
return datas
} catch (error) {
return error
}
}
/**
* @name 删除
* @param {*} _ucid 用户id
* @param {*} project_id 密钥对名称
* @param {*} snapshot_id 备份ID
*/
async destroy(_ucid, project_id, snapshot_id) {
try {
const datas = await this.OSAJax(`${this.actions}/${project_id}/backups/${snapshot_id}`, {
_ucid,
method: 'DELETE',
full: true
});
return {
message: datas.status === 404 && `${keypair_name}不存在或已删除`
}
} catch (error) {

}
}
}
module.exports = VolumeSnapshotService;
磁盘辅助操作配置
控制器
'use strict';

const Controller = require('egg').Controller;

class OPBlcokStorageController extends Controller {
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.DUFN = ctx.helper.deleteUndefined;
this.SERVICE = ctx.service.openstack.blcokStorage.index
};
/**
* name 储存相关配额
*
* @description
*
* @example GET /openstack/blcokstorage/limits
*
* @return {Object}
* - BackupGigabytes 备份可用磁盘可用容量 GB
* - Backups 备份可用个数 个
* - Gigabytes 磁盘可用量 GB
* - Snapshots 磁盘快照可用个数 个
* - Volumes 磁盘可用个数 个
*/
async limits() {
const { ctx } = this;
const DATAS = await this.SERVICE.limits(this.auth.ProjectID, this.auth.id);
ctx.body = DATAS
};
/**
* @name 加载磁盘到服务器
*
* @description
*
* @param {String} instance_uuid 服务器ID
* @param {String} :id 磁盘ID
*
*/
async attach_volume() {
const ctx = this.ctx;
const { instance_uuid, mode } = ctx.request.body;
const BODYS = this.DUFN({ instance_uuid, mode });
const DATAS = await this.SERVICE.attachVolume(this.auth.id, ctx.params.id, BODYS, this.auth.ProjectID);
ctx.body = DATAS;
};
/**
* @name 卸载磁盘
*
* @description
*
* @param {String} attachment_id 服务器ID
* @param {String} :id 磁盘ID
*
*/
async detach_volume() {
const ctx = this.ctx;
const { attachment_id } = ctx.request.body;
const DATAS = await this.SERVICE.detachVolume(this.auth.id, this.auth.ProjectID, ctx.params.id, attachment_id);
ctx.body = DATAS;
};
/**
* @name 创建磁盘镜像
*
* @description
*
* @param {String} image_name 镜像名称
* @param {String} volume_id 磁盘ID
*
*/
async create_image() {
const ctx = this.ctx;
const { image_name, volume_id } = ctx.request.body;
const DATAS = await this.SERVICE.createImage(this.auth.id, this.auth.ProjectID, image_name, volume_id);
ctx.body = DATAS
};
/**
* @name 磁盘扩容
*
* @param {Number} new_size 扩容容量
*/
async new_size_volume() {
const ctx = this.ctx;
const { volumeID } = ctx.params;
const { new_size } = ctx.request.body;
const DATAS = await this.SERVICE.newSizeVolume(this.auth.id, this.auth.ProjectID, volumeID, new_size);
ctx.body = DATAS
};
}

module.exports = OPBlcokStorageController;
service
'use strict';
const ServerIndex = require('../index')
//
class volumeService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.nextChars = ctx.helper.nextChars;
this.actions = ':8776/v3'
};
// 获取用户磁盘配额
async limits(project_id, _ucid) {
const DATAS = this.OSAJax(`${this.actions}/${project_id}/limits`, { _ucid })
try {
const { maxTotalBackupGigabytes, maxTotalBackups, maxTotalSnapshots, maxTotalVolumeGigabytes, maxTotalVolumes, totalBackupGigabytesUsed, totalBackupsUsed, totalGigabytesUsed, totalSnapshotsUsed, totalVolumesUsed } = (await DATAS).limits.absolute;
return {
data: {
maxTotalBackupGigabytes,
totalBackupGigabytesUsed,
'BackupGigabytes': maxTotalBackupGigabytes - totalBackupGigabytesUsed,
maxTotalBackups,
totalBackupsUsed,
'Backups': maxTotalBackups - totalBackupsUsed,
maxTotalVolumeGigabytes,
totalGigabytesUsed,
'Gigabytes': maxTotalVolumeGigabytes - totalGigabytesUsed,
maxTotalSnapshots,
totalSnapshotsUsed,
'Snapshots': maxTotalSnapshots - totalSnapshotsUsed,
maxTotalVolumes,
totalVolumesUsed,
'Volumes': maxTotalVolumes - totalVolumesUsed
}
}
} catch (error) {
console.log(error)
return error
}
};
// 磁盘挂载到服务器
async attachVolume(_ucid, volume_uuid, body, project_id) {
// const charCount = (await this.OSAJax(`:8774/v2.1/servers/${body.instance_uuid}`, { _ucid })).server['os-extended-volumes:volumes_attached'].length;
// console.log(charCount)

const DATAS = this.OSAJax(`${this.actions}/${!!project_id ? project_id : await this.getProject(_ucid)}/attachments/`, {
body: {
'attachment': {
...body,
volume_uuid
}
},
full: true,
method: 'POST',
_ucid
});
try {
const datas = await DATAS;
return {
code: datas.status,
data: datas.data
}
} catch (error) {}
};
// 磁盘从服务器卸载
async detachVolume(_ucid, ProjectID, volume_id, attachment_id) {
const DATAS = this.OSAJax(`${this.actions}/${ProjectID}/volumes/${volume_id}/action`, {
body: {
"os-detach": {
attachment_id
}
},
full: true,
method: 'POST',
_ucid
});
try {
const datas = await DATAS;
return {
code: datas.status,
}
} catch (error) {

}
};
// 扩容
async newSizeVolume(_ucid, project_id, volume_id, new_size) {
try {
const datas = await this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}/action`, {
_ucid,
method: 'POST',
body: {
"os-extend": {
new_size
}
},
full: true
});
return {
code: datas.status,
message: datas.status === 400 && `${datas.data.badRequest.message}`
}
} catch (error) {
return error
}
};
// 创建磁盘镜像
async createImage(_ucid, project_id, image_name, volume_id) {
const datas = this.OSAJax(`${this.actions}/${project_id}/volumes/${volume_id}/action`, {
_ucid,
method: 'POST',
body: {
'os-volume_upload_image': {
... {
// "force": false,
// "disk_format": "raw",
// "container_format": "bare",
"visibility": "private",
// "protected": false
},
image_name
}
}
});
try {
throw new Error('无权限')
return {
data: (await datas)['os-volume_upload_image']
}
} catch (error) {
return error
}
};
}
module.exports = volumeService;
磁盘快照
控制器
'use strict';

const Controller = require('egg').Controller;

class OPBlcokStorageVolumeSnapshotsController extends Controller {
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.QPFN = ctx.helper.queryParamFn;
this.DUFN = ctx.helper.deleteUndefined;
this.snapshotMODEL = ctx.model.Openstack.BlcokStorage.Snapshot;
this.snapshotSERVICE = ctx.service.openstack.blcokStorage.snapshots;
}
/**
* @name 磁盘快照列表
*
* @param {String} ctx.query 不需要参数
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/blcokstorage/volume
*
*/
async index() {
const { ctx } = this;
// const datas = !!ctx.isAdmin() ? await this.snapshotMODEL.getAll(this.QPFN(ctx.query)) : await this.snapshotMODEL.getUsers(this.auth.id, this.QPFN(ctx.query));
const datas = await this.snapshotSERVICE.list(this.QPFN(ctx.query), this.auth.id, ctx.isAdmin())
ctx.body = datas;
}
/**
* @name 获取单一磁盘快照
*
* @description
*
* @example GET /openstack/blcokstorage/snapshot/{id}
*
*/
async show() {
const ctx = this.ctx;
const datas = await this.snapshotSERVICE.show(ctx.params.id, this.auth.id);
ctx.body = datas;
}
/**
* @name 创建磁盘快照
*
* @param {String} name Optional 磁盘快照名称
* @param {String} description Optional 备注
* @param {String} volume_id 磁盘ID
* @param {Boolean} force Optional 是否备份
* @param {Object} metadata Optional One or more metadata key and value pairs for the snapshot.
*
* @description
*
* @example POST /openstack/blcokstorage/snapshot
*
*/
async create() {
const ctx = this.ctx;
const { name, description, volume_id, force, metadata } = ctx.request.body;
const BODYS = this.DUFN({ name, description, volume_id, force, metadata });
const datas = await this.snapshotMODEL.createOne(this.auth.id, BODYS);
ctx.body = datas
}
/**
* @name 删除快照
*
* @param {*} snapshot_id 快照ID
*
*/
async destroy() {
const ctx = this.ctx;
const datas = await this.snapshotSERVICE.destroy(this.auth.id, this.auth.ProjectID, ctx.params.id);
ctx.body = datas
}
}

module.exports = OPBlcokStorageVolumeSnapshotsController;
service
'use strict';
const ServerIndex = require('../index')
//
class VolumeSnapshotService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.adminprojectID = this.config.openstack.projectID.default
this.actions = ':8776/v3'
};
// 获取磁盘快照
async list(query, _ucid, isAdmin) {
const detail = Object.keys(query).includes('detail');
delete query.detail
try {
const datas = await this.OSAJax(`${this.actions}/${!!isAdmin ? this.adminprojectID : await this.getProject(_ucid)}/snapshots${detail ? '/detail' : ''}`, {
...!isAdmin && { _ucid },
body: { ...isAdmin && { 'all_tenants': true } }
});
return {
data: {
result: datas.snapshots,
totalCount: datas.snapshots.length
}
};
} catch (error) {
return error
}
};
// 获取磁盘快照详情
async show(id, _ucid) {
try {
const datas = await this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/snapshots/${id}`, { _ucid });
return { data: datas.snapshot };
} catch (error) {
return error
}
}
// 创建磁盘快照
async create(_ucid, bodys, type = 'manual') {
try {
const datas = await this.OSAJax(`${this.actions}/${await this.getProject(_ucid)}/snapshots`, {
body: {
'snapshot': {
... {
"name": `${!bodys.name && `Snapshot-${type}-${Math.random().toString(36).slice(2, 8)}`}`,
"force": true,
"metadata": null
},
...bodys
}
},
method: 'POST',
_ucid
});
return datas
} catch (error) {
return error
}
}
/**
* @name 删除
* @param {*} _ucid 用户id
* @param {*} project_id 密钥对名称
* @param {*} snapshot_id 快照ID
*/
async destroy(_ucid, project_id, snapshot_id) {
try {
const datas = await this.OSAJax(`${this.actions}/${project_id}/snapshots/${snapshot_id}`, {
_ucid,
method: 'DELETE',
full: true
});
return {
message: datas.status === 404 && `${keypair_name}不存在或已删除`
}
} catch (error) {

}
}
}
module.exports = VolumeSnapshotService;
model
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const { helper, service } = app.createAnonymousContext();
const { NumToStr } = ctx.helper;
const OSblockStorageSnapshotSchema = new Schema({
// 快照类型
type: String,
// 快照状态
// status: String,
// 快照大小
size: Number,
// 快照元信息
metadata: {},
// 快照名称
name: String,
// 快照所属磁盘ID
volume_id: String,
// 创建时间
created_at: Date,
// 描述 prjectID Date
description: String,
// 快照ID
id: String,
// 更新时间
updated_at: Date,
// 公司id
_comp: {
type: Schema.Types.ObjectId,
ref: 'Company',
required: true,
index: true
},
// 状态 ['删除','正常','锁定'] 0,1,2
_status: {
type: Number,
default: 1,
get: v => NumToStr(['删除', '正常', '锁定'], v, true),
},
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
OSblockStorageSnapshotSchema.statics = {
getUsers: async function (_id, queryMix) {
const { querys, select, pages, sort, dates } = queryMix;
const MODELS = this.find({
'_comp': _id,
...querys,
}, {
...select,
})
.limit(!!pages ? pages.limit : 10)
.sort({
'_id': -1,
...sort
});
return {
data: {
result: await MODELS,
totalCount: await MODELS.count()
}
}
},
createOne: async function (_id, body, type) {
const DATAS = await service.openstack.blcokStorage.snapshots.create(_id, body, type);
const MODEL = this.create({
_comp: _id,
...DATAS['snapshot']
});
try {
return { data: await MODEL };
} catch (error) {
return error
}
},
// 获取全部
getAll: async function (queryMix) {
const { querys, select, pages, sort, dates } = queryMix;
const MODELS = this.find({
'status': { '$ne': 0 },
...querys,
// ...(!!pages && !!pages.marker && { '_id': { "$lt": pages.marker } }),
}, {
...select,
})
// .limit(!!pages ? pages.limit : 10)
.sort({
// '_id': -1,
'id': 1,
...sort
});
return { data: { result: await MODELS, totalCount: await MODELS.count() } };
}
}
return mongoose.model('openstack_block_storage_snapshot', OSblockStorageSnapshotSchema)
}

磁盘类型
控制器
'use strict';

const Controller = require('egg').Controller;

class blcokStorageTypesController extends Controller {
constructor(ctx) {
super(ctx);
this.auth = ctx.state.user;
this.QMFN = ctx.helper.queryParamFn;
this.deleteUndefined = ctx.helper.deleteUndefined;
this.volumeTypesMODEL = ctx.model.Openstack.BlcokStorage.Types;
this.volumeTypesSERVICE = ctx.service.openstack.blcokStorage.types
}
/**
* @name servers type 列表
*
* @description query参数detail存在则显示实力配置列表详细信息,若不传仅显示概要列表
*
* @example GET /openstack/blcokstorage/
*
*/
async index() {
const {
ctx,
service
} = this;
const datas = await this.volumeTypesMODEL.getAll(this.auth.id, ctx.isAdmin());
// const datas = await this.volumeTypesSERVICE.list(this.auth.id, this.auth.ProjectID, ctx.isAdmin())
ctx.body = datas;
}
}

module.exports = blcokStorageTypesController;
service
'use strict';
const ServerIndex = require('../index')
//
class volumeTypesService extends ServerIndex {
constructor(ctx) {
super(ctx);
this.actions = ':8776/v3'
};
// 获取磁盘类型列表
async list(_ucid, project_id, isAdmin) {
const {
config
} = this;
const datas = await this.OSAJax(`${this.actions}/${project_id || config.openstack.projectID.default}/types`, {
...!isAdmin && _ucid
});
try {
return {
data: {
result: datas.volume_types,
totalCount: datas.volume_types.length
}
};
} catch (error) {
return error
}
}
}
module.exports = volumeTypesService;
MODEL
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const ctx = app.createAnonymousContext();
const { NumToStr } = ctx.helper;
const OSStorageTypeSchema = new Schema({
// opID
id: String,
// 是否公用
is_public: Boolean,
// 磁盘名称
name: String,
// 磁盘描述备注
description: String,
// 状态 ['删除','正常','锁定'] 0,1,2
status: {
type: Number,
default: 1,
get: v => NumToStr(['删除', '正常', '锁定'], v, true),
},
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
OSStorageTypeSchema.statics = {
// 同步openstack 实例配置
syncFN: async function () {
try {
const datas = (await ctx.service.openstack.blcokStorage.types.list()).data;
if (datas.totalCount) {
let updateModel = datas.result.map(e => this.findOneAndUpdate({ 'id': e.id }, { ...e }, { 'upsert': true, 'new': true }));
let result = await Promise.all(updateModel);
return result;
}
} catch (error) {
return error
}
},
// 获取全部
getAll: async function (queryMix, isAdmin) {
const { querys, select, pages, sort, dates } = queryMix;
const models = this.find({
'status': { '$ne': 0 },
...querys,
// ...(!!pages && !!pages.marker && { '_id': { "$lt": pages.marker } }),
}, {
...select,
...!isAdmin && {
'__v': 0,
'created': 0,
'updated': 0,
'_id': 0
}
})
// .limit(!!pages ? pages.limit : 10)
.sort({
// '_id': -1,
'id': 1,
...sort
});
return { data: { result: await models, totalCount: await models.count() } };
}
}
return mongoose.model('openstack_block_storage_types', OSStorageTypeSchema)
}

0 个评论

要回复文章请先登录注册