From c2c64dafe7f2a4fc2accd7ee5f87d382886bbedb Mon Sep 17 00:00:00 2001 From: Jannik Schönartz Date: Fri, 15 Mar 2019 04:49:30 +0000 Subject: [external-backeds] Big idoit rework, to match the updated api --- server/api/backends.js | 133 ++- server/api/registration.js | 141 ++- server/lib/external-backends/backendhelper.js | 48 +- .../external-backends/backends/idoit-backend.js | 987 +++++++-------------- .../external-backends/backends/infoblox-backend.js | 16 +- server/lib/external-backends/index.js | 10 +- webapp/src/components/BackendModule.vue | 34 +- webapp/src/components/BackendModuleEdit.vue | 1 + 8 files changed, 500 insertions(+), 870 deletions(-) diff --git a/server/api/backends.js b/server/api/backends.js index 7738ec7..838467a 100644 --- a/server/api/backends.js +++ b/server/api/backends.js @@ -59,17 +59,15 @@ router.getAsync('/:id', async (req, res) => { * * @return: Returns a list with all objects of the backend. */ -router.get('/:id/objects', (req, res) => { +router.getAsync('/:id/objects', async (req, res) => { const id = req.params.id - db.backend.findOne({ where: { id: id } }).then(backend => { - if (backend) { - const ba = new ExternalBackends() - const instance = ba.getInstance(backend.type) - instance.getObjects(backend.credentials).then(result => { - res.status(200).send(result) - }) - } else res.status(500).send({ error: 'INVALID_BACKEND_ID', message: 'The provided backend id is invalid.' }) - }) + const backend = await db.backend.findOne({ where: { id: id } }) + if (backend) { + const ba = new ExternalBackends() + const instance = ba.getInstance(backend.type) + const result = await instance.getObjects(backend.credentials) + res.status(200).send(result) + } else res.status(500).send({ error: 'INVALID_BACKEND_ID', message: 'The provided backend id is invalid.' }) }) /* @@ -78,18 +76,16 @@ router.get('/:id/objects', (req, res) => { * * @return: Returns information about a given object and all childs. */ -router.get('/:id/objects/:oid', (req, res) => { +router.getAsync('/:id/objects/:oid', async (req, res) => { const id = req.params.id const oid = req.params.oid - db.backend.findOne({ where: { id: id } }).then(backend => { - if (backend) { - const ba = new ExternalBackends() - const instance = ba.getInstance(backend.type) - instance.getObject(backend.credentials, oid).then(result => { - res.status(200).send(result) - }) - } else res.status(500).send({ error: 'INVALID_BACKEND_ID', message: 'The provided backend id is invalid.' }) - }) + const backend = await db.backend.findOne({ where: { id: id } }) + if (backend) { + const ba = new ExternalBackends() + const instance = ba.getInstance(backend.type) + const result = await instance.getObject(backend.credentials, oid) + res.status(200).send(result) + } else res.status(500).send({ error: 'INVALID_BACKEND_ID', message: 'The provided backend id is invalid.' }) }) /* @@ -97,15 +93,13 @@ router.get('/:id/objects/:oid', (req, res) => { * * @return: Returns a list of all the object types of the given backend. [{id: , title: }, ...] */ -router.get('/:id/objecttypes', (req, res) => { +router.getAsync('/:id/objecttypes', async (req, res) => { const id = req.params.id - db.backend.findOne({ where: { id: id } }).then(backend => { - const ba = new ExternalBackends() - const instance = ba.getInstance(backend.type) - instance.getObjectTypes(backend.credentials).then(result => { - res.status(200).send(result) - }) - }) + const backend = await db.backend.findOne({ where: { id: id } }) + const ba = new ExternalBackends() + const instance = ba.getInstance(backend.type) + const result = await instance.getObjectTypes(backend.credentials) + res.status(200).send(result) }) /* @@ -301,41 +295,37 @@ router.get('/:id/import', (req, res) => { // TODO: Move to clients? // TODO: receive files should be authenticated! // Gets a list of all the files uploaded and connected to the client. -noAuthRouter.get('/:id/:uuid/files', (req, res) => { +noAuthRouter.getAsync('/:id/:uuid/files', async (req, res) => { const id = req.params.id const uuid = req.params.uuid - db.backend.findOne({ where: { id: id, '$mappedClients.uuid$': uuid }, include: ['mappedClients'] }).then(backend => { - if (backend && backend.mappedClients.length === 1) { - const externalId = backend.mappedClients[0].backend_x_client.externalId - const b = new ExternalBackends() - const instance = b.getInstance(backend.type) - instance.getFileList(backend.credentials, externalId).then(fileList => { - res.send({ success: true, data: { backendId: id, clientUUID: uuid, externalId: externalId, fileList: fileList } }) - }) - } else { - res.send({ success: false, error: 'CLIENT_NOT_FOUND', message: 'Couldn\'t find the client' }) - } - }) + const backend = await db.backend.findOne({ where: { id: id, '$mappedClients.uuid$': uuid }, include: ['mappedClients'] }) + if (backend && backend.mappedClients.length === 1) { + const externalId = backend.mappedClients[0].backend_x_client.externalId + const b = new ExternalBackends() + const instance = b.getInstance(backend.type) + const fileList = await instance.getFileList(backend.credentials, externalId) + res.send({ success: true, data: { backendId: id, clientUUID: uuid, externalId: externalId, fileList: fileList } }) + } else { + res.send({ success: false, error: 'CLIENT_NOT_FOUND', message: 'Couldn\'t find the client' }) + } }) // Returns the content of a file -noAuthRouter.get('/:id/:uuid/files/:filename', (req, res) => { +noAuthRouter.getAsync('/:id/:uuid/files/:filename', async (req, res) => { const id = req.params.id const uuid = req.params.uuid const filename = req.params.filename - db.backend.findOne({ where: { id: id, '$mappedClients.uuid$': uuid }, include: ['mappedClients'] }).then(backend => { - if (backend && backend.mappedClients.length === 1) { - const externalId = backend.mappedClients[0].backend_x_client.externalId - const b = new ExternalBackends() - const instance = b.getInstance(backend.type) - instance.getFile(backend.credentials, externalId, filename).then(file => { - file.decoded = Buffer.from(file.value, 'base64').toString('UTF-8') - res.send(file) - }) - } else { - res.send({ success: false, error: 'CLIENT_NOT_FOUND', message: 'Couldn\'t find the client' }) - } - }) + const backend = await db.backend.findOne({ where: { id: id, '$mappedClients.uuid$': uuid }, include: ['mappedClients'] }) + if (backend && backend.mappedClients.length === 1) { + const externalId = backend.mappedClients[0].backend_x_client.externalId + const b = new ExternalBackends() + const instance = b.getInstance(backend.type) + const file = await instance.getFile(backend.credentials, externalId, filename) + file.decoded = Buffer.from(file.value, 'base64').toString('UTF-8') + res.send(file) + } else { + res.send({ success: false, error: 'CLIENT_NOT_FOUND', message: 'Couldn\'t find the client' }) + } }) // POST requests @@ -347,24 +337,22 @@ noAuthRouter.get('/:id/:uuid/files/:filename', (req, res) => { * type: <BACKEND_TYPE> * credentials: <BACKEND_CREDENTIALS> * - * If the id is set, the backend in the db ist testet. - * Else the backend is postet in the request. + * If the id is set, the backend in the db is testet. + * Else the backend is posted in the request. */ -router.post('/:id/connection', (req, res) => { +router.postAsync('/:id/connection', async (req, res) => { const id = req.params.id - var getBackend = null - if (id !== '0') getBackend = db.backend.findOne({ where: { id: id } }) - else getBackend = new Promise(resolve => resolve(req.body)) + let backend = null + if (id !== '0') backend = await db.backend.findOne({ where: { id: id } }) + else backend = req.body - getBackend.then(backend => { - // Creating the backend instance and calling the specific checkConnection. - const b = new ExternalBackends() - const instance = b.getInstance(backend.type) - instance.checkConnection(backend.credentials).then(connection => { - res.status(200).send({ success: connection.success, error: connection.error }) - }) - }) + // Creating the backend instance and calling the specific checkConnection. + const b = new ExternalBackends() + const instance = b.getInstance(backend.type) + const response = await instance.checkConnection(backend.credentials) + if (response.error) return res.status(500).send(response) + else if (response) res.status(200).send() }) // PUT requests @@ -436,12 +424,11 @@ router.put('/:id/syncsettings', (req, res) => { * * Deletes the backend to the given id. */ -router.post('/delete', (req, res) => { +router.postAsync('/delete', async (req, res) => { const backendIds = req.body.id - db.backend.destroy({ where: { id: backendIds } }).then(function () { - res.status(200).send('success') - }) + await db.backend.destroy({ where: { id: backendIds } }) + res.status(200).send('success') }) module.exports.router = router diff --git a/server/api/registration.js b/server/api/registration.js index 2a26c4f..3eb36e0 100644 --- a/server/api/registration.js +++ b/server/api/registration.js @@ -114,7 +114,7 @@ noAuthRouter.postAsync('/add', async (req, res) => { const uuid = req.body.uuid const ip = req.body.ip var name = req.body.name - const parentId = req.body.id + const parentId = parseInt(req.body.id) const purpose = req.body.purpose let parentIds = [] @@ -139,24 +139,15 @@ noAuthRouter.postAsync('/add', async (req, res) => { } // Add the client to the backends. - var c = { title: name, uuid: uuid, network: { mac: mac, ip: ip } } + var c = { id: newClient.id, title: name, uuid: uuid, network: { mac: mac, ip: ip } } if (parentIds.length > 0) c.parents = parentIds - // if (parentId) c.parentId = parentId if (purpose) c.purpose = purpose const result = await backendHelper.addClient(c) if (feedback) res.send(result) - - for (let response of result) { - // If the object was created we need to make the objectid / external id mapping. - if (response.success) { - const backend = await db.backend.findOne({ where: { id: response.backendId }, include: ['mappedClients'] }) - backend.addMappedClients(newClient, { through: { externalId: response.id, externalType: response.type } }) - } - } - if (!feedback) res.send(`#!ipxe\nchain https://` + url + `/api/configloader/\${uuid}`) + else res.send(`#!ipxe\nchain https://` + url + `/api/configloader/\${uuid}`) }) -noAuthRouter.post('/:uuid/update', (req, res) => { +noAuthRouter.postAsync('/:uuid/update', async (req, res) => { const uuid = req.params.uuid const name = req.body.name const parentId = req.body.id @@ -174,85 +165,89 @@ noAuthRouter.post('/:uuid/update', (req, res) => { const cpuCores = req.body.cpu_cores // RAM - var ramSize = req.body.ram_size.split('\n') - var ramManufacturer = req.body.ram_manufacturer.split('\n') - var ramFormfactor = req.body.ram_formfactor.split('\n') - var ramType = req.body.ram_type.split('\n') - var ramIsEcc = req.body.ram_isecc.replace('Error Correction Type: ', '') - var ramModules = [] - // Build ram array - for (var ram in ramSize) { - if (ramSize[ram].replace('Size: ', '') !== 'No Module Installed') { - const size = ramSize[ram].replace('Size: ', '').split(' ') - var title = ramFormfactor[ram].replace('Form Factor: ', '') - if (ramIsEcc === 'Single-bit ECC') title += '-ECC' - - var ramModule = { - capacity: size[0], - unit: size[1], - manufacturer: ramManufacturer[ram].replace('Manufacturer: ', ''), - title: title, - type: ramType[ram].replace('Type: ', '') + if (req.body.ram_size) { + const ramSize = req.body.ram_size.split('\n') + const ramManufacturer = req.body.ram_manufacturer.split('\n') + const ramFormfactor = req.body.ram_formfactor.split('\n') + const ramType = req.body.ram_type.split('\n') + const ramIsEcc = req.body.ram_isecc.replace('Error Correction Type: ', '') + var ramModules = [] + + // Build ram array + for (let ram in ramSize) { + if (ramSize[ram].replace('Size: ', '') !== 'No Module Installed') { + const size = ramSize[ram].replace('Size: ', '').split(' ') + let title = ramFormfactor[ram].replace('Form Factor: ', '') + if (ramIsEcc === 'Single-bit ECC') title += '-ECC' + + const ramModule = { + capacity: size[0], + unit: size[1], + manufacturer: ramManufacturer[ram].replace('Manufacturer: ', ''), + title: title, + type: ramType[ram].replace('Type: ', '') + } + ramModules.push(ramModule) } - ramModules.push(ramModule) } } // SSD / HDD - var drivesRaw = req.body.drives.split('%OBJECT_SPLITTER%') - var drives = [] - for (var driveRaw in drivesRaw) { - if (drivesRaw[driveRaw].length > 0) { - var dRaw = drivesRaw[driveRaw].split('%ATTRIBUTE_SPLITTER%') - var drive = { - model: dRaw[0].trim().replace('Device Model: ', ''), - serial: dRaw[1].trim().replace('Serial Number: ', ''), - capacity: dRaw[2].trim().split(' ')[0], - unit: dRaw[2].trim().split(' ')[1], - type: dRaw[3].trim().replace('Rotation Rate: ', ''), - formfactor: dRaw[4].trim().replace('Form Factor: ', ''), - connection: dRaw[5].trim().replace('SATA Version is: ', '') + if (req.body.drives) { + const drivesRaw = req.body.drives.split('%OBJECT_SPLITTER%') + var drives = [] + for (let driveRaw in drivesRaw) { + if (drivesRaw[driveRaw].length > 0) { + const dRaw = drivesRaw[driveRaw].split('%ATTRIBUTE_SPLITTER%') + const drive = { + model: dRaw[0].trim().replace('Device Model: ', ''), + serial: dRaw[1].trim().replace('Serial Number: ', ''), + capacity: dRaw[2].trim().split(' ')[0], + unit: dRaw[2].trim().split(' ')[1], + type: dRaw[3].trim().replace('Rotation Rate: ', ''), + formfactor: dRaw[4].trim().replace('Form Factor: ', ''), + connection: dRaw[5].trim().replace('SATA Version is: ', '') + } + drives.push(drive) } - drives.push(drive) } } - db.client.findOne({ where: { uuid: uuid } }).then(client => { - client.update({ name: name }) - var c = { uuid: uuid, id: client.id } - if (name) c.title = name - if (parentId) c.parentId = parentId + const client = await db.client.findOne({ where: { uuid: uuid } }) + if (!client) return res.status(404).send({ error: 'CLIENT_NOT_FOUND', message: 'There is no client matching the provided uuid.' }) - // System data. Sometime just string with whitespaces only. - c.system = {} - if (/\S/.test(sysManufacturer)) c.system.manufacturer = sysManufacturer - else c.system.manufacturer = 'Not set' + client.update({ name: name }) + var c = { uuid: uuid, id: client.id } + if (name) c.title = name + if (parentId) c.parentId = parentId - if (/\S/.test(sysModel)) c.system.model = sysModel - else c.system.model = 'Not set' + // System data. Sometime just string with whitespaces only. + c.system = {} + if (/\S/.test(sysManufacturer)) c.system.manufacturer = sysManufacturer + else c.system.manufacturer = 'Not set' - if (/\S/.test(sysSerial)) c.system.serialnumber = sysSerial - else c.system.serialnumber = 'Not set' + if (/\S/.test(sysModel)) c.system.model = sysModel + else c.system.model = 'Not set' - // TODO: MULTI GPU's ?! - c.cpu = { model: cpuModel, manufacturer: cpuManufacturer, type: cpuType, frequency: cpuFrequency, cores: cpuCores } - c.ram = ramModules - c.drives = drives + if (/\S/.test(sysSerial)) c.system.serialnumber = sysSerial + else c.system.serialnumber = 'Not set' - backendHelper.updateClient(c).then(result => { - res.send(result) - }) - }) + // TODO: MULTI GPU's ?! + c.cpu = { model: cpuModel, manufacturer: cpuManufacturer, type: cpuType, frequency: cpuFrequency, cores: cpuCores } + if (ramModules) c.ram = ramModules + if (drives) c.drives = drives + + const result = await backendHelper.updateClient(c) + res.send(result) }) /* * Mehtod for uploading the tpm key and stuff. */ -noAuthRouter.put('/:uuid/files', (req, res) => { - db.client.findOne({ where: { uuid: req.params.uuid } }).then(client => { - backendHelper.uploadFiles(client.id, req.files) - res.send() - }) +noAuthRouter.putAsync('/:uuid/files', async (req, res) => { + const client = await db.client.findOne({ where: { uuid: req.params.uuid } }) + const result = await backendHelper.uploadFiles(client.id, req.files) + res.send(result) }) /* diff --git a/server/lib/external-backends/backendhelper.js b/server/lib/external-backends/backendhelper.js index ae1af3d..bb95844 100644 --- a/server/lib/external-backends/backendhelper.js +++ b/server/lib/external-backends/backendhelper.js @@ -15,22 +15,11 @@ module.exports = { const instance = ba.getInstance(backend.type) var tmpClient = JSON.parse(JSON.stringify(client)) - // If the client id is set we need to get the external id. - if (client.id) { - var exid = backend.mappedClients.find(y => y.id === parseInt(client.id)) - if (exid) tmpClient.id = exid.backend_x_client.externalId - } else { - // If we don't already have the client id, we need to check if there is already a client with the provided uuid in the backend. - var cl = await instance.getClient(backend.credentials, { uuid: tmpClient.uuid }) - if (cl.succes) { - tmpClient.id = cl.data - } - } - + // Add client has no support for update anymore.. use update method.. maybe call conflict here // Convert the parent group id to the external backend parentId. // if (client.parentId) { if (client.parents) { - var elements = backend.mappedGroups.filter(x => client.parents.includes(x.id)) + const elements = backend.mappedGroups.filter(x => client.parents.includes(x.id)) if (elements.length > 1) { // Conflict occured! const conflict = await db.conflict.create({ description: 'Multiple parents found' }) @@ -43,13 +32,15 @@ module.exports = { conflict.createObject({ objectType: 'GROUP', objectId: element.id }) } } else if (elements.length === 1) tmpClient['parentId'] = elements[0].backend_x_group.externalId - - // var element = backend.mappedGroups.find(x => x.id === parseInt(client.parentId)) - // if (element) tmpClient['parentId'] = element.backend_x_group.externalId } - var addClient = await instance.addClient(backend.credentials, tmpClient) + let addClient = await instance.addClient(backend.credentials, tmpClient) addClient.backendId = backend.id + if (addClient.succes) { + // If the object was created we need to make the objectid / external id mapping. + const clientDb = await db.client.findOne({ where: { id: client.id } }) + backend.addMappedClients(clientDb, { through: { externalId: addClient.id, externalType: addClient.type } }) + } result.push(addClient) } return result @@ -57,11 +48,11 @@ module.exports = { updateClient: async function (client) { // Get all backends and call addClient for each instance. - var backends = await db.backend.findAll({ include: ['mappedGroups', 'mappedClients'] }) - var result = [] + const backends = await db.backend.findAll({ include: ['mappedGroups', 'mappedClients'] }) + let result = [] - for (var b in backends) { - var backend = backends[b] + for (let b in backends) { + const backend = backends[b] const ba = new ExternalBackends() const instance = ba.getInstance(backend.type) var tmpClient = JSON.parse(JSON.stringify(client)) @@ -76,7 +67,7 @@ module.exports = { if (element) tmpClient['parentId'] = element.backend_x_group.externalId } - var updateClient = await instance.updateClient(backend.credentials, tmpClient) + let updateClient = await instance.updateClient(backend.credentials, tmpClient) updateClient.backendId = backend.id result.push(updateClient) } @@ -100,15 +91,18 @@ module.exports = { }, uploadFiles: async function (clientId, files) { - var backends = await db.backend.findAll({ include: ['mappedClients'] }) - for (var b in backends) { - var backend = backends[b] + const backends = await db.backend.findAll({ include: ['mappedClients'] }) + let results = [] + for (let b in backends) { + const backend = backends[b] const ba = new ExternalBackends() const instance = ba.getInstance(backend.type) - var exid = backend.mappedClients.find(y => y.id === parseInt(clientId)) + let exid = backend.mappedClients.find(y => y.id === parseInt(clientId)) if (exid) exid = exid.backend_x_client.externalId - instance.uploadFiles(backend.credentials, exid, files) + results.push(await instance.uploadFiles(backend.credentials, exid, files)) } + return results } + } diff --git a/server/lib/external-backends/backends/idoit-backend.js b/server/lib/external-backends/backends/idoit-backend.js index d3d992f..9325ad5 100644 --- a/server/lib/external-backends/backends/idoit-backend.js +++ b/server/lib/external-backends/backends/idoit-backend.js @@ -4,9 +4,6 @@ const ExternalBackends = require(path.join(__appdir, 'lib', 'external-backends') var axios = require('axios') class IdoitBackend extends ExternalBackends { - // ############################################################################ - // ######################## needed functions ################################# - /* * Returns the credential structure / fields, defined in the backends. */ @@ -31,33 +28,30 @@ class IdoitBackend extends ExternalBackends { * Checks the connection of a given backend. * idoIT: Checks if we can get a valid session id. If so the connection must be successfull. * - * return: { success: <boolean>, status: '<STATUS_CODE_IF_ERROR>', error: '<ERROR_MESSAGE>' } + * return: true / { error: <ERROR>, message: <MESSAGE> } */ - checkConnection (credentials) { - var c = this.mapCredentials(credentials) - return this.getSession(c) + async checkConnection (credentials) { + const c = this.mapCredentials(credentials) + const body = this.getBody('idoit.version', { 'apikey': c.apikey }, 'version_check') + const headers = await this.getHeaders(c) + if (headers.error) return headers + + // Axios request + const result = await this.axiosRequest(c.url, [body], headers) + if (result.error) return { error: 'IDOIT_ERROR', message: result.errno } + return true } // Return the list of object types created in iDoIT. async getObjectTypes (credentials) { - var c = this.mapCredentials(credentials) - var login = await this.getSession(c) - var sid = login.data.result['session-id'] - - // Headers - var headers = { - 'X-RPC-Auth-Session': sid - } - - // Params - var params = { - 'apikey': c.apikey, - 'language': 'en' - } + const c = this.mapCredentials(credentials) + const body = this.getBody('cmdb.object_types', { 'apikey': c.apikey }, 'object_types') + const headers = await this.getHeaders(c) + if (headers.error) return headers var result = {} - result.types = await this.axiosRequest(c.url, 'cmdb.object_types', params, headers) - result.types = result.types.data.result + result.types = await this.axiosRequest(c.url, [body], headers) + result.types = result.types[0].result var types = [] result.types.forEach(type => { @@ -72,235 +66,90 @@ class IdoitBackend extends ExternalBackends { } /* - * Gets all objects and searches for the ip. Because idoit cannot search for ip or mac. + * Gets all objects and searches for the uuid to get the requested client. * */ async getClient (credentials, client) { - var c = this.mapCredentials(credentials) - var login = await this.getSession(c) - var sid = login.data.result['session-id'] - // var uuid = client.uuid - - // Headers - var headers = { - 'X-RPC-Auth-Session': sid, - 'Content-Type': 'application/json' - } + const c = this.mapCredentials(credentials) - // Params to get all clients. - var params = { + const paramsObjects = { 'apikey': c.apikey, - 'language': 'en', 'filter': { 'type': 10 - } + }, + 'categories': ['C__CATG__MODEL'] } + const body = this.getBody('cmdb.objects', paramsObjects, 'objects') + const headers = await this.getHeaders(c) + if (headers.error) return headers // Get all client objects. - var clients = await this.axiosRequest(c.url, 'cmdb.objects', params, headers) - clients = clients.data.result - - var bodies = [] - - clients.forEach(client => { - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.read', - 'params': { - 'objID': client.id, - 'apikey': c.apikey, - 'language': 'en', - 'category': 'C__CATG__MODEL' - }, - 'id': client.id - }) - }) - - var config = { - timeout: 180000, - headers: { - 'X-RPC-Auth-Session': sid, - 'Content-Type': 'application/json' - } - } - var requestClient = await axios.post(c.url, bodies, config) - requestClient = requestClient.data.filter(x => x.result.length >= 1 && x.result[0].productid === client.uuid) + const clients = await this.axiosRequest(c.url, [body], headers) - return requestClient.length >= 1 ? { succes: true, data: requestClient[0].result[0].objID } : { success: false, error: 'NO_CLIENT_FOUND', msg: 'There is no client matching with the provided uuid.' } + let result = clients[0].result.filter(x => x.categories.C__CATG__MODEL.length > 0 && x.categories.C__CATG__MODEL[0].productid === client.uuid) + return result.length >= 1 ? result.map(x => x.id) : { error: 'NO_CLIENT_FOUND', msg: 'There is no client matching with the provided uuid.' } } async getObjects (credentials) { - var c = this.mapCredentials(credentials) - var login = await this.getSession(c) - var sid = login.data.result['session-id'] - - // Headers - var headers = { - 'X-RPC-Auth-Session': sid - } - - // Params - var params = { - 'apikey': c.apikey, - 'language': 'en' - } + const c = this.mapCredentials(credentials) + const body = this.getBody('cmdb.objects', { 'apikey': c.apikey }, 'objects') + const headers = await this.getHeaders(c) + if (headers.error) return headers - var result = {} - result.objects = await this.axiosRequest(c.url, 'cmdb.objects', params, headers) - result.objects = result.objects.data.result - - return result + const objects = await this.axiosRequest(c.url, [body], headers) + return objects[0] } async getObject (credentials, oid) { - var c = this.mapCredentials(credentials) - var login = await this.getSession(c) - var sid = login.data.result['session-id'] - - // Headers - var headers = { - 'X-RPC-Auth-Session': sid - } - - // Params - var params = { - 'id': oid, - 'apikey': c.apikey, - 'language': 'en' - } + const c = this.mapCredentials(credentials) + const body = this.getBody('cmdb.object.read', { 'apikey': c.apikey, 'id': oid }, 'object_read') + const bodyChilds = this.getBody('cmdb.location_tree', { 'apikey': c.apikey, 'id': oid }, 'object_location_tree') + const headers = await this.getHeaders(c) + if (headers.error) return headers var result = {} - result.object = await this.axiosRequest(c.url, 'cmdb.object.read', params, headers) - result.childs = await this.axiosRequest(c.url, 'cmdb.location_tree', params, headers) - result.object = result.object.data.result - result.childs = result.childs.data.result + result.object = await this.axiosRequest(c.url, [body], headers) + result.childs = await this.axiosRequest(c.url, [bodyChilds], headers) + result.object = result.object[0].result + result.childs = result.childs[0].result return result } async deleteObjects (credentials, objectIds) { - var c = this.mapCredentials(credentials) - var login = await this.getSession(c) - var sid = login.data.result['session-id'] - - var config = { - timeout: 180000, - headers: { - 'X-RPC-Auth-Session': sid, - 'Content-Type': 'application/json' - } - } - - var bodies = [] + const c = this.mapCredentials(credentials) + const headers = await this.getHeaders(c) + if (headers.error) return headers + let bodies = [] objectIds.forEach(oid => { - // Body - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.object.delete', - 'params': { - 'id': oid, - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': oid - }) + bodies.push(this.getBody('cmdb.object.quickpurge', { 'id': oid, 'apikey': c.apikey }, oid)) }) - var requestDelete = await axios.post(c.url, bodies, config) - - return { success: requestDelete.success, data: requestDelete.data } + let deleteRequest = await this.axiosRequest(c.url, bodies, headers) + return deleteRequest } // Function to use the same session for multiple requests async getDataTree (credentials, objects) { - var c = this.mapCredentials(credentials) - - // LOGIN - // Open and get a session - const body = { - 'version': '2.0', - 'method': 'idoit.login', - 'params': { - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': 1 - } - - // Headers - var headers = {} - // Optional credentials - if (c.login) { - headers['X-RPC-Auth-Username'] = c.username - headers['X-RPC-Auth-Password'] = c.password - } - - var config = { - timeout: 180000, - headers: headers - } - - // Make a login request and see if we are authenticated. - var log = await axios.post(c.url, body, config) - log = log.data.result - var sid = log['session-id'] - - // Headers - config.headers = { 'X-RPC-Auth-Session': sid, 'Content-Type': 'application/json' } - body.method = 'cmdb.location_tree' - - // Go through the objects and get all the childs. - var promises = [] - - var counter = 0 - var index = 0 - var gids = {} + const c = this.mapCredentials(credentials) + const headers = await this.getHeaders(c) + if (headers.error) return headers + let bodies = [] + let gids = {} // Prepare all the batch request bodies. - var e - for (e in objects) { - // Pack 400 requests in one batch request to reduce api calls. - if (counter >= 400) { - counter = 0 - index++ - } - if (counter === 0) promises[index] = [] - counter++ - - var element = objects[e] - const bod = { - 'version': '2.0', - 'method': 'cmdb.location_tree', - 'params': { - 'id': element.eid, - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': element.eid - } - promises[index].push(bod) + for (let element of objects) { + bodies.push(this.getBody('cmdb.location_tree', { 'id': element.eid, 'apikey': c.apikey }, element.eid)) gids[element.eid] = element.gid } // Send all the batch request and post proccess the result into one array. - var result = [] - var p - var counter2 = 1 - for (p in promises) { - // TODO: Remove - // Counter for getting an overview, how far the requests are. - console.log(counter2 + '/' + promises.length + ' requests send') - counter2++ - - // Send the request. - var requestResult = await axios.post(c.url, promises[p], config) - const args = requestResult.data - - // Post process the data. - var a - for (a in args) { - result.push({ gid: gids[args[a].id], childs: args[a].result }) - } + let requestResult = await this.axiosRequest(c.url, bodies, headers) + + // Post process the data. + let result = [] + for (let res of requestResult) { + result.push({ gid: gids[res.id], childs: res.result }) } return result } @@ -309,157 +158,53 @@ class IdoitBackend extends ExternalBackends { * Adds the client to the backend. * * credentials: <BACKEND_CREDENTIALS> - * The client parameters are all optional. If the client has an id the object is not created but the categories of the object. + * The client parameters are all optional. * client: { - * id: <CLIENT_ID>, title: <CLIENT_TITLE>, parentId: <PARENT_ID>, + * title: <CLIENT_TITLE>, parentId: <PARENT_ID>, * network: { mac: <MAC_ADDRESS>, ip: <IP_ADDRESS> } * } */ async addClient (credentials, client) { - var c = this.mapCredentials(credentials) - var login = await this.getSession(c) - var sid = login.data.result['session-id'] - - var config = { - timeout: 180000, - headers: { - 'X-RPC-Auth-Session': sid, - 'Content-Type': 'application/json' - } - } - var bodies = [] - var clientid - if (!client.id) { - // Create the object in idoIT. - var params = { - 'type': 10, - 'title': client.title, - 'apikey': c.apikey, - 'language': 'en' - } - // 1 = Production - // 2 = Test - // 3 = Quality Assurance - // 5 = PVS - // 7 = Pool PC - // 8 = Mitarbeiter Arbeitsplatz - if (client.purpose === 'Pool PC') params.purpose = 7 - - var requestCreate = await this.axiosRequest(c.url, 'cmdb.object.create', params, config.headers) - - clientid = requestCreate.data.result.id - } else { - clientid = client.id - - // Update the client title - var bodyGeneral = { - 'version': '2.0', - 'method': 'cmdb.object.update', - 'params': { - 'id': clientid, - 'title': client.title, - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': 'update_title' - } - if (client.purpose === 'Pool PC') bodyGeneral.params.purpose = 7 - - bodies.push(bodyGeneral) - } + const c = this.mapCredentials(credentials) + const headers = await this.getHeaders(c) + if (headers.error) return headers - if (client.uuid) { - // Update the productid to the uuid. - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.update', - 'params': { - 'objID': clientid, - 'category': 'C__CATG__MODEL', - 'data': { - 'productid': client.uuid - }, - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': 'update_uuid' - }) + let params = { + 'apikey': c.apikey, + 'title': client.title, + 'purpose': client.purpose === 'Pool PC' ? 7 : undefined, + 'categories': {} } - if (client.network) { - // Update the object. MAC-Address - if (client.network.mac) { - // First read if there are current entries. - // Delete the previous entries. - // Finally create the new entry. - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.create', - 'params': { - 'objID': clientid, - 'category': 'C__CATG__NETWORK_PORT', - 'data': { - 'category_id': 1, - 'mac': client.network.mac - }, - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': 'create_mac' - }) - } + if (client.type === 'CLIENT') params['type'] = 10 + else if (client.type === 'SERVER') { + params['type'] = 5 - // Update the object. IP-Address - if (client.network.ip) { - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.create', - 'params': { - 'objID': clientid, - 'category': 'C__CATG__IP', - 'data': { - 'category_id': 1, - 'ipv4_address': client.network.ip - }, - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': 'create_ip' - }) - } + if (client.location) params.categories.C__CATG__LOCATION = { 'data': { 'option': client.location.assembly, 'insertion': client.location.insertion, 'pos': 32 } } + // TODO: Assign to rack with the given rackid } - // Update the object. Location - if (client.parentId) { - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.update', - 'params': { - 'objID': clientid, - 'category': 'C__CATG__LOCATION', - 'data': { - 'parent': client.parentId - }, - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': 'update_parent' - }) - } - - var requestUpdate = await axios.post(c.url, bodies, config) - - var result = { - success: true, - id: clientid, - type: 10, - create: requestCreate ? requestCreate.success : false, - update: requestUpdate ? requestUpdate.success : false, - createData: requestCreate ? requestCreate.data : false, - updateData: requestUpdate ? requestUpdate.data : false - } - - return result + // Add categories to the object + if (client.uuid) params.categories.C__CATG__MODEL = { 'data': { 'productid': client.uuid } } + if (client.network) { + // TOOD: + // First read if there are current entries. + // Delete the previous entries. + // Finally create the new entry. + if (client.network.mac) params.categories.C__CATG__NETWORK_PORT = { 'data': { 'category_id': 1, 'mac': client.network.mac } } + if (client.network.ip) params.categories.C__CATG__IP = { 'data': { 'category_id': 1, 'ipv4_address': client.network.ip } } + } + if (client.parentId) params.categories.C__CATG__LOCATION = { 'data': { 'parent': client.parentId } } + + // Send the create request. + const body = this.getBody('cmdb.object.create', params, 'client_create') + const requestCreate = await this.axiosRequest(c.url, [body], headers) + + // Purpose for Clients: + // 1 = Production | 5 = PVS + // 2 = Test | 7 = Pool PC + // 3 = Quality Assurance | 8 = Mitarbeiter Arbeitsplatz + return { succes: true, id: requestCreate[0].result.id, type: params.type, message: requestCreate[0].result.message } } /* @@ -476,120 +221,84 @@ class IdoitBackend extends ExternalBackends { * } */ async updateClient (credentials, client) { - var c = this.mapCredentials(credentials) - var login = await this.getSession(c) - var sid = login.data.result['session-id'] - - var config = { - timeout: 180000, - headers: { - 'X-RPC-Auth-Session': sid, - 'Content-Type': 'application/json' - } - } + const c = this.mapCredentials(credentials) + const headers = await this.getHeaders(c) + if (headers.error) return headers - var clientid = client.id - var bodies = [] - var counter - - if (client.title) { - // Update title of the object - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.object.update', - 'params': { - 'id': clientid, - 'title': client.title, - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': 'update_title' - }) - } + let bodies = [] + + // Update title of the object + if (client.title) bodies.push(this.getBody('cmdb.object.update', { 'id': client.id, 'title': client.title, 'apikey': c.apikey }, 'update_title')) + // 'object' should be 'objID' but there is a fucking bug in the idoit api. Soo let's add both parameters because else it will break when they fix it. + // Update the productid to the uuid. if (client.uuid) { - // Update the productid to the uuid. - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.update', - 'params': { - 'objID': clientid, - 'category': 'C__CATG__MODEL', - 'data': { - 'productid': client.uuid - }, - 'apikey': c.apikey, - 'language': 'en' + let params = { + 'object': client.id, + 'objID': client.id, + 'category': 'C__CATG__MODEL', + 'data': { + 'productid': client.uuid }, - 'id': 'update_uuid' - }) + 'apikey': c.apikey + } + bodies.push(this.getBody('cmdb.category.save', params, 'update_uuid')) } // Update the object. Location if (client.parentId) { - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.update', - 'params': { - 'objID': clientid, - 'category': 'C__CATG__LOCATION', - 'data': { - 'parent': client.parentId - }, - 'apikey': c.apikey, - 'language': 'en' + let params = { + 'object': client.id, + 'objID': client.id, + 'category': 'C__CATG__LOCATION', + 'data': { + 'parent': client.parentId }, - 'id': 'update_parent' - }) + 'apikey': c.apikey + } + bodies.push(this.getBody('cmdb.category.save', params, 'update_parent')) } + // Update the object. Model data. if (client.system) { - // Update the object. - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.update', - 'params': { - 'objID': clientid, - 'category': 'C__CATG__MODEL', - 'data': { - 'manufacturer': client.system.manufacturer, - 'title': client.system.model, - 'serial': client.system.serialnumber - }, - 'apikey': c.apikey, - 'language': 'en' + let params = { + 'object': client.id, + 'objID': client.id, + 'category': 'C__CATG__MODEL', + 'data': { + 'manufacturer': client.system.manufacturer, + 'title': client.system.model, + 'serial': client.system.serialnumber }, - 'id': 'update_model' - }) + 'apikey': c.apikey + } + bodies.push(this.getBody('cmdb.category.save', params, 'update_model')) } + // Update the object. CPU data. + // TODO: Delete cpu if exists? if (client.cpu) { - // TODO: Delete cpu if exists? - // Update the object. - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.create', - 'params': { - 'objID': clientid, - 'category': 'C__CATG__CPU', - 'data': { - 'category_id': 1, - 'manufacturer': client.cpu.manufacturer, - 'title': client.cpu.model, - 'type': client.cpu.type, - 'frequency': client.cpu.frequency, - 'frequency_unit': 3, - 'cores': client.cpu.cores - }, - 'apikey': c.apikey, - 'language': 'en' + let params = { + 'object': client.id, + 'objID': client.id, + 'category': 'C__CATG__CPU', + 'data': { + 'category_id': 1, + 'manufacturer': client.cpu.manufacturer, + 'title': client.cpu.model, + 'type': client.cpu.type, + 'frequency': client.cpu.frequency, + 'frequency_unit': 3, + 'cores': client.cpu.cores }, - 'id': 'update_cpu' - }) + 'apikey': c.apikey + } + bodies.push(this.getBody('cmdb.category.save', params, 'update_cpu')) } + // Update the object. Ram data. if (client.ram) { - counter = 1 + let counter = 1 for (var memory in client.ram) { var mem = client.ram[memory] var ramId = 'create_memory_' + counter @@ -597,31 +306,27 @@ class IdoitBackend extends ExternalBackends { // 2 = MB // 3 = GB - // Update the object. - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.create', - 'params': { - 'objID': clientid, - 'category': 'C__CATG__MEMORY', - 'data': { - 'title': mem.title, - 'manufacturer': mem.manufacturer, - 'type': mem.type, - 'capacity': mem.capacity, - 'unit': 3 - }, - 'apikey': c.apikey, - 'language': 'en' + let params = { + 'object': client.id, + 'objID': client.id, + 'category': 'C__CATG__MEMORY', + 'data': { + 'title': mem.title, + 'manufacturer': mem.manufacturer, + 'type': mem.type, + 'capacity': mem.capacity, + 'unit': 3 }, - 'id': ramId - }) + 'apikey': c.apikey + } counter++ + bodies.push(this.getBody('cmdb.category.save', params, ramId)) } } + // Update the object. Drive data. if (client.drives) { - counter = 1 + let counter = 1 for (var drive in client.drives) { var d = client.drives[drive] var driveId = 'create_drive_' + counter @@ -634,198 +339,113 @@ class IdoitBackend extends ExternalBackends { else if (d.unit === 'KB') unit = 1 else if (d.unit === 'B') unit = 0 - // Update the object. - bodies.push({ - 'version': '2.0', - 'method': 'cmdb.category.create', - 'params': { - 'objID': clientid, - 'category': 'C__CATG__STORAGE_DEVICE', - 'data': { - 'title': d.model, - 'type': d.type, - // 'manufacturer': , - // 'model': , - 'capacity': d.capacity, - 'unit': unit, - 'serial': d.serial, - 'connected': d.connection - }, - 'apikey': c.apikey, - 'language': 'en' + let params = { + 'object': client.id, + 'objID': client.id, + 'category': 'C__CATG__STORAGE_DEVICE', + 'data': { + 'title': d.model, + 'type': d.type, + // 'manufacturer': , + // 'model': , + 'capacity': d.capacity, + 'unit': unit, + 'serial': d.serial, + 'connected': d.connection }, - 'id': driveId - }) + 'apikey': c.apikey + } + bodies.push(this.getBody('cmdb.category.save', params, driveId)) } } - try { - var requestUpdate = await axios.post(c.url, bodies, config) - } catch (error) { - console.log(error) - } + + const requestUpdate = await this.axiosRequest(c.url, bodies, headers) // 10 is the idoit object id for clients. var result = { success: true, - id: clientid, + id: client.id, type: 10, - update: requestUpdate ? requestUpdate.success : false, - updateData: requestUpdate ? requestUpdate.data : false + response: requestUpdate } return result } async getFileList (credentials, externalId) { - var c = this.mapCredentials(credentials) - var login = await this.getSession(c) - var sid = login.data.result['session-id'] - - var config = { - timeout: 180000, - headers: { - 'X-RPC-Auth-Session': sid, - 'Content-Type': 'application/json' - } - } - var body = { - 'version': '2.0', - 'method': 'cmdb.category.read', - 'params': { - 'objID': externalId, - 'category': 'C__CATG__FILE', - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': 1 - } - let result = await axios.post(c.url, body, config) - return result.data.result + const c = this.mapCredentials(credentials) + const body = this.getBody('cmdb.category.read', { 'objID': externalId, 'category': 'C__CATG__FILE', apikey: c.apikey }, 'filelist') + const headers = await this.getHeaders(c) + if (headers.error) return headers + + const result = await this.axiosRequest(c.url, [body], headers) + return result[0].result } async getFile (credentials, externalId, filename) { - var c = this.mapCredentials(credentials) - var login = await this.getSession(c) - var sid = login.data.result['session-id'] - - var config = { - timeout: 180000, - headers: { - 'X-RPC-Auth-Session': sid, - 'Content-Type': 'application/json' - } - } + const c = this.mapCredentials(credentials) + const body = this.getBody('cmdb.category.read', { 'objID': externalId, 'category': 'C__CATG__FILE', apikey: c.apikey }, 'filelist') + const headers = await this.getHeaders(c) + if (headers.error) return headers - var body = { - 'version': '2.0', - 'method': 'cmdb.category.read', - 'params': { - 'objID': externalId, - 'category': 'C__CATG__FILE', - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': 1 - } - let files = await axios.post(c.url, body, config) - let fileObjId = files.data.result.find(x => x.file.title === filename).file.id + const files = await this.axiosRequest(c.url, [body], headers) + let fileObjId = files[0].result.find(x => x.file.title === filename).file.id - var body2 = { - 'version': '2.0', - 'method': 'cmdb.category.read', - 'params': { - 'objID': fileObjId, - 'category': 'C__CMDB__SUBCAT__FILE_VERSIONS', - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': 1 - } - let result = await axios.post(c.url, body2, config) - result = result.data.result[0] + const body2 = this.getBody('cmdb.category.read', { 'objID': fileObjId, 'category': 'C__CMDB__SUBCAT__FILE_VERSIONS', apikey: c.apikey }, 'file') + let result = await this.axiosRequest(c.url, [body2], headers) + result = result[0].result[0] return { filename: result.file_title, value: result.file_content.value, md5: result.md5_hash } } async uploadFiles (credentials, externalId, files) { - var c = this.mapCredentials(credentials) - var login = await this.getSession(c) - var sid = login.data.result['session-id'] - - var config = { - timeout: 180000, - headers: { - 'X-RPC-Auth-Session': sid, - 'Content-Type': 'application/json' - } - } - var result = [] - for (var key in files) { - var body = { - 'version': '2.0', - 'method': 'cmdb.object.create', - 'params': { - 'type': 29, - 'title': files[key].name, - 'apikey': c.apikey, - 'language': 'en' - }, - 'id': key - } - var fileObject = await axios.post(c.url, body, config) - result.push(fileObject) + const c = this.mapCredentials(credentials) + const headers = await this.getHeaders(c) + if (headers.error) return headers + let result = [] + for (var key in files) { + const filename = files[key].name /* eslint-disable */ - var buffer = new Buffer.from(files[key].data) + const buffer = new Buffer.from(files[key].data) /* eslint-enable */ - var filename = files[key].name + // Create the fileObject where the file gets uplaoded to. + const body = this.getBody('cmdb.object.create', { 'type': 29, 'title': files[key].name, 'apikey': c.apikey }, 'createFileObject_' + key) + const fileObject = await this.axiosRequest(c.url, [body], headers) // Upload file to fileobject. - body = { - 'version': '2.0', - 'method': 'cmdb.category.create', - 'params': { - 'objID': fileObject.data.result.id, - 'data': { - 'file_content': buffer.toString('base64'), - 'file_physical': filename, - 'file_title': filename, - 'version_description': key - }, - 'category': 'C__CMDB__SUBCAT__FILE_VERSIONS', - 'apikey': c.apikey, - 'language': 'en' + const paramsUploadFile = { + 'object': fileObject[0].result.id, // <-- workaround for the idoit api bug (wrong mapping of objID) + 'objID': fileObject[0].result.id, + 'data': { + 'file_content': buffer.toString('base64'), + 'file_physical': filename, + 'file_title': filename, + 'version_description': key }, - 'id': key + 'category': 'C__CMDB__SUBCAT__FILE_VERSIONS', + 'apikey': c.apikey } - var fileupload = await axios.post(c.url, body, config) - result.push(fileupload) - - // Combine fileObject with object. - body = { - 'version': '2.0', - 'method': 'cmdb.category.create', - 'params': { - 'objID': externalId, - 'data': { - 'file': fileObject.data.result.id - }, - 'category': 'C__CATG__FILE', - 'apikey': c.apikey, - 'language': 'en' + const bodyUploadFile = this.getBody('cmdb.category.save', paramsUploadFile, 'uploadFile_' + key) + const uploadFile = await this.axiosRequest(c.url, [bodyUploadFile], headers) + + // Connect the file with the client (object). + const paramsConnectFile = { + 'object': externalId, + 'objID': externalId, + 'data': { + 'file': fileObject[0].result.id }, - 'id': 4 - } - var concat = await axios.post(c.url, body, config) - result.push(concat) - } + 'category': 'C__CATG__FILE', + 'apikey': c.apikey } + const bodyConnect = this.getBody('cmdb.category.save', paramsConnectFile, 'uploadFile_' + key) + const connectFile = await this.axiosRequest(c.url, [bodyConnect], headers) - return { result: result } + result.push({ createObject: fileObject, uploadFile: uploadFile, connectObjectFile: connectFile }) + } + return result } - // ############################################################################ - // ####################### helper/optional functions ######################### - // Helper function, to map the array of credential objects into a single js object. mapCredentials (credentials) { const c = JSON.parse(credentials) @@ -843,61 +463,86 @@ class IdoitBackend extends ExternalBackends { return mapped } - // Username and password are optional. - async getSession (credentials) { - // Headers - var headers = {} - // Optional credentials - if (credentials.login) { - headers['X-RPC-Auth-Username'] = credentials.username - headers['X-RPC-Auth-Password'] = credentials.password - } - - // Params - var params = { - 'apikey': credentials.apikey, - 'language': 'en' + // Method for making the axios request and error handling. + async axiosRequest (url, bodies, headers, batchRequestSize = 400) { + let config = { timeout: 180000, headers: headers } + + // Split batchrequest in multiple request + let batchRequests = [] + // For spliceing the array a while loop seems to be the most efficient: + // https://ourcodeworld.com/articles/read/278/how-to-split-an-array-into-chunks-of-the-same-size-easily-in-javascript + while (bodies.length) { + batchRequests = [...batchRequests, bodies.splice(0, batchRequestSize)] + } + // Make all batch request and return the result of all. + let results = [] + let requestCounter = 1 + + for (let i = 0; i < batchRequests.length; i++) { + // Axios error handling + try { + console.log(requestCounter + '/' + batchRequests.length + ' requests send') + requestCounter++ + const responses = await axios.post(url, batchRequests[i], config) + if (Array.isArray(responses.data)) results = [...results, ...responses.data] + else results = [...results, responses.data] + } catch (error) { + let errorResponse = { error: true } + if (error.response) { + // The request was made and the server responded with a status code + // that falls out of the range of 2xx + errorResponse['data'] = error.response.data + errorResponse['status'] = error.response.status + errorResponse['headers'] = error.response.headers + } else if (error.request) { + // The request was made but no response was received + // `error.request` is an instance of XMLHttpRequest in the browser and an instance of + // http.ClientRequest in node.js + errorResponse['errno'] = error.errno + } else { + // Something happened in setting up the request that triggered an Error + errorResponse['message'] = error.message + } + + return errorResponse + } } - - // Make a login request and see if we are authenticated. - return this.axiosRequest(credentials.url, 'idoit.login', params, headers) + return results } - // Helper function to make the axios http/https requests to reduced copy pasta code in this backend. Including the error handling. - async axiosRequest (url, method, params, headers) { - const body = { + // Body wrapper for the requests to remove duplicated code. + getBody (method, params, id) { + return { 'version': '2.0', 'method': method, - 'params': params, - 'id': 1 + 'params': { + ...params, + 'language': 'en' + }, + 'id': id } + } - var config = { - timeout: 180000, - headers: headers - } - config.headers['Content-Type'] = 'application/json' - var response = await axios.post(url, body, config) - .then(response => { - return response - }) - .catch(error => { - console.log(error) - return error.response ? error.response : { status: 900, statusText: 'Request failed timeout' } - }) - // Axios error handling - if (response.status !== 200) { - return { success: false, error: response.status, msg: response.statusText } - } - // iDoIT error handling. - if (response.data.result) { - return { success: true, data: response.data } - } else if (response.data.error) { - console.log(response.data.error) - return { success: false, error: response.data.error.message, msg: response.data.error.data.error } - } else { - return { success: false, error: 'UNNOWN_ERROR' } + // Returns the header. Sets the session id if needed. + async getHeaders (credentials = {}) { + let headers = { 'Content-Type': 'application/json' } + + // Get a session id for the header + if (credentials.login && credentials.username && credentials.password) { + const header = { + ...headers, + 'X-RPC-Auth-Username': credentials.username, + 'X-RPC-Auth-Password': credentials.password + } + const sessionRequest = await this.axiosRequest(credentials.url, [this.getBody('idoit.login', { 'apikey': credentials.apikey, 'language': 'en' }, 'login')], header) + // Axios errors + if (sessionRequest.error) return sessionRequest + // Idoit error + if (sessionRequest[0].error) return { error: 'IDOIT_ERROR', message: sessionRequest[0].error.message } + headers = { ...headers, 'X-RPC-Auth-Session': sessionRequest[0].result['session-id'] } } + + return headers } } diff --git a/server/lib/external-backends/backends/infoblox-backend.js b/server/lib/external-backends/backends/infoblox-backend.js index 9d070ac..2b2c6d1 100644 --- a/server/lib/external-backends/backends/infoblox-backend.js +++ b/server/lib/external-backends/backends/infoblox-backend.js @@ -25,20 +25,20 @@ class InfobloxBackend extends ExternalBackends { * * return: { success: <boolean>, status: '<STATUS_CODE_IF_ERROR>', error: '<ERROR_MESSAGE>' } */ - checkConnection (credentials) { + async checkConnection (credentials) { var c = this.mapCredentials(credentials) var ipam = new Infoblox({ ip: c.url, apiVersion: c.version }) - return ipam.login(c.username, c.password).then(response => { - if (response) { - return { success: true } - } else { - return { success: false, error: 'Login failed' } - } - }) + const response = await ipam.login(c.username, c.password) + + if (response) { + return true + } else { + return { error: 'LOGIN_FAILED', message: 'Login failed' } + } } /* diff --git a/server/lib/external-backends/index.js b/server/lib/external-backends/index.js index 92e0f07..755cef4 100644 --- a/server/lib/external-backends/index.js +++ b/server/lib/external-backends/index.js @@ -141,13 +141,21 @@ class ExternalBackends { * credentials: <BACKEND_CREDENTIALS> * The client parameters are all optional. * client: { - * id: <CLIENT_ID>, title: <CLIENT_TITLE>, parentId: <PARENT_ID>, uuid: <CLIENT_UUID>, + * id: <CLIENT_ID>, title: <CLIENT_TITLE>, parentId: <PARENT_ID>, uuid: <CLIENT_UUID>, type: <CLIENT/SERVER> * system: { model: <SYSTEM_MODEL>, manufacturer: <SYSTEM_MANUFACTURER>, serialnumber: <SYSTEM_SERIALNUMBER> }, * cpu: { model: <CPU_MODEL>, manufacturer: <CPU_MANUFACTURER>, type: <CPU_TYPE>, frequency: <CPU_FREQUENCY>, cores: <CPU_CORES> }, * ram: [{ model: <RAM_MODEL>, manufacturer: <RAM_MANUFACTURER>, type: <RAM_TYPE>, capacity: <RAM_CAPACITY>, unit: <RAM_UNIT> }, ...], * storage: {}, * network: { mac: <MAC_ADDRESS>, ip: <IP_ADDRESS> } * } + * + * Servers are clients, that can additionally have special values: + * { + * ..., rackid: <RACK_ID> + * location: { assembly: <Horizontal/Vertical>, insertion: <Back/Front/Front and Back>, position: <RU 1 - 46> } + * system: { model: <SYSTEM_MODEL>, manufacturer: <SYSTEM_MANUFACTURER>, serialnumber: <SYSTEM_SERIALNUMBER> }, + * formfactor: { formfactor: <e.g. 19">, rackUnits: <integer> } + * } */ async updateClient (credentials, client) { return { success: false, error: 'NOT_IMPLEMENTED_EXCEPTION', message: 'The provided backend does not have an updateClient method' } diff --git a/webapp/src/components/BackendModule.vue b/webapp/src/components/BackendModule.vue index 43f07a2..6945d82 100644 --- a/webapp/src/components/BackendModule.vue +++ b/webapp/src/components/BackendModule.vue @@ -165,26 +165,26 @@ export default { } }, methods: { - checkConnection (item) { + async checkConnection (item) { // Set to start the loading animation. item.loading = true // Test the credential connection. - this.$http.post('/api/backends/' + item.id + '/connection', { - headers: { - 'Cache-Control': 'no-cache' - } - }).then(response => { - if (response.data.success) { - // Set the button color to green if success. - item.connection = 'success' - } else { - // Set the button color to red if error. - item.connection = 'error' - this.$snackbar({ color: 'error', text: response.data.error }) - } - // Set item.loading = false to end the loading animation. - item.loading = false - }) + try { + const response = await this.$http.post('/api/backends/' + item.id + '/connection', { + headers: { + 'Cache-Control': 'no-cache' + } + }) + // Set the button color to green if success. + if (response) item.connection = 'success' + } catch (error) { + // Set the button color to red if error. + item.connection = 'error' + this.$snackbar({ color: 'error', text: error.response.data.message }) + } + + // Set item.loading = false to end the loading animation. + item.loading = false }, checkConnections (items) { const tmp = this diff --git a/webapp/src/components/BackendModuleEdit.vue b/webapp/src/components/BackendModuleEdit.vue index 95f4d37..c5c1c31 100644 --- a/webapp/src/components/BackendModuleEdit.vue +++ b/webapp/src/components/BackendModuleEdit.vue @@ -106,6 +106,7 @@ <v-icon x-large color="primary">cached</v-icon> </v-btn> <div class="display-1">{{ $t('Status') }}: <strong :class="statusColor">{{ statusLabel }}</strong></div> + <div class="display-1">{{ $t('Status') }}: <strong :class="statusColor">TODO: REMOVE</strong></div> </v-layout> </v-container> </v-stepper-content> -- cgit v1.2.3-55-g7522