summaryrefslogblamecommitdiffstats
path: root/server/lib/external-backends/backends/idoit-backend.js
blob: fc3bbcabd684e2558751fb05729379c03a90584f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12


                                                                                 
                            

                                             





                                                                                 
                     


                                                                                   

                       










                                                                                  





                                                                                               
                                 



                                            




























                                                                                       



                                                                                                                                                
































































                                                                                                                            























                                                                                    















                                             




                                                                                         
                 
   
 

































                                                                       
                                                           
                                            






















                                                 
                      

                      
 
                                                            









                                                                                      





                                            
         









                                                                    







                                       
                         
       


                                     
 


















                                                                              
     
                 

   





























































































































































































                                                                                                                                                    



















                                                                                     





















                                                                                                                                    

                       

                       



                  
                      
                      
     
                                                       







                                                                                                      



                                                                                 

                               
                                                   
                                     
                                      

                                                                                                        
                                                      
     



                             
/* 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: <boolean>, status: '<STATUS_CODE_IF_ERROR>', error: '<ERROR_MESSAGE>' }
   */
  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: <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: <CLIENT_ID>, title: <CLIENT_TITLE>, parentId: <PARENT_ID>,
   *            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> }
   *         }
   */
  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