From 92e2d90dd65dd9b68b6e779c41993d73be5d6e94 Mon Sep 17 00:00:00 2001 From: Jannik Schönartz Date: Tue, 11 Dec 2018 14:51:58 +0000 Subject: Rename registrations in registration. --- server/api/registration.js | 472 ++++++++++++++++++++++++++++++++++++++++++ server/api/registrations.js | 472 ------------------------------------------ server/ipxe/grepSystemInfo.sh | 6 +- server/ipxe/registration.ipxe | 8 +- 4 files changed, 479 insertions(+), 479 deletions(-) create mode 100644 server/api/registration.js delete mode 100644 server/api/registrations.js (limited to 'server') diff --git a/server/api/registration.js b/server/api/registration.js new file mode 100644 index 0000000..29e47bd --- /dev/null +++ b/server/api/registration.js @@ -0,0 +1,472 @@ +/* global __appdir */ +var path = require('path') +var express = require('express') +var router = express.Router() +var noAuthRouter = express.Router() +var db = require(path.join(__appdir, 'lib', 'sequelize')) +const ExternalBackends = require(path.join(__appdir, 'lib', 'external-backends')) +const backendHelper = require(path.join(__appdir, 'lib', 'external-backends', 'backendhelper')) + +// GET requests. + +/* + * TODO: CURRENTLY TEST FUNCTION + */ +noAuthRouter.get('/', (req, res) => { + // backendHelper.deleteClients().then(r => { + // res.send(r) + // }) + + /* + db.backend.findOne({ where: { id: 1 } }).then(result => { + const b = new ExternalBackends() + const instance = b.getInstance(result.type) + instance.getClient(result.credentials, {}).then(result => { + res.status(200).send(result) + }) + }) */ + db.backend.findOne({ where: { id: 3 } }).then(result => { + const b = new ExternalBackends() + const instance = b.getInstance(result.type) + instance.uploadTpm(result.credentials, 99696, 'I-123-d12', null).then(result => { + res.status(200).send(result) + }) + }) +}) + +/* + * Returns all registration hooks sorted by sortValue. + * + * @return: List of registration hooks + */ +router.get('/hooks', (req, res) => { + db.registrationhook.findAll({ order: [ ['sortValue', 'ASC'] ], include: [{ model: db.group, as: 'groups', attributes: ['id'] }] }).then(hooks => { + res.send(hooks) + }) +}) + +// POST requests. + +/* + * Reorders the registration hooks based on an array of hook ids. + */ +router.post('/hookorder', async (req, res) => { + var idSortvalueMap = {} + req.body.ids.forEach((id, index) => { + idSortvalueMap[id] = index + }) + var hooks = await db.registrationhook.findAll() + var promises = [] + hooks.forEach(hook => { + promises.push(hook.update({ sortvalue: idSortvalueMap[hook.id] })) + }) + await Promise.all(promises) + res.end() +}) + +router.post(['/hooks', '/hooks/:id'], async (req, res) => { + var item = { + name: req.body.name, + description: req.body.description, + type: req.body.type, + script: req.body.script + } + var hook = null + if (req.params.id > 0) { + hook = await db.registrationhook.findOne({ where: { id: req.params.id } }) + if (hook) await hook.update(item) + } else { + var maxSortvalue = await db.registrationhook.max('sortvalue') + item.sortvalue = maxSortvalue ? maxSortvalue + 1 : 1 + hook = await db.registrationhook.create(item) + } + if (hook) { + hook.setGroups(req.body.groups) + res.send({ id: hook.id }) + } + res.end() +}) + +// DELETE requests. + +router.delete(['/hooks', '/hooks/:id'], (req, res) => { + db.registrationhook.destroy({ where: { id: req.params.id || req.body.ids } }).then(count => { res.send({ count }) }) +}) + +module.exports.router = router + +// GET requests. + +// POST requests. + +/* + * Returns all root parents or all childs of a group. + * + * @return: Ipxe menu with a list of groups. + */ +noAuthRouter.post('/group', (req, res) => { + const id = req.body.id + var parents = [] + if (req.body.parents) parents = JSON.parse(req.body.parents) + if (id === '0') { + db.group.findAll({ where: { '$parents.id$': null }, include: ['parents'] }).then(groups => { + if (groups) { + res.send(buildIpxeMenu(id, 'Root', groups, [])) + } else { + res.status(404).end() + } + }) + } else { + db.group.findOne({ where: { id: id }, include: ['parents', 'subgroups', 'clients'] }).then(group => { + if (group) { + res.send(buildIpxeMenu(id, group.name, group.subgroups, parents)) + } else { + res.status(404).end() + } + }) + } +}) + +/* + * Adds the client to the database and set parents if a parent was selected. Calls addClient for all external-backends. + */ +noAuthRouter.post('/add', (req, res) => { + const feedback = req.body.feedback + const mac = req.body.mac + const uuid = req.body.uuid + const ip = req.body.ip + var name = req.body.name + const parentId = req.body.id + const purpose = req.body.purpose + + if (!name) name = 'Client_' + uuid + + db.client.findOne({ where: { uuid: uuid } }).then(client => { + if (client) res.send(`#!ipxe\nchain https://bas.intra.uni-freiburg.de/api/configloader/\${uuid}`) + else { + var groupids = [] + if (parentId) groupids = [parentId] + getNextHookScript(groupids).then(resId => { + db.client.create({ name: name, description: 'Client', ip: ip, mac: mac, uuid: uuid, registrationState: resId }).then(newClient => { + if (parentId) { + newClient.addGroup(parentId) + } + + // Add the client to the backends. + var c = { title: name, uuid: uuid, network: { mac: mac, ip: ip } } + if (parentId) c.parentId = parentId + if (purpose) c.purpose = purpose + backendHelper.addClient(c).then(result => { + if (feedback) res.send(result) + result.forEach(response => { + // If the object was created we need to make the objectid / external id mapping. + if (response.success) { + db.backend.findOne({ where: { id: response.backendId }, include: ['mappedClients'] }).then(backend => { + backend.addMappedClients(newClient, { through: { externalId: response.id, externalType: response.type } }) + }) + } + }) + }) + if (!feedback) res.send(`#!ipxe\nchain https://bas.intra.uni-freiburg.de/api/configloader/\${uuid}`) + }) + }) + } + }) +}) + +noAuthRouter.post('/:uuid/update', (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 + 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(' ') + const 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: ', '') } + ramModules.push(ramModule) + } + } + // ramTmpSize = ramSize.split('\n')[0].replace('Size: ', '').split(' ') + // ramSize = ramTmpSize[0] + // ramUnit = ramTmpSize[1] + // ramManufacturer = ramManufacturer.split('\n')[0].replace('Manufacturer: ', '') + // ramType = ramType.split('\n')[0].replace('Type: ', '') + // ramFormfactor = ramFormfactor.split('\n')[0].replace('Form Factor: ', '') + // var ramTitle = ramFormfactor + // if (ramIsEcc === "Single-bit ECC") ramTitle += '-ECC' + // var ram = { capacity: ramSize, manufacturer: ramManufacturer, title: ramTitle, type: ramType, formfactor: ramFormfactor, unit: ramUnit } + + 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 + + // 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 } + c.ram = ramModules + + backendHelper.updateClient(c).then(result => { + 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() + }) +}) + +/* + * Open api method for setting the registration state of a given uuid. + */ +noAuthRouter.post('/:uuid/success', (req, res) => { + const uuid = req.params.uuid + const id = parseInt(req.body.id) + db.client.findOne({ where: { uuid: uuid }, include: ['groups'] }).then(client => { + // Client not found handling + if (client === null) { + res.status(404).send({ status: 'INVALID_UUID', error: 'There is no client with the provided UUID.' }) + return + } + + // Check if the finished script id (id) matches the current state of the client. + if (client.registrationState !== id) { + res.status(400).send({ status: 'INVALID_SCRIPT', error: 'This script should not have been executed.' }) + return + } + + // If it matches, search for the next script and update the clients registrationState. + // Get all group id's of the client. + var groupids = [] + client.groups.forEach(g => { + groupids = [...groupids, g.id] + }) + + // Get the sort value of the current hook. + db.registrationhook.findOne({ where: { id: client.registrationState } }).then(hook => { + getNextHookScript(groupids, hook.sortvalue).then(resID => { + // Update the client's registration state + client.updateAttributes({ + registrationState: resID + }) + res.send({ status: 'SUCCESS' }) + }) + }) + }) +}) + +/* + * Returns the next bash script for the minilinux. Else empty script. (Empty = bash will make reboot) + */ +noAuthRouter.get('/:uuid/nexthook', (req, res) => { + const uuid = req.params.uuid + db.client.findOne({ where: { uuid: uuid } }).then(client => { + // Return 404 if the client doesn't exist or it has no registration state. + if (client === null || client.registrationState === null) { + res.status(404).send() + return + } + db.registrationhook.findOne({ where: { id: client.registrationState } }).then(hook => { + if (hook.type !== 'BASH') { + res.send() + } else { + res.set('id', client.registrationState) + res.send(hook.script) + } + }) + }) +}) + +module.exports.noAuthRouter = noAuthRouter + +/* + * parentIds: + * sortvalue: + * + */ +function getNextHookScript (groupids, sortvalue) { + // Gets the list of all groupids inclusive the recursive parents. + return getRecursiveParents(groupids).then(gids => { + // Get the list of all hooks where the parent is null or those who fullfill the group dependency. + var options = { where: { '$groups.id$': { $or: [null, gids] } }, include: ['groups'], order: [['sortvalue', 'ASC']] } + if (sortvalue !== undefined) options.where.sortvalue = { $gt: sortvalue } + return db.registrationhook.findAll(options).then(result => { + var resID = null + if (result.length >= 1) resID = result[0].id + return resID + }) + }) +} + +/* + * groupids: Array of group ids to get the parents from. + * + * Returns a list of the grop ids and all recursive ids of their parents. + */ +function getRecursiveParents (groupIds) { + var gids = [] + return db.group.findAll({ where: { id: groupIds }, include: ['parents'] }).then(groups => { + groups.forEach(group => { + group.parents.forEach(parent => { + if (!groupIds.includes(parent.id) && !gids.includes(parent.id)) gids = [...gids, parent.id] + }) + }) + if (gids.length === 0) return groupIds + else { + return getRecursiveParents(gids).then(r => { + return groupIds.concat(r) + }) + } + }) +} + +/* + * id: id of the current selected location. + * name: Name of the current selected location + * groups: List of group [{ id: , name: }, ...] + * + * Build the ipxe menu out of the list of groups. + * Used by the manual registration. + */ +function buildIpxeMenu (id, name, groups, parents) { + var basUrl = 'https://bas.intra.uni-freiburg.de' + var script = '#!ipxe\r\n' + // script = script.concat(`console --picture \${img} --x 800 --y 600 || shell\r\n`) + + // Add parent to keep track of the path we clicked through. + var parentId = 0 + var oldParents = parents.slice(0) + if (parents.length > 0) { + parentId = oldParents[oldParents.length - 1].id + oldParents.length = oldParents.length - 1 + } + parents.push({ id: id, name: toAscii(name) }) + script += `set space:hex 20:20\r\n` + script += `set space \${space:string}\r\n` + script += `set parents ` + JSON.stringify(parents) + '\r\n\r\n' + + // Menu + var menuscript = '' + script += ':start\r\n' + script += 'menu Choose the group you want the client to be saved in\r\n' + + // Parent menu entries. + var spacer = '' + parents.forEach(parent => { + script += 'item --gap ' + spacer + '[' + parent.id + '] ' + parent.name + '\r\n' + spacer += `\${space}` + }) + + // Back button + script += 'item --key b back ' + spacer + '..\r\n' + menuscript += ':back\r\nparams\r\nparam id ' + parentId + '\r\nparam parents ' + JSON.stringify(oldParents) + '\r\n' + menuscript += 'chain --replace ' + basUrl + '/api/registration/group##params\r\n\r\n' + + // Group menu entries. First 1-9 are pressable via key? + var counter = '1' + groups.forEach(group => { + script += 'item --key ' + counter + ' ' + counter + ' ' + spacer + '[' + group.id + '] ' + toAscii(group.name) + '\r\n' + menuscript += ':' + counter + '\r\n' + 'params\r\nparam id ' + group.id + `\r\nparam parents \${parents}\r\n` + menuscript += 'chain --replace ' + basUrl + '/api/registration/group##params\r\n\r\n' + counter++ + }) + + // Menu seperator + script += 'item --gap\r\n' + + // Add client menu + script += 'item select Add client to ' + toAscii(name) + '\r\n' + menuscript += `:select\r\necho Enter client name\r\nread clientname\r\nparams\r\nparam name \${clientname}\r\n` + menuscript += 'param id ' + id + `\r\nparam mac \${net0/mac}\r\nparam uuid \${uuid}\r\nparam ip \${net0/ip}\r\n` + menuscript += 'chain --replace ' + basUrl + '/api/registration/add##params\r\n\r\n' + + // Goto start menu + if (id !== '0') { + script += 'item reset Go to start\r\n' + menuscript += ':reset\r\nparams\r\nparam id ' + 0 + '\r\nchain --replace ' + basUrl + '/api/registration/group##params\r\n\r\n' + } + + // Exit menu + script += 'item exit Exit manual registration\r\n' + menuscript += ':exit\r\nexit 1\r\n\r\n' + + // Concat script + menuscript and return it. + script += `choose target && goto \${target}\r\n\r\n` + script += menuscript + return script +} + +function toAscii (string) { + string = string.replace('ü', 'ue') + string = string.replace('ö', 'oe') + string = string.replace('ä', 'ae') + return ascii(string) +} + +/* eslint-disable */ +var escapable = /[\\"\x00-\x1f\x7f-\uffff]/g +/* eslint-enable */ +var meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"': '\\"', + '\\': '\\\\' +} + +function ascii (string) { +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0 + return escapable.test(string) + ? string.replace(escapable, function (a) { + var c = meta[a] + return typeof c === 'string' ? c + : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4) + }) : string +} diff --git a/server/api/registrations.js b/server/api/registrations.js deleted file mode 100644 index 9192619..0000000 --- a/server/api/registrations.js +++ /dev/null @@ -1,472 +0,0 @@ -/* global __appdir */ -var path = require('path') -var express = require('express') -var router = express.Router() -var noAuthRouter = express.Router() -var db = require(path.join(__appdir, 'lib', 'sequelize')) -const ExternalBackends = require(path.join(__appdir, 'lib', 'external-backends')) -const backendHelper = require(path.join(__appdir, 'lib', 'external-backends', 'backendhelper')) - -// GET requests. - -/* - * TODO: CURRENTLY TEST FUNCTION - */ -noAuthRouter.get('/', (req, res) => { - // backendHelper.deleteClients().then(r => { - // res.send(r) - // }) - - /* - db.backend.findOne({ where: { id: 1 } }).then(result => { - const b = new ExternalBackends() - const instance = b.getInstance(result.type) - instance.getClient(result.credentials, {}).then(result => { - res.status(200).send(result) - }) - }) */ - db.backend.findOne({ where: { id: 3 } }).then(result => { - const b = new ExternalBackends() - const instance = b.getInstance(result.type) - instance.uploadTpm(result.credentials, 99696, 'I-123-d12', null).then(result => { - res.status(200).send(result) - }) - }) -}) - -/* - * Returns all registration hooks sorted by sortValue. - * - * @return: List of registration hooks - */ -router.get('/hooks', (req, res) => { - db.registrationhook.findAll({ order: [ ['sortValue', 'ASC'] ], include: [{ model: db.group, as: 'groups', attributes: ['id'] }] }).then(hooks => { - res.send(hooks) - }) -}) - -// POST requests. - -/* - * Reorders the registration hooks based on an array of hook ids. - */ -router.post('/hookorder', async (req, res) => { - var idSortvalueMap = {} - req.body.ids.forEach((id, index) => { - idSortvalueMap[id] = index - }) - var hooks = await db.registrationhook.findAll() - var promises = [] - hooks.forEach(hook => { - promises.push(hook.update({ sortvalue: idSortvalueMap[hook.id] })) - }) - await Promise.all(promises) - res.end() -}) - -router.post(['/hooks', '/hooks/:id'], async (req, res) => { - var item = { - name: req.body.name, - description: req.body.description, - type: req.body.type, - script: req.body.script - } - var hook = null - if (req.params.id > 0) { - hook = await db.registrationhook.findOne({ where: { id: req.params.id } }) - if (hook) await hook.update(item) - } else { - var maxSortvalue = await db.registrationhook.max('sortvalue') - item.sortvalue = maxSortvalue ? maxSortvalue + 1 : 1 - hook = await db.registrationhook.create(item) - } - if (hook) { - hook.setGroups(req.body.groups) - res.send({ id: hook.id }) - } - res.end() -}) - -// DELETE requests. - -router.delete(['/hooks', '/hooks/:id'], (req, res) => { - db.registrationhook.destroy({ where: { id: req.params.id || req.body.ids } }).then(count => { res.send({ count }) }) -}) - -module.exports.router = router - -// GET requests. - -// POST requests. - -/* - * Returns all root parents or all childs of a group. - * - * @return: Ipxe menu with a list of groups. - */ -noAuthRouter.post('/group', (req, res) => { - const id = req.body.id - var parents = [] - if (req.body.parents) parents = JSON.parse(req.body.parents) - if (id === '0') { - db.group.findAll({ where: { '$parents.id$': null }, include: ['parents'] }).then(groups => { - if (groups) { - res.send(buildIpxeMenu(id, 'Root', groups, [])) - } else { - res.status(404).end() - } - }) - } else { - db.group.findOne({ where: { id: id }, include: ['parents', 'subgroups', 'clients'] }).then(group => { - if (group) { - res.send(buildIpxeMenu(id, group.name, group.subgroups, parents)) - } else { - res.status(404).end() - } - }) - } -}) - -/* - * Adds the client to the database and set parents if a parent was selected. Calls addClient for all external-backends. - */ -noAuthRouter.post('/add', (req, res) => { - const feedback = req.body.feedback - const mac = req.body.mac - const uuid = req.body.uuid - const ip = req.body.ip - var name = req.body.name - const parentId = req.body.id - const purpose = req.body.purpose - - if (!name) name = 'Client_' + uuid - - db.client.findOne({ where: { uuid: uuid } }).then(client => { - if (client) res.send(`#!ipxe\nchain https://bas.intra.uni-freiburg.de/api/configloader/\${uuid}`) - else { - var groupids = [] - if (parentId) groupids = [parentId] - getNextHookScript(groupids).then(resId => { - db.client.create({ name: name, description: 'Client', ip: ip, mac: mac, uuid: uuid, registrationState: resId }).then(newClient => { - if (parentId) { - newClient.addGroup(parentId) - } - - // Add the client to the backends. - var c = { title: name, uuid: uuid, network: { mac: mac, ip: ip } } - if (parentId) c.parentId = parentId - if (purpose) c.purpose = purpose - backendHelper.addClient(c).then(result => { - if (feedback) res.send(result) - result.forEach(response => { - // If the object was created we need to make the objectid / external id mapping. - if (response.success) { - db.backend.findOne({ where: { id: response.backendId }, include: ['mappedClients'] }).then(backend => { - backend.addMappedClients(newClient, { through: { externalId: response.id, externalType: response.type } }) - }) - } - }) - }) - if (!feedback) res.send(`#!ipxe\nchain https://bas.intra.uni-freiburg.de/api/configloader/\${uuid}`) - }) - }) - } - }) -}) - -noAuthRouter.post('/:uuid/update', (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 - 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(' ') - const 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: ', '') } - ramModules.push(ramModule) - } - } - // ramTmpSize = ramSize.split('\n')[0].replace('Size: ', '').split(' ') - // ramSize = ramTmpSize[0] - // ramUnit = ramTmpSize[1] - // ramManufacturer = ramManufacturer.split('\n')[0].replace('Manufacturer: ', '') - // ramType = ramType.split('\n')[0].replace('Type: ', '') - // ramFormfactor = ramFormfactor.split('\n')[0].replace('Form Factor: ', '') - // var ramTitle = ramFormfactor - // if (ramIsEcc === "Single-bit ECC") ramTitle += '-ECC' - // var ram = { capacity: ramSize, manufacturer: ramManufacturer, title: ramTitle, type: ramType, formfactor: ramFormfactor, unit: ramUnit } - - 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 - - // 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 } - c.ram = ramModules - - backendHelper.updateClient(c).then(result => { - 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() - }) -}) - -/* - * Open api method for setting the registration state of a given uuid. - */ -noAuthRouter.post('/:uuid/success', (req, res) => { - const uuid = req.params.uuid - const id = parseInt(req.body.id) - db.client.findOne({ where: { uuid: uuid }, include: ['groups'] }).then(client => { - // Client not found handling - if (client === null) { - res.status(404).send({ status: 'INVALID_UUID', error: 'There is no client with the provided UUID.' }) - return - } - - // Check if the finished script id (id) matches the current state of the client. - if (client.registrationState !== id) { - res.status(400).send({ status: 'INVALID_SCRIPT', error: 'This script should not have been executed.' }) - return - } - - // If it matches, search for the next script and update the clients registrationState. - // Get all group id's of the client. - var groupids = [] - client.groups.forEach(g => { - groupids = [...groupids, g.id] - }) - - // Get the sort value of the current hook. - db.registrationhook.findOne({ where: { id: client.registrationState } }).then(hook => { - getNextHookScript(groupids, hook.sortvalue).then(resID => { - // Update the client's registration state - client.updateAttributes({ - registrationState: resID - }) - res.send({ status: 'SUCCESS' }) - }) - }) - }) -}) - -/* - * Returns the next bash script for the minilinux. Else empty script. (Empty = bash will make reboot) - */ -noAuthRouter.get('/:uuid/nexthook', (req, res) => { - const uuid = req.params.uuid - db.client.findOne({ where: { uuid: uuid } }).then(client => { - // Return 404 if the client doesn't exist or it has no registration state. - if (client === null || client.registrationState === null) { - res.status(404).send() - return - } - db.registrationhook.findOne({ where: { id: client.registrationState } }).then(hook => { - if (hook.type !== 'BASH') { - res.send() - } else { - res.set('id', client.registrationState) - res.send(hook.script) - } - }) - }) -}) - -module.exports.noAuthRouter = noAuthRouter - -/* - * parentIds: - * sortvalue: - * - */ -function getNextHookScript (groupids, sortvalue) { - // Gets the list of all groupids inclusive the recursive parents. - return getRecursiveParents(groupids).then(gids => { - // Get the list of all hooks where the parent is null or those who fullfill the group dependency. - var options = { where: { '$groups.id$': { $or: [null, gids] } }, include: ['groups'], order: [['sortvalue', 'ASC']] } - if (sortvalue !== undefined) options.where.sortvalue = { $gt: sortvalue } - return db.registrationhook.findAll(options).then(result => { - var resID = null - if (result.length >= 1) resID = result[0].id - return resID - }) - }) -} - -/* - * groupids: Array of group ids to get the parents from. - * - * Returns a list of the grop ids and all recursive ids of their parents. - */ -function getRecursiveParents (groupIds) { - var gids = [] - return db.group.findAll({ where: { id: groupIds }, include: ['parents'] }).then(groups => { - groups.forEach(group => { - group.parents.forEach(parent => { - if (!groupIds.includes(parent.id) && !gids.includes(parent.id)) gids = [...gids, parent.id] - }) - }) - if (gids.length === 0) return groupIds - else { - return getRecursiveParents(gids).then(r => { - return groupIds.concat(r) - }) - } - }) -} - -/* - * id: id of the current selected location. - * name: Name of the current selected location - * groups: List of group [{ id: , name: }, ...] - * - * Build the ipxe menu out of the list of groups. - * Used by the manual registration. - */ -function buildIpxeMenu (id, name, groups, parents) { - var basUrl = 'https://bas.intra.uni-freiburg.de' - var script = '#!ipxe\r\n' - // script = script.concat(`console --picture \${img} --x 800 --y 600 || shell\r\n`) - - // Add parent to keep track of the path we clicked through. - var parentId = 0 - var oldParents = parents.slice(0) - if (parents.length > 0) { - parentId = oldParents[oldParents.length - 1].id - oldParents.length = oldParents.length - 1 - } - parents.push({ id: id, name: toAscii(name) }) - script += `set space:hex 20:20\r\n` - script += `set space \${space:string}\r\n` - script += `set parents ` + JSON.stringify(parents) + '\r\n\r\n' - - // Menu - var menuscript = '' - script += ':start\r\n' - script += 'menu Choose the group you want the client to be saved in\r\n' - - // Parent menu entries. - var spacer = '' - parents.forEach(parent => { - script += 'item --gap ' + spacer + '[' + parent.id + '] ' + parent.name + '\r\n' - spacer += `\${space}` - }) - - // Back button - script += 'item --key b back ' + spacer + '..\r\n' - menuscript += ':back\r\nparams\r\nparam id ' + parentId + '\r\nparam parents ' + JSON.stringify(oldParents) + '\r\n' - menuscript += 'chain --replace ' + basUrl + '/api/registrations/group##params\r\n\r\n' - - // Group menu entries. First 1-9 are pressable via key? - var counter = '1' - groups.forEach(group => { - script += 'item --key ' + counter + ' ' + counter + ' ' + spacer + '[' + group.id + '] ' + toAscii(group.name) + '\r\n' - menuscript += ':' + counter + '\r\n' + 'params\r\nparam id ' + group.id + `\r\nparam parents \${parents}\r\n` - menuscript += 'chain --replace ' + basUrl + '/api/registrations/group##params\r\n\r\n' - counter++ - }) - - // Menu seperator - script += 'item --gap\r\n' - - // Add client menu - script += 'item select Add client to ' + toAscii(name) + '\r\n' - menuscript += `:select\r\necho Enter client name\r\nread clientname\r\nparams\r\nparam name \${clientname}\r\n` - menuscript += 'param id ' + id + `\r\nparam mac \${net0/mac}\r\nparam uuid \${uuid}\r\nparam ip \${net0/ip}\r\n` - menuscript += 'chain --replace ' + basUrl + '/api/registrations/add##params\r\n\r\n' - - // Goto start menu - if (id !== '0') { - script += 'item reset Go to start\r\n' - menuscript += ':reset\r\nparams\r\nparam id ' + 0 + '\r\nchain --replace ' + basUrl + '/api/registrations/group##params\r\n\r\n' - } - - // Exit menu - script += 'item exit Exit manual registration\r\n' - menuscript += ':exit\r\nexit 1\r\n\r\n' - - // Concat script + menuscript and return it. - script += `choose target && goto \${target}\r\n\r\n` - script += menuscript - return script -} - -function toAscii (string) { - string = string.replace('ü', 'ue') - string = string.replace('ö', 'oe') - string = string.replace('ä', 'ae') - return ascii(string) -} - -/* eslint-disable */ -var escapable = /[\\"\x00-\x1f\x7f-\uffff]/g -/* eslint-enable */ -var meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"': '\\"', - '\\': '\\\\' -} - -function ascii (string) { -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. - - escapable.lastIndex = 0 - return escapable.test(string) - ? string.replace(escapable, function (a) { - var c = meta[a] - return typeof c === 'string' ? c - : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4) - }) : string -} diff --git a/server/ipxe/grepSystemInfo.sh b/server/ipxe/grepSystemInfo.sh index a0810be..386f3b2 100644 --- a/server/ipxe/grepSystemInfo.sh +++ b/server/ipxe/grepSystemInfo.sh @@ -29,7 +29,7 @@ CPU_TYPE=$(dmidecode -q -s processor-family) CPU_CORES=$(cat /sys/devices/system/cpu/cpu*/topology/thread_siblings_list | sort -u | wc -l) #CPUMODEL=$(grep -m1 '^model name\s*:' /proc/cpuinfo | sed 's/^model name\s*:\s*//;s/\s\s*/ /g;s/^ //;s/ $//') #echo "$CPUMODEL" -CPU_FREQUENCY=$(dmidecode -q -s processor-frequency) +CPU_FREQUENCY=$(dmidecode -q -s processor-frequency)registrations CPU_FREQUENCY=${CPU_FREQUENCY%" MHz"} # RAM @@ -63,5 +63,5 @@ done # 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" -H "Content-Type: application/x-www-form-urlencoded" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registrations/$UUID/update +#curl --data "state=6" --insecure https://bas.stfu-kthx.net:8888/api/registration/$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" -H "Content-Type: application/x-www-form-urlencoded" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registration/$UUID/update diff --git a/server/ipxe/registration.ipxe b/server/ipxe/registration.ipxe index c7fa24c..66e34e2 100644 --- a/server/ipxe/registration.ipxe +++ b/server/ipxe/registration.ipxe @@ -4,8 +4,8 @@ set crosscert http://ca.ipxe.org/auto/ #set img https://ife-server.com/b4db0y/ipxeWallpaper4.png || shell #set img tftp://bas.stfu-kthx.net/ipxeWallpaper4.png || shell -set img tftp://10.8.102.124/ipxeWallpaper3_scale.png || shell -console --picture ${img} --x 800 --y 600 || shell +#set img tftp://10.8.102.124/ipxeWallpaper3_scale.png || shell +#console --picture ${img} --x 800 --y 600 || shell :start menu Initializing client registration @@ -28,12 +28,12 @@ param mac ${net0/mac} param uuid ${uuid} param ip ${net0/ip} param purpose Pool PC -chain https://bas.intra.uni-freiburg.de/api/registrations/add##params +chain https://bas.intra.uni-freiburg.de/api/registration/add##params :manual params param id 0 -chain https://bas.intra.uni-freiburg.de/api/registrations/group##params || +chain https://bas.intra.uni-freiburg.de/api/registration/group##params || goto start :reboot -- cgit v1.2.3-55-g7522