From 67d1402c75e562af34058d0021cf6a14b5588d22 Mon Sep 17 00:00:00 2001 From: Jannik Schönartz Date: Wed, 20 Mar 2019 04:22:50 +0000 Subject: [server/registration/backends] Rework addClient and updateClient to receive json Add idoit workaround for saving floats again Rework the grepSystemInfo bash script to match the new api --- server/api/registration.js | 157 ++-------------- server/ipxe/bash_scripts/addServer.sh | 6 +- server/ipxe/bash_scripts/grepSystemInfoRework.sh | 171 +++++++++++++++++ server/lib/external-backends/backendhelper.js | 204 +++++++++++---------- .../external-backends/backends/idoit-backend.js | 132 +++++++------ server/lib/external-backends/index.js | 13 +- server/lib/iphelper.js | 2 +- 7 files changed, 386 insertions(+), 299 deletions(-) create mode 100755 server/ipxe/bash_scripts/grepSystemInfoRework.sh (limited to 'server') diff --git a/server/api/registration.js b/server/api/registration.js index 11de700..4891e31 100644 --- a/server/api/registration.js +++ b/server/api/registration.js @@ -107,17 +107,17 @@ noAuthRouter.post('/group', (req, res) => { }) /* - * Reworked add method for adding a client or server. + * Add method for adding a client or server. */ noAuthRouter.postAsync('/', async (req, res) => { let client = req.body.client if (typeof client === 'string') client = JSON.parse(client) - const ipxe = req.body.ipxe - if (typeof ipxe === 'string') ipxe === 'true' ? true : false + let ipxe = req.body.ipxe + if (typeof ipxe === 'string') ipxe = true if (!client.type) client.type = 'CLIENT' - if (!client.title) client.title = client.type + '_' + client.uuid + if (!client.name) client.name = client.type + '_' + client.uuid // If the client already exists return the configloader ipxe script. const clientDb = await db.client.findOne({ where: { uuid: client.uuid } }) @@ -128,7 +128,7 @@ noAuthRouter.postAsync('/', async (req, res) => { // Client does not exist. if (!client.parents) client.parents = [] - const createClient = { name: client.title, description: client.type, ip: client.network.ip, mac: client.network.mac, uuid: client.uuid } + const createClient = { name: client.name, description: client.type, ip: client.network.ip, mac: client.network.mac, uuid: client.uuid } if (client.type === 'CLIENT') createClient.registrationState = await getNextHookScript(client.parents) const newClient = await db.client.create(createClient) client.id = newClient.id @@ -136,7 +136,7 @@ noAuthRouter.postAsync('/', async (req, res) => { // Add groups to the client. if (client.parents.length === 0) client.parents = await ipHelper.getGroups(client.network.ip) client.parents.forEach(pid => { newClient.addGroup(pid) }) - log({ category: 'CLIENT_REGISTRATION', description: client.type + ' added successfully.', clientId: newClient.id }) + log({ category: 'CLIENT_REGISTRATION', description: 'Client added successfully.', clientId: newClient.id }) // Add the client to the backends. const result = await backendHelper.addClient(client) @@ -144,142 +144,25 @@ noAuthRouter.postAsync('/', async (req, res) => { else return res.send(result) }) -/* - * Adds the client to the database and set parents if a parent was selected. Calls addClient for all external-backends. - */ -noAuthRouter.postAsync('/add', async (req, res) => { - const feedback = req.body.feedback - const mac = req.body.mac - const uuid = req.body.uuid - const ip = req.body.ip - let name = req.body.name - const parentId = parseInt(req.body.id) - const purpose = req.body.purpose - let parentIds = [] - - if (!name) name = 'Client_' + uuid - - // If the client already exists return the configloader ipxe script. - const client = await db.client.findOne({ where: { uuid: uuid } }) - if (client) return res.send(`#!ipxe\nchain https://` + url + `/api/configloader/\${uuid}`) - - // Else (Client does not exist) - var groupids = [] - if (parentId) groupids = [parentId] - const resId = await getNextHookScript(groupids) - const newClient = await db.client.create({ name: name, description: 'Client', ip: ip, mac: mac, uuid: uuid, registrationState: resId }) - if (parentId) { - newClient.addGroup(parentId) - parentIds.push(parentId) - } else { - // Filtered list with all group we will add the client - parentIds = await ipHelper.getGroups(ip) - parentIds.forEach(pid => { newClient.addGroup(pid) }) - } - log({ category: 'CLIENT_REGISTRATION', description: 'Client added successfully.', clientId: newClient.id }) - - // Add the client to the backends. - var c = { id: newClient.id, title: name, uuid: uuid, network: { mac: mac, ip: ip }, type: req.body.type } - if (parentIds.length > 0) c.parents = parentIds - if (purpose) c.purpose = purpose - - var result = await backendHelper.addClient(c) - - if (feedback) res.send(result) - else res.send(`#!ipxe\nchain https://` + url + `/api/configloader/\${uuid}`) -}) - -noAuthRouter.postAsync('/:uuid/update', async (req, res) => { - const uuid = req.params.uuid - const name = req.body.name - const parentId = req.body.id - - // System - const sysManufacturer = req.body.sys_manufacturer - const sysModel = req.body.sys_model - const sysSerial = req.body.sys_serial - - // CPU - const cpuModel = req.body.cpu_model - const cpuManufacturer = req.body.cpu_manufacturer - const cpuType = req.body.cpu_type - var cpuFrequency = req.body.cpu_frequency / 1000 - const cpuCores = req.body.cpu_cores - - // RAM - 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) - } - } - } +noAuthRouter.postAsync('/:uuid', async (req, res) => { + let client = req.body.client - // SSD / HDD - 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) - } - } + // Add the name to the ram modules. + for (let ram of client.ram.modules) { + ram.name = ram.formfactor + if (client.ram.isEcc === 'Single-bit ECC') ram.name += '-ECC' } - 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.' }) - - client.update({ name: name }) - var c = { uuid: uuid, id: client.id } - if (name) c.title = name - if (parentId) c.parentId = parentId + const clientDb = await db.client.findOne({ where: { uuid: client.uuid } }) + if (!clientDb) return res.status(404).send({ error: 'CLIENT_NOT_FOUND', message: 'There is no client matching the provided uuid.' }) + if (client.name) clientDb.update({ name: client.name }) + client.id = clientDb.id // 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(sysModel)) c.system.model = sysModel - else c.system.model = 'Not set' - - if (/\S/.test(sysSerial)) c.system.serialnumber = sysSerial - else c.system.serialnumber = 'Not set' - - // 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) + if (!/\S/.test(client.system.manufacturer)) client.system.manufacturer = 'unavailable' + if (!/\S/.test(client.system.model)) client.system.model = 'unavailable' + if (!/\S/.test(client.system.serialnumber)) client.system.serialnumber = 'unavailable' + const result = await backendHelper.updateClient(client) res.send(result) }) diff --git a/server/ipxe/bash_scripts/addServer.sh b/server/ipxe/bash_scripts/addServer.sh index 13f81d1..ad6e3aa 100755 --- a/server/ipxe/bash_scripts/addServer.sh +++ b/server/ipxe/bash_scripts/addServer.sh @@ -9,7 +9,7 @@ json_data() "type": "SERVER", "uuid": "$(dmidecode -q -s system-uuid | grep -v '^#' | head -n 1 | tr '[a-z]' '[A-Z]')", "network": { - "mac": "$(cat /sys/class/net/ens3/address)", + "mac": "$(ip addr show | grep -Eo -m 1 'ether\s.*\sbrd' | awk '{print $2}')", "ip": "$(hostname -I | awk '{print $1}')" }, "location": { @@ -27,5 +27,5 @@ json_data() EOF } -#curl -d "$(json_data)" -H "Content-Type: application/json" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registration -curl --data "$(json_data)" -H "Content-Type: application/json" -X POST --insecure https://bas.stfu-kthx.net:8888/api/registration \ No newline at end of file +curl -d "$(json_data)" -H "Content-Type: application/json" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registration +# curl --data "$(json_data)" -H "Content-Type: application/json" -X POST --insecure https://bas.stfu-kthx.net:8888/api/registration \ No newline at end of file diff --git a/server/ipxe/bash_scripts/grepSystemInfoRework.sh b/server/ipxe/bash_scripts/grepSystemInfoRework.sh new file mode 100755 index 0000000..bdc59b8 --- /dev/null +++ b/server/ipxe/bash_scripts/grepSystemInfoRework.sh @@ -0,0 +1,171 @@ +#!/bin/bash +. /lib/dracut-lib.sh +# http://git.openslx.org/openslx-ng/mltk.git/tree/core/modules/hardware-stats/data/opt/openslx/scripts/systemd-hardware_stats +# dmidecode | grep -i UUID +TYPE="CLIENT" + +cpu() { + cat << EOF +{ + "model": "$1", + "manufacturer": "$2", + "type": "$3", + "cores": "$4", + "frequency": "$5", + "unit": "$6" +} +EOF +} + +getCpus() { + readarray -t CPU_MODEL <<< "$(dmidecode -q -s processor-version)" + readarray -t CPU_MANUFACTURER <<< "$(dmidecode -q -s processor-manufacturer)" + readarray -t CPU_TYPE <<< "$(dmidecode -q -s processor-family)" + readarray -t CPU_CORES <<< "$(dmidecode -t processor | grep -o 'Core Count:.*' | cut -f3- -d ' ')" + readarray -t CPU_FREQUENCY <<< "$(dmidecode -q -s processor-frequency | cut -f1- -d ' ')" + + CPUS=() + FIRST=true + for i in ${!CPU_MODEL[@]}; do + if [ "$FIRST" == "true" ]; then + FIRST=false + else + CPUS+=", " + fi + + frequency=$(echo ${CPU_FREQUENCY[i]} | awk '{print $1}') + unit=$(echo ${CPU_FREQUENCY[i]} | awk '{print $2}') + CPUS+=$(cpu "${CPU_MODEL[i]}" "${CPU_MANUFACTURER[i]}" "${CPU_TYPE[i]}" "${CPU_CORES[i]}" "$frequency" "$unit") + done + echo ${CPUS[*]} +} + +# CPU +CPU_MODEL=$(dmidecode -q -s processor-version) +# CPUMODEL=$(grep -m1 '^model name\s*:' /proc/cpuinfo | sed 's/^model name\s*:\s*//;s/\s\s*/ /g;s/^ //;s/ $//') +CPU_MANUFACTURER=$(dmidecode -q -s processor-manufacturer) +CPU_TYPE=$(dmidecode -q -s processor-family) +CPU_CORES=$(cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list | sort -u | wc -l) +CPU_FREQUENCY=$(dmidecode -q -s processor-frequency) +CPU_FREQUENCY=${CPU_FREQUENCY%" MHz"} + +ram() { + cat << EOF +{ + "capacity": "$1", + "unit": "$2", + "manufacturer": "$3", + "type": "$4", + "formfactor": "$5" +} +EOF +} + +getRamModules() { + readarray -t RAM_SIZE <<< "$(dmidecode -t 17 | grep -o 'Size:.*' | cut -f2- -d ' ')" + readarray -t RAM_MANUFACTURER <<< "$(dmidecode -t 17 | grep -o 'Manufacturer:.*' | cut -f2- -d ' ')" + readarray -t RAM_TYPE <<< "$(dmidecode -t 17 | grep -o 'Type:.*' | cut -f2- -d ' ')" + readarray -t RAM_FORMFACTOR <<< "$(dmidecode -t 17 | grep -o 'Form Factor:.*' | cut -f3- -d ' ')" + RAM_MODULES=() + FIRST=true + for i in ${!RAM_SIZE[@]}; do + if [ "${RAM_SIZE[i]}" == 'No Module Installed' ] + then + continue + fi + + if [ "$FIRST" == "true" ]; then + FIRST=false + else + RAM_MODULES+=", " + fi + + size=$(echo ${RAM_SIZE[i]} | awk '{print $1}') + unit=$(echo ${RAM_SIZE[i]} | awk '{print $2}') + RAM_MODULES+=$(ram "$size" "$unit" "${RAM_MANUFACTURER[i]}" "${RAM_TYPE[i]}" "${RAM_FORMFACTOR[i]}") + done + echo ${RAM_MODULES[*]} +} + +drive() { + cat << EOF +{ + "model": "$1", + "serial": "$2", + "capacity": "$3", + "unit": "$4", + "type": "$5", + "formfactor": "$6", + "connection": "$7" +} +EOF +} + +getDrives() { +# HDD / SSD +# hd parm or smartctl from smartmontools +drives=$(ls /dev/sd* | grep -o '/dev/sd.$') + +DRIVES=() +FIRST=true +for drive in $drives; do + if [ "$FIRST" == "true" ]; then + FIRST=false + else + DRIVES+=", " + fi + drivedata=$(mktemp) + smartctl -i $drive >> $drivedata + + DRIVE_MODEL=$(cat $drivedata | grep -o "Device Model: .*" | cut -f2- -d ":" | sed -e 's/^[[:space:]]*//') + DRIVE_SERIAL=$(cat $drivedata | grep -o "Serial Number: .*" | cut -f2- -d ":" | sed -e 's/^[[:space:]]*//') + DRIVE_CAPACITY=$(cat $drivedata | grep -o "User Capacity: .*" | grep -Pzo '(?<=\[)(.*?)(?=\])' | awk '{print $1}') + DRIVE_UNIT=$(cat $drivedata | grep -o "User Capacity: .*" | grep -Pzo '(?<=\[)(.*?)(?=\])' | awk '{print $2}') + DRIVE_TYPE=$(cat $drivedata | grep -o "Rotation Rate: .*" | cut -f2- -d ":" | sed -e 's/^[[:space:]]*//') + DRIVE_FORMFACTOR=$(cat $drivedata | grep -o "Form Factor: .*" | cut -f2- -d ":" | sed -e 's/^[[:space:]]*//') + DRIVE_CONNECTION=$(cat $drivedata | grep -o "SATA Version is: .*" | cut -f2- -d ":" | sed -e 's/^[[:space:]]*//') + DRIVES+=$(drive "$DRIVE_MODEL" "$DRIVE_SERIAL" "$DRIVE_CAPACITY" "$DRIVE_UNIT" "$DRIVE_TYPE" "$DRIVE_FORMFACTOR" "$DRIVE_CONNECTION") +done +echo ${DRIVES[*]} +} + +# System +# VENDOR=$(dmidecode | grep -Eo '(Vendor).*' | cut -f 2 -d ":") + +# Mainboard +# MAINBOARD_MANUFACTURER=$(dmidecode -q -s baseboard-manufacturer) +# MAINBOARD_MODEL=$(dmidecode -q -s baseboard-product-name) +# MAINBOARD_SERIAL_NUMBER=$(dmidecode -q -s baseboard-serial-number) +UUID=$(dmidecode -q -s system-uuid | grep -v '^#' | head -n 1 | tr '[a-z]' '[A-Z]') +json_data() { + cat << EOF +{ + "client": { + "parents": [], + "type": "$TYPE", + "uuid": "$UUID", + "network": { + "mac": "$(ip addr show | grep -Eo -m 1 'ether\s.*\sbrd' | awk '{print $2}')", + "ip": "$(hostname -I | awk '{print $1}')" + }, + "system": { + "model": "$(dmidecode -q -s system-product-name)", + "manufacturer": "$(dmidecode -q -s system-manufacturer)", + "serialnumber": "$(dmidecode -q -s system-serial-number)" + }, + "cpus": [$(getCpus)], + "ram": { + "modules": [$(getRamModules)], + "isEcc": "$(dmidecode -t 16 | grep -o 'Error Correction Type:.*' | cut -f4- -d ' ')" + }, + "drives": [$(getDrives)] + } +} +EOF +} + +# Curl +# curl --data "state=6" --insecure https://bas.stfu-kthx.net:8888/api/registrations/$UUID/state +# curl -d "name=Client_$UUID&sys_manufacturer=$MANUFACTURER&sys_model=$MODEL&sys_serial=$SERIAL&cpu_model=$CPU_MODEL&cpu_manufacturer=$CPU_MANUFACTURER&cpu_type=$CPU_TYPE&cpu_cores=$CPU_CORES&cpu_frequency=$CPU_FREQUENCY&ram_size=$RAM_SIZE&ram_manufacturer=$RAM_MANUFACTURER&ram_type=$RAM_TYPE&ram_isecc=$RAM_ISECC&ram_formfactor=$RAM_FORMFACTOR&drives=${DRIVES[*]}" -H "Content-Type: application/x-www-form-urlencoded" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registration/$UUID/update +#echo $(json_data) +curl -d "$(json_data)" -H "Content-Type: application/json" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registration/$UUID \ No newline at end of file diff --git a/server/lib/external-backends/backendhelper.js b/server/lib/external-backends/backendhelper.js index 4bd9969..6892f7c 100644 --- a/server/lib/external-backends/backendhelper.js +++ b/server/lib/external-backends/backendhelper.js @@ -4,107 +4,115 @@ const ExternalBackends = require(path.join(__appdir, 'lib', 'external-backends') const db = require(path.join(__appdir, 'lib', 'sequelize')) const log = require(path.join(__appdir, 'lib', 'log')) -module.exports = { - addClient: async function (client) { - // Get all backends and call addClient for each instance. - var backends = await db.backend.findAll({ include: ['mappedGroups', 'mappedClients'] }) - var result = [] - - for (var b in backends) { - var backend = backends[b] - const ba = new ExternalBackends() - const instance = ba.getInstance(backend.type) - var tmpClient = JSON.parse(JSON.stringify(client)) - - // 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) { - 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' }) - - // Add backend to the conflict. - conflict.createObject({ objectType: 'BACKEND', objectId: backend.id }) - - // Add the groups to the conflict. - for (let element of elements) { - conflict.createObject({ objectType: 'GROUP', objectId: element.id }) - } - } else if (elements.length === 1) tmpClient['parentId'] = elements[0].backend_x_group.externalId - } - - 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 } }) - } - if (addClient.error && addClient.error !== 'NOT_IMPLEMENTED_EXCEPTION') log({ category: 'BACKEND_ERROR', description: `[${addClient.backendId}] ${addClient.error}: ${addClient.message}`, clientId: client.id }) - result.push(addClient) +module.exports = { addClient, updateClient, deleteClients, uploadFiles } + +async function addClient (client) { + // Get all backends and call addClient for each instance. + var backends = await db.backend.findAll({ include: ['mappedGroups', 'mappedClients'] }) + var result = [] + + for (var b in backends) { + var backend = backends[b] + const ba = new ExternalBackends() + const instance = ba.getInstance(backend.type) + var tmpClient = JSON.parse(JSON.stringify(client)) + + // Convert the parent group ids to the external backend parentIds. If multiple -> conflict + if (client.parents) { + 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' }) + + // Add backend to the conflict. + conflict.createObject({ objectType: 'BACKEND', objectId: backend.id }) + + // Add the groups to the conflict. + for (let element of elements) { + conflict.createObject({ objectType: 'GROUP', objectId: element.id }) + } + } else if (elements.length === 1) tmpClient['parentId'] = elements[0].backend_x_group.externalId } - return result - }, - - updateClient: async function (client) { - // Get all backends and call addClient for each instance. - const backends = await db.backend.findAll({ include: ['mappedGroups', 'mappedClients'] }) - let result = [] - - 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)) - - // Get the external clientid. - var exid = backend.mappedClients.find(y => y.id === parseInt(client.id)) - if (exid) tmpClient.id = exid.backend_x_client.externalId - - // Convert the parent group id to the external backend parentId. - if (client.parentId) { - var element = backend.mappedGroups.find(x => x.id === parseInt(client.parentId)) - if (element) tmpClient['parentId'] = element.backend_x_group.externalId - } - - let updateClient = await instance.updateClient(backend.credentials, tmpClient) - updateClient.backendId = backend.id - result.push(updateClient) + + 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 } }) } - return result - }, - - deleteClients: async function (clientids) { - // Get all backends and call deleteClient for each instance. - const backends = await db.backend.findAll({ where: { '$clientMappings.clientid$': clientids }, include: ['clientMappings'] }) - - backends.forEach(backend => { - const ba = new ExternalBackends() - const instance = ba.getInstance(backend.type) - var objectsToDelete = [] - backend.clientMappings.forEach(mapping => { - objectsToDelete.push(mapping.externalId) - }) - // If there are objects to delete -> delete them. - if (objectsToDelete.length > 0) instance.deleteObjects(backend.credentials, objectsToDelete) - }) - }, - - uploadFiles: async function (clientId, files) { - 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) - - let exid = backend.mappedClients.find(y => y.id === parseInt(clientId)) - if (exid) exid = exid.backend_x_client.externalId - results.push(await instance.uploadFiles(backend.credentials, exid, files)) + if (addClient.error && addClient.error !== 'NOT_IMPLEMENTED_EXCEPTION') log({ category: 'BACKEND_ERROR', description: `[${addClient.backendId}] ${addClient.error}: ${addClient.message}`, clientId: client.id }) + result.push(addClient) + } + return result +} + +async function updateClient (client) { + // Get all backends and call addClient for each instance. + const backends = await db.backend.findAll({ include: ['mappedGroups', 'mappedClients'] }) + let result = [] + + 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)) + + // Get the external clientid. + var exid = backend.mappedClients.find(y => y.id === parseInt(client.id)) + if (exid) tmpClient.id = exid.backend_x_client.externalId + + // Convert the parent group ids to the external backend parentIds. If multiple -> conflict + if (client.parents) { + 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' }) + + // Add backend to the conflict. + conflict.createObject({ objectType: 'BACKEND', objectId: backend.id }) + + // Add the groups to the conflict. + for (let element of elements) { + conflict.createObject({ objectType: 'GROUP', objectId: element.id }) + } + } else if (elements.length === 1) tmpClient['parentId'] = elements[0].backend_x_group.externalId } - return results + + let updateClient = await instance.updateClient(backend.credentials, tmpClient) + updateClient.backendId = backend.id + result.push(updateClient) } + return result +} + +async function deleteClients (clientids) { + // Get all backends and call deleteClient for each instance. + const backends = await db.backend.findAll({ where: { '$clientMappings.clientid$': clientids }, include: ['clientMappings'] }) + + backends.forEach(backend => { + const ba = new ExternalBackends() + const instance = ba.getInstance(backend.type) + var objectsToDelete = [] + backend.clientMappings.forEach(mapping => { + objectsToDelete.push(mapping.externalId) + }) + // If there are objects to delete -> delete them. + if (objectsToDelete.length > 0) instance.deleteObjects(backend.credentials, objectsToDelete) + }) +} +async function uploadFiles (clientId, files) { + 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) + + let exid = backend.mappedClients.find(y => y.id === parseInt(clientId)) + if (exid) exid = exid.backend_x_client.externalId + 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 8c1a4c3..ce7680a 100644 --- a/server/lib/external-backends/backends/idoit-backend.js +++ b/server/lib/external-backends/backends/idoit-backend.js @@ -170,7 +170,7 @@ class IdoitBackend extends ExternalBackends { if (headers.error) return headers let params = { 'apikey': c.apikey, - 'title': client.title, + 'title': client.name, 'purpose': client.purpose === 'Pool PC' ? 7 : undefined, 'categories': {} } @@ -218,7 +218,7 @@ class IdoitBackend extends ExternalBackends { 'apikey': c.apikey } const bodyMac = this.getBody('cmdb.category.save', paramsMac, 'add_mac_address') - const requestMac = await this.axiosRequest(c.url, [bodyMac], headers) + await this.axiosRequest(c.url, [bodyMac], headers) } // Purpose for Clients: @@ -247,9 +247,11 @@ class IdoitBackend extends ExternalBackends { if (headers.error) return headers let bodies = [] + // workaround for the fucking idoit shit. -.- + let requestResults = [] // 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')) + if (client.name) bodies.push(this.getBody('cmdb.object.update', { 'id': client.id, 'title': client.name, '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. @@ -298,95 +300,123 @@ class IdoitBackend extends ExternalBackends { // Update the object. CPU data. // TODO: Delete cpu if exists? - if (client.cpu) { - 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 - }, - 'apikey': c.apikey + if (client.cpus) { + let counter = 1 + for (let cpu of client.cpus) { + // Add KB and TB + if (cpu.unit === 'MB') cpu.unit = 2 + else if (cpu.unit === 'GB') cpu.unit = 3 + + let params = { + 'object': client.id, + 'objID': client.id, + 'category': 'C__CATG__CPU', + 'data': { + 'manufacturer': cpu.manufacturer, + 'title': cpu.model, + 'type': cpu.type, + 'frequency': parseFloat(cpu.frequency), + 'frequency_unit': 3, + 'cores': parseInt(cpu.cores) + }, + 'apikey': c.apikey + } + + counter++ + // WORKAROUND + // bodies.push(this.getBody('cmdb.category.save', params, 'create_cpu_' + counter)) + const a = await this.axiosRequest(c.url, [this.getBody('cmdb.category.save', params, 'create_cpu_' + counter)], headers) + requestResults.push(a) } - bodies.push(this.getBody('cmdb.category.save', params, 'update_cpu')) } // Update the object. Ram data. if (client.ram) { let counter = 1 - for (var memory in client.ram) { - var mem = client.ram[memory] - var ramId = 'create_memory_' + counter - if (mem.unit === 'MB') mem.capacity = mem.capacity / 1024 + for (let module of client.ram.modules) { + // Add KB and TB + if (module.unit === 'MB') module.unit = 2 + else if (module.unit === 'GB') module.unit = 3 - // 2 = MB - // 3 = GB 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 + 'title': module.type, + 'manufacturer': module.manufacturer, + 'type': module.type, + 'capacity': parseFloat(module.capacity), + 'unit': module.unit }, 'apikey': c.apikey } counter++ - bodies.push(this.getBody('cmdb.category.save', params, ramId)) + // WORKAROUND + // bodies.push(this.getBody('cmdb.category.save', params, 'create_memory_' + counter)) + const a = await this.axiosRequest(c.url, [this.getBody('cmdb.category.save', params, 'create_memory_' + counter)], headers) + requestResults.push(a) } } // Update the object. Drive data. if (client.drives) { let counter = 1 - for (var drive in client.drives) { - var d = client.drives[drive] - var driveId = 'create_drive_' + counter - + for (let drive of client.drives) { // UNIT - var unit = 0 - if (d.unit === 'GB') unit = 3 - else if (d.unit === 'TB') unit = 4 - else if (d.unit === 'MB') unit = 2 - else if (d.unit === 'KB') unit = 1 - else if (d.unit === 'B') unit = 0 + if (drive.unit === 'GB') drive.unit = 3 + else if (drive.unit === 'MB') drive.unit = 2 + else if (drive.unit === 'TB') drive.unit = 4 + else if (drive.unit === 'KB') drive.unit = 1 + else if (drive.unit === 'B') drive.unit = 0 + + if (drive.type === 'Solid State Device') drive.type = 'SSD' + else if (drive.type === '5400 rpm') drive.type = 'Hard disk' + else if (drive.type === '7200 rpm') drive.type = 'Hard disk' + else if (drive.type === '') drive.type = 'Hard disk' let params = { 'object': client.id, 'objID': client.id, 'category': 'C__CATG__STORAGE_DEVICE', 'data': { - 'title': d.model, - 'type': d.type, + 'category_id': counter, + 'title': drive.model, + 'type': drive.type, // 'manufacturer': , // 'model': , - 'capacity': d.capacity, - 'unit': unit, - 'serial': d.serial, - 'connected': d.connection + 'capacity': parseFloat(drive.capacity), + 'unit': drive.unit, + 'serial': drive.serial, + 'connected': drive.connection }, 'apikey': c.apikey } - bodies.push(this.getBody('cmdb.category.save', params, driveId)) + + counter++ + // WORKAROUND + // bodies.push(this.getBody('cmdb.category.save', params, 'create_drive_' + counter)) + const a = await this.axiosRequest(c.url, [this.getBody('cmdb.category.save', params, 'create_drive_' + counter)], headers) + requestResults.push(a) } } const requestUpdate = await this.axiosRequest(c.url, bodies, headers) + requestResults.push(requestUpdate) + + if (requestUpdate.error) return requestUpdate // 10 is the idoit object id for clients. - var result = { + // 5 is the idoit object id for servers. + let type = 0 + if (client.type === 'CLIENT') type = 10 + else if (client.type === 'SERVER') type = 5 + + const result = { success: true, id: client.id, - type: 10, - response: requestUpdate + type: type, + // response: requestUpdate + response: requestResults } return result diff --git a/server/lib/external-backends/index.js b/server/lib/external-backends/index.js index 41d1c31..7acaa85 100644 --- a/server/lib/external-backends/index.js +++ b/server/lib/external-backends/index.js @@ -128,7 +128,10 @@ class ExternalBackends { * 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: , uuid: , - * network: { mac: , ip: } + * network: { mac: , ip: }, + * location: { assembly: , insertion: , position: }, + * system: { model: , manufacturer: , serialnumber: }, + * formfactor: { formfactor: , rackunits: } * } */ async addClient (credentials, client) { @@ -148,14 +151,6 @@ class ExternalBackends { * storage: {}, * network: { mac: , ip: } * } - * - * Servers are clients, that can additionally have special values: - * { - * ..., rackid: - * location: { assembly: , insertion: , position: } - * system: { model: , manufacturer: , serialnumber: }, - * formfactor: { formfactor: , rackunits: } - * } */ async updateClient (credentials, client) { return { error: 'NOT_IMPLEMENTED_EXCEPTION', message: 'The provided backend does not have an updateClient method' } diff --git a/server/lib/iphelper.js b/server/lib/iphelper.js index 769dcc3..8432b01 100644 --- a/server/lib/iphelper.js +++ b/server/lib/iphelper.js @@ -5,7 +5,7 @@ module.exports = { toDecimal, toIPv4, getGroups, isIPv4 } // Finds the groups where the ip fits best in the subnets. async function getGroups (ipString) { - const ipInt = toDecimal(ipString) + const ipInt = toDecimal(ipString) let fittingIpRanges = await db.iprange.findAll({ where: { startIp: { [db.Op.lte]: ipInt }, endIp: { [db.Op.gte]: ipInt } } }) fittingIpRanges = fittingIpRanges.map(x => x.groupId) -- cgit v1.2.3-55-g7522