/* global __appdir */ const path = require('path') 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. */ getCredentials () { return [ { type: 'text', id: 1, name: 'API url', icon: 'link' }, { type: 'password', id: 2, name: 'API token', icon: 'vpn_key', show: false }, { type: 'switch', id: 3, name: 'Login', icon: 'lock_open', elements: [ { type: 'text', id: 4, name: 'username', icon: 'person_outline' }, { type: 'password', id: 5, name: 'password', icon: 'lock', show: false } ] } ] } /* * 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: , status: '', error: '' } */ checkConnection (credentials) { var c = this.mapCredentials(credentials) return this.getSession(c) } // 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' } var result = {} result.types = await this.axiosRequest(c.url, 'cmdb.object_types', params, headers) result.types = result.types.data.result var types = [] result.types.forEach(type => { types.push({ id: type.id, title: type.title }) }) return types } getSyncTypes () { return ['None', 'Two-Way', 'Upload Only', 'Upload Then Delete', 'Upload Mirror', 'Download Only', 'Download Then Delete', 'Download Mirror'] } /* * Gets all objects and searches for the ip. Because idoit cannot search for ip or mac. * */ async getClient (credentials, client) { 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': 1450, 'apikey': c.apikey, 'language': 'en' } // Get common object data var result = {} result.common = await this.axiosRequest(c.url, 'cmdb.object.read', params, headers) result.common = result.common.data.result // Get objecttypes delete params.id // params.type = result.common.objecttype // result.categories = await this.axiosRequest(c.url, 'cmdb.object_type_categories', params, headers) // result.categories = result.categories.data.result // result.categories = result.categories.data.result /* var cat = [] var self = this result.categories.catg.forEach(async c => { delete params.type params.objID = 1450 params.category = c.const console.log(params) //var tmp = await self.axiosRequest(c.url, 'cmdb.category.read', params, headers).catch(error => {console.log(error)}) //tmp = tmp.data.result //cat.push(tmp) }) result.cat = cat */ // Get all ip addresses // delete params.type params.objID = 1450 params.category = 'C__CATG__IP' var tmp = await this.axiosRequest(c.url, 'cmdb.category.read', params, headers) tmp = tmp.data.result tmp.forEach(element => { if (element.primary_hostaddress) { result.ip = element.primary_hostaddress.ref_title } }) return result } 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' } var result = {} result.objects = await this.axiosRequest(c.url, 'cmdb.objects', params, headers) result.objects = result.objects.data.result return result } 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' } 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 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 = [] objectIds.forEach(oid => { // Body bodies.push({ 'version': '2.0', 'method': 'cmdb.object.delete', 'params': { 'id': oid, 'apikey': c.apikey, 'language': 'en' }, 'id': oid }) }) var requestDelete = await axios.post(c.url, bodies, config) return { success: requestDelete.success, data: requestDelete.data } } // 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 = {} // 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) 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 }) } } return result } /* * Adds the client to the 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. * client: { * id: , title: , parentId: , * system: { model: , manufacturer: , serialnumber: }, * cpu: { model: , manufacturer: , type: , frequency: , cores: }, * ram: [{ model: , manufacturer: , type: , capacity: , unit: }, ...], * storage: {}, * network: { mac: , ip: } * } */ 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 clientid if (!client.id) { // Create the object in idoIT. var params = { 'type': 'C__OBJTYPE__CLIENT', 'title': client.title, 'apikey': c.apikey, 'language': 'en' } var requestCreate = await this.axiosRequest(c.url, 'cmdb.object.create', params, config.headers) clientid = requestCreate.data.result.id } else { clientid = client.id } var bodies = [] if (client.network) { // Update the object. MAC-Address if (client.network.mac) { 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' }) } // 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' }) } } // 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' }) } 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' }, 'id': 'update_model' }) } if (client.cpu) { // 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': 1, 'cores': client.cpu.cores }, 'apikey': c.apikey, 'language': 'en' }, 'id': 'update_cpu' }) } if (client.ram) { var counter = 1 var mem for (mem in client.ram) { var id = 'create_memory_' + counter // Update the object. bodies.push({ 'version': '2.0', 'method': 'cmdb.category.create', 'params': { 'objID': clientid, 'category': 'C__CATG__MEMORY', 'data': { 'title': mem.model, 'manufacturer': mem.manufacturer, 'type': mem.type, 'capacity': mem.capacity, 'unit': mem.unit }, 'apikey': c.apikey, 'language': 'en' }, 'id': id }) counter++ } } var requestUpdate = await axios.post(c.url, bodies, config) var result = { success: true, id: clientid, type: 'C__OBJTYPE__CLIENT', create: requestCreate ? requestCreate.success : false, update: requestUpdate ? requestUpdate.success : false, createData: requestCreate ? requestCreate.data : false, updateData: requestUpdate ? requestUpdate.data : false } 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) const login = c.find(x => x.id === 3) var mapped = { url: c.find(x => x.id === 1).value, apikey: c.find(x => x.id === 2).value, login: login.value } if (mapped.login) { mapped.username = login.elements.find(x => x.id === 4).value mapped.password = login.elements.find(x => x.id === 5).value } 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' } // Make a login request and see if we are authenticated. return this.axiosRequest(credentials.url, 'idoit.login', params, headers) } // 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 = { 'version': '2.0', 'method': method, 'params': params, 'id': 1 } 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' } } } } module.exports = IdoitBackend