Files
qmi-cloud/server/routes/api-users.js
Manuel Romero 69dffe0710 fix redshift
2025-07-24 12:56:23 +02:00

1524 lines
44 KiB
JavaScript

const express = require('express')
const router = express.Router()
const db = require('@QMI/qmi-cloud-common/mongo');
const passport = require('../passport-okta');
const fs = require('fs-extra');
const cli = require('@QMI/qmi-cloud-common/cli');
const sendEmail = require("@QMI/qmi-cloud-common/send-email");
const requestIp = require('request-ip');
const utils = require('../utils');
var qmiConfig = require('@QMI/qmi-cloud-common/qmi-config').qmiConfig;
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
const MYQUEUES = require('@QMI/qmi-cloud-common/queues');
const queues = MYQUEUES.queues;
const TF_APPLY_QUEUE = MYQUEUES.TF_APPLY_QUEUE;
const TF_APPLY_QSEOK_QUEUE = MYQUEUES.TF_APPLY_QSEOK_QUEUE;
const TF_DESTROY_QUEUE = MYQUEUES.TF_DESTROY_QUEUE;
const STOP_CONTAINER_QUEUE = MYQUEUES.STOP_CONTAINER_QUEUE;
const SYNAPSE_QUEUE = MYQUEUES.SYNAPSE_QUEUE;
const WEBHOOK_QUEUE = MYQUEUES.WEBHOOK_QUEUE;
/**
* @swagger
* /users:
* get:
* description: Get all users
* summary: Get all users
* parameters:
* - name: filter
* in: query
* required: false
* type: object
* content:
* application/json:
* schema:
* type: object
* produces:
* - application/json
* responses:
* 200:
* description: User
*/
router.get('/', passport.ensureAuthenticated, async (req, res, next) => {
try {
const filter = req.query.filter? JSON.parse(req.query.filter) : {};
const result = await db.user.get(filter, "-msGroups");
return res.json(result);
} catch (error) {
next(error);
}
});
router.get('/myclientip', (req, res, next) => {
const ipAddress = requestIp.getClientIp(req);
return res.send(ipAddress);
});
/**
* @swagger
* /users/me:
* get:
* description: Get profile logged-in user
* summary: Get logged-in user
* produces:
* - application/json
* responses:
* 200:
* description: User
*/
router.get('/me', passport.ensureAuthenticated, async (req, res, next) => {
try {
const result = await db.user.getById(req.user._id);
return res.json(result);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}:
* get:
* description: Get profile for an user
* summary: Get profile for an user
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* produces:
* - application/json
* responses:
* 200:
* description: User
*/
router.get('/:userId', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
const result = await db.user.getById(userId);
return res.json(result);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}:
* put:
* description: Update profile for an user
* summary: Update profile for an user
* tags:
* - admin
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - in: body
* name: body
* description: User object
* required: true
* produces:
* - application/json
* responses:
* 200:
* description: User
*/
router.put('/:userId', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
const result = await db.user.update(userId, req.body);
return res.json(result);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions:
* post:
* description: Start a new Terraform provision
* summary: Start a new Terraform provision
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* scenario:
* type: string
* description:
* type: string
* options:
* type: object
* properties:
* vm1:
* type: object
* properties:
* vmType:
* type: string
* version:
* type: object
* properties:
* name:
* type: string
* image:
* type: string
* responses:
* 200:
* description: Provision
* 404:
* description: Scenario not found
* 400:
* description: Invalid options
*/
router.post('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
req.body.user = userId;
const scenarioSource = await db.scenario.getOne({name: req.body.scenario});
if (!scenarioSource) {
return res.status(404).json({"msg": "Scenario not found "});
}
const filterProvisions = {"user": userId, "isDestroyed": false, "isDeleted": false, "scenario": scenarioSource.name };
const result = await db.provision.get(filterProvisions);
if ( scenarioSource.numSimultaneousProvisions && result.total >= scenarioSource.numSimultaneousProvisions ) {
return res.status(400).json({"msg": "Number of simultaneous provisions reached for this scenario: " + scenarioSource.numSimultaneousProvisions});
}
if ( scenarioSource.name.includes('onelabs-databricks') && req.body.options && req.body.options.catalog_name && req.body.options.catalog_name.selected){
const thingName = req.body.options.catalog_name.selected.value;
const onelabProv = await db.provision.getOne({"user": userId, "status":"provisioned", "scenario": scenarioSource.name, "description": thingName, "isDestroyed": false});
if ( onelabProv ) {
queues[WEBHOOK_QUEUE].add("webhook_job", {
provId: onelabProv._id,
scenario: onelabProv.scenario,
user: userId,
eventType: 'provision.finished'
});
return res.status(200).json(onelabProv);
}
}
if ( scenarioSource.name.includes('onelabs-snowflake') && req.body.options && req.body.options.user_name && req.body.options.user_name.selected){
const thingName = req.body.options.user_name.selected.value;
const onelabProv = await db.provision.getOne({"user": userId, "status":"provisioned", "scenario": scenarioSource.name, "description": thingName, "isDestroyed": false});
if ( onelabProv ) {
queues[WEBHOOK_QUEUE].add("webhook_job", {
provId: onelabProv._id,
scenario: onelabProv.scenario,
user: userId,
eventType: 'provision.finished'
});
return res.status(200).json(onelabProv);
}
}
//if (!req.body.options || !req.body.options.vm1 || !req.body.options.vm1.vmType ) {
// return res.status(400).json({"msg": "Invalid options"});
//}
req.body.scenarioVersion = scenarioSource.version;
if ( req.body.scheduleData && req.body.scheduleData.is24x7 !== undefined ) {
const schedule = await db.schedule.add(req.body.scheduleData);
req.body.schedule = schedule._id;
} else {
req.body.schedule = null;
}
req.body.terraformImage = scenarioSource.terraformImage || process.env.DOCKERIMAGE_TERRAFORM;
//---Accomodation old QDI Cloud Storage
if (req.body.vmImage) {
req.body.options = {};
if (req.body.vmImage.db) {
if (req.body.scenario === 'azqmi-synapse'){
req.body.options['sku'] = {
selected: {
value: req.body.vmImage.db.version.image,
name: req.body.vmImage.db.version.name
}
};
} else {
req.body.options['db'] = {
selected: {
value: req.body.vmImage.db.version.image,
name: req.body.vmImage.db.version.name
}
};
}
}
if (req.body.vmImage.qdi_sa_id) {
req.body.options['qdi_sa_id'] = {
selected: {
value: req.body.vmImage.qdi_sa_id.version.image,
name: req.body.vmImage.qdi_sa_id.version.name
}
};
}
if (req.body.vmImage.qdi_repl_id) {
req.body.options['qdi_repl_id'] = {
selected: {
value: req.body.vmImage.qdi_repl_id.version.image,
name: req.body.vmImage.qdi_repl_id.version.name
}
};
}
if (req.body.vmImage.qdisacc_name) {
req.body.options['qdisacc_name'] = {
selected: {
value: req.body.vmImage.qdisacc_name.version.image,
name: req.body.vmImage.qdisacc_name.version.name
}
};
}
if (req.body.vmImage.qdisacc_accesskey) {
req.body.options['qdisacc_accesskey'] = {
selected: {
value: req.body.vmImage.qdisacc_accesskey.version.image,
name: req.body.vmImage.qdisacc_accesskey.version.name
}
};
}
}
let theUser = await db.user.getById(userId);
if (theUser && theUser.msGroups && theUser.msGroups.length){
const forced_destroy_groups = qmiConfig().forced_destroy_groups;
const forced_destroy_period_days = qmiConfig().forced_destroy_period_days;
let isGroupFound = theUser.msGroups.some( ai => forced_destroy_groups.includes(ai) );
if (isGroupFound) {
let dd = new Date();
dd.setDate(dd.getDate() + forced_destroy_period_days);
req.body['forcedDestroyDate'] = dd;
}
}
if ( req.body.parent ) {
let parentProv = await db.provision.getById(req.body.parent);
if ( parentProv && parentProv.forcedDestroyDate ) {
req.body['forcedDestroyDate'] = parentProv.forcedDestroyDate;
}
}
delete req.body['vmImage'];
//---
const provision = await db.provision.add(req.body);
if ( provision.scenario === "azqmi-qseok" ){
queues[TF_APPLY_QSEOK_QUEUE].add("tf_apply_qseok_job", {
scenario: req.body.scenario,
vmType: req.body.vmType || null,
nodeCount: req.body.nodeCount,
id: provision._id,
user: req.user,
_scenario: scenarioSource
});
} else {
queues[TF_APPLY_QUEUE].add("tf_apply_job", {
scenario: req.body.scenario,
vmType: req.body.vmType,
nodeCount: req.body.nodeCount,
id: provision._id,
user: req.user,
_scenario: scenarioSource
});
}
return res.status(200).json(provision);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}:
* get:
* description: Get provision details
* summary: Get provision details
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* produces:
* - application/json
* responses:
* 200:
* description: Provision
*/
router.get('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
let provision = await db.provision.getById(req.params.id);
return res.json(provision);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}:
* put:
* description: Update Provision by ID
* summary: Update Provision by ID
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* - in: body
* name: body
* description: Provision object
* required: true
* produces:
* - application/json
* responses:
* 200:
* description: Provision
*/
router.put('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
const triggerUser = req.user;
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
}
try {
let schedule;
var msg = "";
let patch = req.body || {};
if ( req.body.scheduleData ) {
if ( req.body.scheduleData._id ) {
schedule = await db.schedule.update(req.body.scheduleData._id, req.body.scheduleData);
msg += `Updated running schedule (${schedule._id}). `;
} else {
schedule = await db.schedule.add(req.body.scheduleData);
msg += `New running schedule (${schedule._id}). `;
}
var tagsEdit = {
"24x7": schedule.is24x7? " " : false,
"StartupTime": (schedule.isStartupTimeEnable && !schedule.is24x7 && schedule.utcTagStartupTime)? schedule.utcTagStartupTime : false,
"ShutdownTime": (!schedule.is24x7 && schedule.utcTagShutdownTime)? schedule.utcTagShutdownTime : false
}
cli.updateVmsTags(provision._id, tagsEdit);
patch.schedule = schedule._id;
delete patch['scheduleData'];
}
var resShared = null;
var resProvision = await db.provision.update(provision._id, patch);
if ( patch.user ) {
msg += `Changed owner (${patch.user}).`;
resShared = await db.sharedProvision.updateMany({"provision": provision._id}, {"user": patch.user});
}
let result = {
provision: resProvision,
sharedProvision: resShared
}
db.event.add({ user: triggerUser._id, provision: provision._id, type: 'provision.update', message: msg });
return res.json(result);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}:
* delete:
* description: Delete Provision by ID
* summary: Delete a Terraform Provision by ID
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.delete('/:userId/provisions/:id', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const triggerUser = req.user;
const provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
}
//var delDest = provision.destroy._id;
//if ( provision.destroy ) {
// delDest = await db.destroy.del(provision.destroy._id);
//}
const delProv = await db.provision.update(req.params.id, {"isDeleted": true});
//Move folder
if (fs.existsSync(`/provisions/${provision.scenario}_${req.params.id}`)) {
fs.moveSync(`/provisions/${provision.scenario}_${req.params.id}`, `/provisions/deleted/${provision.scenario}_${req.params.id}`, { overwrite: true })
}
db.event.add({ user: triggerUser._id, provision: provision._id, type: 'provision.delete-history' });
return res.json({"provision": delProv, "destroy": delProv.destroy});
} catch (error) {
next(error);
}
});
/**
* /users/{userId}/provisions/{id}/barracuda:
* get:
* description: Barracuda - get details and provision status
* summary: Barracuda - get details and provision status
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
/*router.get('/:userId/provisions/:id/barracuda', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
}
if ( !provision.barracudaAppId ) {
console.log(`APIUser# Provision (${req.params.id}) does not have a barracudaAppId value!`);
return res.status(404).json({"msg": "Not found Barracuda App for this provision"});
}
var app = await barracuda.getApp(provision);
return res.json(app);
} catch (error) {
next(error);
}
});*/
/**
* /users/{userId}/provisions/{id}/barracuda:
* post:
* description: Barracuda - give a provision external access
* summary: Barracuda - give a provision external access
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
/*router.post('/:userId/provisions/:id/barracuda', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
}
if ( !provision.barracudaAzureFqdn ) {
console.log(`APIUser# Provision (${req.params.id}) does not have a barracudaAzureFqdn value!`);
return res.json(provision);
}
if ( provision.barracudaAppId ) {
console.log(`APIUser# Provision (${req.params.id}) already have a Barracuda App (${provision.barracudaAppId})!`);
return res.json(provision);
}
console.log(`APIUser# Calling Barracuda service to create App and DNS CName for provision (${provision._id})`);
barracuda.createApp(provision);
return res.json(provision);
} catch (error) {
next(error);
}
});*/
/**
* /users/{userId}/provisions/{id}/barracuda:
* delete:
* description: Barracuda - delete a provision external access
* summary: Barracuda - delete a provision external access
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
/*router.delete('/:userId/provisions/:id/barracuda', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
}
if ( !provision.barracudaAppId ) {
console.log(`APIUser# Provision (${req.params.id}) does not have a barracudaAppId value!`);
return res.json({});
}
console.log(`APIUser# Calling Barracuda service to delete App and DNS CName for provision (${provision._id})`);
barracuda.deleteApp(provision);
return res.json(provision);
} catch (error) {
next(error);
}
});*/
/**
* @swagger
* /users/{userId}/provisions/{id}/abort:
* post:
* description: Abort provision
* summary: Abort provision
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.post('/:userId/provisions/:id/abort', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
}
queues[STOP_CONTAINER_QUEUE].add("tf_abort_apply_job", {
provId: provision._id,
user: req.user
});
return res.json({"status": "aborting"});
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/deallocatevms:
* post:
* description: Stop all VMs for this provision
* summary: Stop all VMs for this provision
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.post('/:userId/provisions/:id/deallocatevms', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const triggerUser = req.user;
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found provision with id "+req.params.id});
}
//Set DivvyTags according to Schedule
if ( provision.schedule && req.body.isStartupTimeEnable !== undefined ) {
console.log("APIUser# Set DivvyTags according to schedule");
var schedule = await db.schedule.update(provision.schedule._id, { "isStartupTimeEnable": req.body.isStartupTimeEnable });
var tagsEdit = {
"24x7": schedule.is24x7? " " : false,
"StartupTime": (schedule.isStartupTimeEnable && !schedule.is24x7 && schedule.utcTagStartupTime)? schedule.utcTagStartupTime : false,
"ShutdownTime": (!schedule.is24x7 && schedule.utcTagShutdownTime)? schedule.utcTagShutdownTime : false
}
cli.updateVmsTags(provision._id, tagsEdit);
}
if (provision.scenario === 'azqmi-synapse') {
queues[SYNAPSE_QUEUE].add("synapse_job", {
provId: provision._id,
tasktype: 'pause',
user: req.user
});
} else if(provision.scenario === 'awsqmi-rds') {
cli.stopDb(provision._id, triggerUser._id);
} else if(provision.scenario === 'awsqmi-redshift') {
cli.stopRedshiftCluster(provision._id, triggerUser._id);
} else {
cli.deallocate(provision._id, triggerUser._id);
}
provision.statusVms = "Stopping";
return res.json(provision);
} catch (error) {
db.provision.update(req.params.id, {"statusVms": "Error_Stopping"});
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/startvms:
* post:
* description: Start all VMs for this provision
* summary: Start all VMs for this provision
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.post('/:userId/provisions/:id/startvms', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const triggerUser = req.user;
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
}
//Re-enable DivvyTags according to schedule
if ( provision.schedule ) {
let schedule = await db.schedule.getById(provision.schedule._id);
console.log("APIUser# Re-enabling DivvyTags according to schedule");
var tagsEdit = {
"24x7": schedule.is24x7? " " : false,
"StartupTime": (schedule.isStartupTimeEnable && !schedule.is24x7 && schedule.utcTagStartupTime)? schedule.utcTagStartupTime : false,
"ShutdownTime": (!schedule.is24x7 && schedule.utcTagShutdownTime)? schedule.utcTagShutdownTime : false
}
cli.updateVmsTags(provision._id, tagsEdit);
}
if (provision.scenario === 'azqmi-synapse') {
queues[SYNAPSE_QUEUE].add("synapse_job", {
provId: provision._id,
tasktype: 'resume',
user: req.user
});
} else if(provision.scenario === 'awsqmi-rds') {
cli.startDb(provision._id, triggerUser._id);
} else if(provision.scenario === 'awsqmi-redshift') {
cli.startRedshiftCluster(provision._id, triggerUser._id);
} else {
cli.start(provision._id, triggerUser._id);
}
provision.statusVms = "Starting";
return res.json(provision);
} catch (error) {
db.provision.update(req.params.id, {"statusVms": "Error_Starting"});
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/rotate-sa-key:
* post:
* description: Rotate Storage Account AccessKey
* summary: Rotate Storage Account AccessKey
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* - name: keyName
* in: query
* type: string
* required: false
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.post('/:userId/provisions/:id/rotate-sa-key', passport.ensureAuthenticated, async (req, res, next) => {
try {
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
}
const modProvision = await cli.rotateStorageAccountKey(provision._id, req.query.keyName);
if (modProvision) {
sendEmail.sendRotateKey(modProvision, modProvision.user);
}
db.event.add({ user: req.user._id, provision: provision._id, type: `rotated-key.az-sa`, message: `` });
return res.json(modProvision);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/rotate-awsiam-key:
* post:
* description: Rotate AWS IAM user Access Key
* summary: Rotate AWS IAM user Access Key
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.post('/:userId/provisions/:id/rotate-awsiam-key', passport.ensureAuthenticated, async (req, res, next) => {
try {
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
}
const modProvision = await cli.rotateIAMUserAccessKey(provision);
if (modProvision) {
sendEmail.sendRotateAWSKey(modProvision, modProvision.user);
}
db.event.add({ user: req.user._id, provision: provision._id, type: `rotated-key.aws-iam`, message: `` });
return res.json(modProvision);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/get-awsiam-key:
* get:
* description: Check AWS IAM user Access Key
* summary: Check AWS IAM user Access Key
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.get('/:userId/provisions/:id/get-awsiam-key', passport.ensureAuthenticated, async (req, res, next) => {
try {
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
}
const result = await cli.checkIAMUserAccessKey(provision);
return res.json(result);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/extend:
* post:
* description: Extend this provision Running more time
* summary: Extend this provision Running more time
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.post('/:userId/provisions/:id/extend', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
}
/*if ( provision.countExtend === 5 ) {
return res.status(200).json({"msg": "You have reached the limit for the number of times to extend the Running VMs period."});
}*/
let timeRunning = db.utils.getNewTimeRunning(provision);
let countExtend = db.utils.getNewCountExtend(provision);
provision = await db.provision.update(req.params.id, {"runningFrom":new Date(), "timeRunning": timeRunning, "countExtend": countExtend, "pendingNextAction": null});
console.log(`APIUser# Extending running period fo provision (${provision._id}), new total extends: ${countExtend}`);
return res.json(provision);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/destroy:
* post:
* description: Destroy a Terraform Provision
* summary: Destroy a Terraform Provision
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.post('/:userId/provisions/:id/destroy', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
let provision = await db.provision.getById(req.params.id);
if (!provision){
return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
}
if ( provision.destroy && provision.destroy.status !== 'error' ) {
console.log(`APIUser# This provision is already destroyed or being destroyed right now: ${provision._id}`);
return res.status(200).json(provision);
}
//
console.log(`APIUser# Queueing destroy provision: ${provision._id}`);
const destroyJob = await db.destroy.add({ "user": userId });
provision = await db.provision.update(req.params.id, {"destroy": destroyJob._id});
const scenarioSource = await db.scenario.getOne({name: provision.scenario});
queues[TF_DESTROY_QUEUE].add("tf_destroy_job", {
scenario: provision.scenario,
provId: provision._id,
user: req.user,
id: destroyJob._id,
_scenario: scenarioSource
});
//Check children provisions
let children = await db.provision.get({ "parent": provision._id, "isDestroyed": false, "isDeleted": false });
if (children.results.length > 0 ) {
await asyncForEach(children.results, async function(child) {
if ( !child.destroy || child.destroy.status === 'error' ) {
console.log(`APIUser# Queueing destroy children provision: ${child._id}`);
let destroyJobChild = await db.destroy.add({ "user": userId });
await db.provision.update(child._id, {"destroy": destroyJobChild._id});
let scenarioSourceChild = await db.scenario.getOne({name: child.scenario});
queues[TF_DESTROY_QUEUE].add("tf_destroy_job", {
scenario: child.scenario,
provId: child._id,
user: req.user,
id: destroyJobChild._id,
_scenario: scenarioSourceChild
});
} else {
console.log(`APIUser# This child provision is already destroyed or being destroyed right now: ${child._id}`);
}
})
}
return res.status(200).json(provision);
} catch (error) {
return res.status(error.output.statusCode).json({"err":error});
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/share/{withUserId}:
* put:
* description: Share provision with another user
* summary: Share provision with another user
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* - name: withUserId
* in: path
* type: string
* required: true
* - in: body
* name: body
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.put('/:userId/provisions/:id/share/:withUserId', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
let provision = await db.provision.getById(req.params.id);
var shareWithUser = await db.user.getById(req.params.withUserId);
if (!provision || !shareWithUser){
return res.status(404).json({"msg": "Not found privision with id "+req.params.id});
}
if ( req.params.withUserId === provision.user._id ) {
return res.status(400).json({"msg": "Can't share with the same user"});
}
let found = await db.sharedProvision.getOne({
"user": provision.user._id,
"provision": provision._id,
"sharedWithUser": req.params.withUserId
});
if ( !found ) {
let canManage = req.body && req.body.type === "manage";
found = await db.sharedProvision.add({"user": provision.user._id, "provision": provision._id, "sharedWithUser": req.params.withUserId, "canManage": canManage})
sendEmail.sendSharedProvision(provision, shareWithUser);
db.event.add({ user: userId, provision: provision._id, type: 'provision.share', 'message': `Start sharing with user (${req.params.withUserId}) with "${canManage? 'manage' : 'view'}" permission` });
}
return res.json(found);
} catch (error) {
return res.status(error.output.statusCode).json({"err":error});
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/share/{withUserId}:
* delete:
* description: Stop sharing this provision with another user
* summary: Stop sharing this provision with another user
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* - name: withUserId
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.delete('/:userId/provisions/:id/share/:withUserId', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
if ( req.params.withUserId === userId ) {
return res.status(400).json({"msg": "Can't share with the same user"});
}
const result = await db.sharedProvision.delMany({"provision": req.params.id, "sharedWithUser": req.params.withUserId});
db.event.add({ user: userId, provision: req.params.id, type: 'provision.stop-share', 'message': `Stop sharing with user (${req.params.withUserId})` });
return res.json(result);
} catch (error) {
return res.status(error.output.statusCode).json({"err":error});
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/share:
* delete:
* description: Stop sharing this provision with everybody
* summary: Stop sharing this provision with everybody
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.delete('/:userId/provisions/:id/share', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
if ( req.params.withUserId === userId ) {
return res.status(400).json({"msg": "Can't share with the same user"});
}
const result = await db.sharedProvision.delMany({"provision": req.params.id, "sharedWithUser": req.params.withUserId});
return res.json(result);
} catch (error) {
return res.status(error.output.statusCode).json({"err":error});
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/share:
* get:
* description: Get shares of this provision
* summary: Get shares of this provision
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.get('/:userId/provisions/:id/share', passport.ensureAuthenticated, async (req, res, next) => {
try {
let result = await db.sharedProvision.get({"provision": req.params.id});
return res.json(result);
} catch (error) {
return res.status(error.output.statusCode).json({"err":error});
}
});
/**
* @swagger
* /users/{userId}/sharedprovisions:
* get:
* description: Get provision shared with me
* summary: Get provision shared with me
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* responses:
* 200:
* description: Provision
* 404:
* description: Not found
*
*/
router.get('/:userId/sharedprovisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
let out = await db.sharedProvision.get({"sharedWithUser": userId});
return res.json(out);
} catch (error) {
return res.status(error.output.statusCode).json({"err":error});
}
});
/**
* @swagger
* /users/{userId}/provisions:
* get:
* description: Get all Provisions for an User
* summary: Get all Provisions for an User
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* responses:
* 200:
* description: JSON Array
*/
router.get('/:userId/provisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
const filter = {"user": userId, "isDeleted": false, $or: [ { isUIHidden: { $exists: false } }, { isUIHidden: false } ] };
const result = await db.provision.get(filter);
return res.json(result);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/events:
* get:
* description: Get all Events for an User
* summary: Get all Events for an User
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* responses:
* 200:
* description: JSON Array
*/
router.get('/:userId/events', passport.ensureAuthenticated, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
const result = await db.event.get({"user": userId});
return res.json(result);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/provisions/{id}/events:
* get:
* description: Get all Events for an User and Provision
* summary: Get all Events for an User and Provision
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* - name: id
* in: path
* type: string
* required: true
* responses:
* 200:
* description: JSON Array
*/
router.get('/:userId/provisions/:id/events', passport.ensureAuthenticated, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
const result = await db.event.get({"provision": req.params.id});
return res.json(result);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/scenarios:
* get:
* description: Get all Provisions for an User
* summary: Get all Provisions for an User
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* responses:
* 200:
* description: JSON Array
*/
router.get('/:userId/scenarios', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
let filter = {};
if (req.user.role === "user") {
filter.isAdminOnly = false;
}
filter.isDisabled = filter.isDisabled || false;
var result = await db.scenario.get(filter);
if (req.user.role === "user") {
result.results = result.results.filter( scenario => {
let noAllowedUsers = !scenario.allowedUsers || scenario.allowedUsers.length === 0;
if ( noAllowedUsers ) {
return true;
} else {
let allowedUserIds = scenario.allowedUsers.map( u=> u._id.toString());
return allowedUserIds.indexOf(req.user._id.toString()) !== -1;
}
});
}
return res.json(result);
} catch (error) {
next(error);
}
});
/**
* @swagger
* /users/{userId}/destroyprovisions:
* get:
* description: Get all Destroy Provisions for an User
* summary: Get all Destroy Provisions for an User
* produces:
* - application/json
* parameters:
* - name: userId
* in: path
* type: string
* required: true
* responses:
* 200:
* description: JSON Array
*/
router.get('/:userId/destroyprovisions', passport.ensureAuthenticatedAndIsMe, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
const result = await db.destroy.get({"user": userId});
return res.json(result);
} catch (error) {
next(error);
}
});
router.get('/:userId/settitle', passport.ensureAuthenticatedAndAdmin, async (req, res, next) => {
try {
const userId = req.params.userId === 'me'? req.user._id : req.params.userId;
let patch = {};
if ( req.query.title ) {
patch['jobTitle'] = req.query.title;
}
const result = await db.user.update(userId, patch);
utils.saveUserPhoto(result.upn, result.oid);
return res.json(result);
} catch (error) {
next(error);
}
});
module.exports = router;