summaryrefslogtreecommitdiffstats
path: root/server/api/registration.js
diff options
context:
space:
mode:
Diffstat (limited to 'server/api/registration.js')
-rw-r--r--server/api/registration.js298
1 files changed, 181 insertions, 117 deletions
diff --git a/server/api/registration.js b/server/api/registration.js
index 4897bb5..fd8b808 100644
--- a/server/api/registration.js
+++ b/server/api/registration.js
@@ -14,6 +14,7 @@ const log = require(path.join(__appdir, 'lib', 'log'))
const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse'))
// This is needed for parsing vendor/product codes
const pci = require(path.join(__appdir, 'lib', 'pci'))
+const EdidReader = require('edid-reader')
// Permission check middleware
router.all(['', '/hooks', '/:y', '/hooks/:x'], async (req, res, next) => {
@@ -183,134 +184,144 @@ noAuthRouter.post('/group', (req, res) => {
* Add method for adding a client or server.
*/
noAuthRouter.postAsync('/clients', async (req, res) => {
- let client = req.body.client
- if (typeof client === 'string') client = JSON.parse(client)
+ let client = {}
+
+ // Defines weather the answer is a ipxe script or json response
let ipxe = req.body.ipxe
if (typeof ipxe === 'string' && ipxe === 'true') ipxe = true
- let automatic = req.body.automatic
- if (typeof automatic === 'string' && automatic === 'true') automatic = true
- let confirmation = req.body.confirmation
- if (typeof confirmation === 'string' && confirmation === 'true') confirmation = true
-
- // If the client already exists return the configloader ipxe script.
- const clientDb = await db.client.findOne({ where: { uuid: client.uuid } })
- if (clientDb) {
- if (ipxe) return res.send(`#!ipxe\nchain https://` + url + `/api/configloader/\${uuid}`)
- else return res.send({ error: 'CLIENT_ALREADY_EXISTS', msg: 'A client with the provided UUID does already exist.' })
- }
-
- if (!client.type) client.type = 'CLIENT'
-
- // DHCP network stuff:
-
- // TODO: Multiip / backend problems
- // * Multiple backends possible ? multiple dhcp's? if set ip differentiates which one should we save in the bas db?
- // * Only servers have multiple ips? No multi leased ips possible?
-
- // If there is no ip, we don't need DHCP checks.
- // Only the first ip address is checked! client.networks[0]
let dhcp = false
- if (client.networks.length >= 1 && client.type === 'CLIENT') {
- const network = client.networks[0]
- // Get the dhcp backend. Only one dhcp backend can exist else -> conflict.
- dhcp = await backendHelper.getDhcp()
- let ipSelection = false
- let setIpError
- if (dhcp) {
- if (automatic) {
- // Set the name of the client if it's not set
- if (!client.name) {
- // Check the ip state in the dhcp
- const ipCheck = await dhcp.instance.checkIp(dhcp.backend.credentials, network.ip)
- // If it's not leased, set the hostname as clientname
- if (!ipCheck.error && !ipCheck.leased && ipCheck.name !== '') {
- if (ipCheck.name) client.name = ipCheck.name
- if (ipCheck.id) dhcp.ref = ipCheck.id
- } else {
- client.name = client.type + '_' + client.uuid
- const setIp = await dhcp.instance.setIp(dhcp.backend.credentials, network.ip, undefined, network.mac, undefined, true)
- // Check for errors.
- if (!setIp.error) {
- dhcp.ref = setIp.ref
- // Client ip set successfully
- client.networks[0].ip = setIp.ip
+ if (req.body.version && req.body.version >= 2) {
+ /* New hardware collection script */
+ client = await parseHardwareInformation(req.body)
+ } else {
+ client = req.body.client
+ if (typeof client === 'string') client = JSON.parse(client)
+ let automatic = req.body.automatic
+ if (typeof automatic === 'string' && automatic === 'true') automatic = true
+ let confirmation = req.body.confirmation
+ if (typeof confirmation === 'string' && confirmation === 'true') confirmation = true
+
+ // If the client already exists return the configloader ipxe script.
+ const clientDb = await db.client.findOne({ where: { uuid: client.uuid } })
+ if (clientDb) {
+ if (ipxe) return res.send(`#!ipxe\nchain https://` + url + `/api/configloader/\${uuid}`)
+ else return res.send({ error: 'CLIENT_ALREADY_EXISTS', msg: 'A client with the provided UUID does already exist.' })
+ }
+
+ // DHCP network stuff:
+
+ // TODO: Multiip / backend problems
+ // * Multiple backends possible ? multiple dhcp's? if set ip differentiates which one should we save in the bas db?
+ // * Only servers have multiple ips? No multi leased ips possible?
+
+ // If there is no ip, we don't need DHCP checks.
+ // Only the first ip address is checked! client.networks[0]
+ if (client.networks.length >= 1 && client.type === 'CLIENT') {
+ const network = client.networks[0]
+ // Get the dhcp backend. Only one dhcp backend can exist else -> conflict.
+ dhcp = await backendHelper.getDhcp()
+ let ipSelection = false
+ let setIpError
+ if (dhcp) {
+ if (automatic) {
+ // Set the name of the client if it's not set
+ if (!client.name) {
+ // Check the ip state in the dhcp
+ const ipCheck = await dhcp.instance.checkIp(dhcp.backend.credentials, network.ip)
+
+ // If it's not leased, set the hostname as clientname
+ if (!ipCheck.error && !ipCheck.leased && ipCheck.name !== '') {
+ if (ipCheck.name) client.name = ipCheck.name
+ if (ipCheck.id) dhcp.ref = ipCheck.id
} else {
- log({
- category: 'ERROR_DHCP',
- description: `[${dhcp.backend.id}] Error setting ip ${network.ip} for mac ${network.mac}\nError: ${setIp.msg}`
- })
+ client.name = client.type + '_' + client.uuid
+ const setIp = await dhcp.instance.setIp(dhcp.backend.credentials, network.ip, undefined, network.mac, undefined, true)
+ // Check for errors.
+ if (!setIp.error) {
+ dhcp.ref = setIp.ref
+ // Client ip set successfully
+ client.networks[0].ip = setIp.ip
+ } else {
+ log({
+ category: 'ERROR_DHCP',
+ description: `[${dhcp.backend.id}] Error setting ip ${network.ip} for mac ${network.mac}\nError: ${setIp.msg}`
+ })
+ }
}
}
- }
- } else if (network.dhcp) {
- // If networks.dhcp is set the user already choose the ip and we have to set it now.
- if (!network.dhcp.domain) {
- // Check if there are multiple domains.
- const domainList = await dhcp.instance.checkDomain(dhcp.backend.credentials)
- if (domainList.length > 1) return res.send(buildSelectDomainIpxeMenu(client, domainList))
- else network.dhcp.domain = domainList[0]
- }
- if (!client.name) return res.send(buildNameClientIpxeMenu(client))
- if (confirmation) return res.send(buildOverviewIpxeMenu(client))
-
- const setIp = await dhcp.instance.setIp(dhcp.backend.credentials, network.dhcp.ip, network.dhcp.domain, network.mac, client.name)
- dhcp.ref = setIp.id
- // Check for errors.
- if (setIp.error) {
- log({
- category: 'ERROR_DHCP',
- description: `[${dhcp.backend.id}] Error setting ip ${network.ip} for mac ${network.mac}\nError: ${setIp.msg}`
- })
-
- // Setting the client ip failed
- ipSelection = true
- delete client.networks[0].dhcp
- delete client.name
- setIpError = setIp.msg
+ } else if (network.dhcp) {
+ // If networks.dhcp is set the user already choose the ip and we have to set it now.
+ if (!network.dhcp.domain) {
+ // Check if there are multiple domains.
+ const domainList = await dhcp.instance.checkDomain(dhcp.backend.credentials)
+ if (domainList.length > 1) return res.send(buildSelectDomainIpxeMenu(client, domainList))
+ else network.dhcp.domain = domainList[0]
+ }
+ if (!client.name) return res.send(buildNameClientIpxeMenu(client))
+ if (confirmation) return res.send(buildOverviewIpxeMenu(client))
+
+ const setIp = await dhcp.instance.setIp(dhcp.backend.credentials, network.dhcp.ip, network.dhcp.domain, network.mac, client.name)
+ dhcp.ref = setIp.id
+ // Check for errors.
+ if (setIp.error) {
+ log({
+ category: 'ERROR_DHCP',
+ description: `[${dhcp.backend.id}] Error setting ip ${network.ip} for mac ${network.mac}\nError: ${setIp.msg}`
+ })
+
+ // Setting the client ip failed
+ ipSelection = true
+ delete client.networks[0].dhcp
+ delete client.name
+ setIpError = setIp.msg
+ } else {
+ // Client ip set successfully
+ client.networks[0].ip = network.dhcp.ip
+ client.networks[0].hostname = client.name
+ client.networks[0].domain = setIp.domain
+ }
} else {
- // Client ip set successfully
- client.networks[0].ip = network.dhcp.ip
- client.networks[0].hostname = client.name
- client.networks[0].domain = setIp.domain
+ ipSelection = true
}
- } else {
- ipSelection = true
- }
- if (ipSelection) {
- // If not: check if the client has a leased ipv4 address.
- const ipCheck = await dhcp.instance.checkIp(dhcp.backend.credentials, network.ip)
+ if (ipSelection) {
+ // If not: check if the client has a leased ipv4 address.
+ const ipCheck = await dhcp.instance.checkIp(dhcp.backend.credentials, network.ip)
- // Build ipxe and return
- if (ipxe && ipCheck.leased && !ipCheck.error) return res.send(buildSelectIpIpxeMenu(client, ipCheck.nextIps, setIpError))
- else if (!ipxe && ipCheck.leased && !ipCheck.error) return res.send({ client: client, ipList: ipCheck.nextIps })
+ // Build ipxe and return
+ if (ipxe && ipCheck.leased && !ipCheck.error) return res.send(buildSelectIpIpxeMenu(client, ipCheck.nextIps, setIpError))
+ else if (!ipxe && ipCheck.leased && !ipCheck.error) return res.send({ client: client, ipList: ipCheck.nextIps })
- // Set the hostname as clientname if it exists and is not a leased ip.
- if (!ipCheck.leased && ipCheck.name) {
- if (ipCheck.name) client.name = ipCheck.name
- if (ipCheck.id) dhcp.ref = ipCheck.id
- } else {
- // Leased ip but no hostname? --> Maybe not waited long enough after DHCP deletion
- let date = new Date()
- const tenMin = 1000 * 60 * 10
- const fiveMin = 1000 * 60 * 5
- // Round up to the next 10-min mark for the error msg
- // === Add 5 min to the time and round to the nearest one
- const rounded = new Date(Math.round((date.getTime() + fiveMin) / tenMin) * tenMin)
-
- return res.send(buildNameClientIpxeMenu(client, ['Client has a fixed IP but NO hostname was found.', 'Infoblox might not be ready after client deletion.', `Wait until ${rounded.toTimeString()} or enter a name and continue anyways ...`]))
+ // Set the hostname as clientname if it exists and is not a leased ip.
+ if (!ipCheck.leased && ipCheck.name) {
+ if (ipCheck.name) client.name = ipCheck.name
+ if (ipCheck.id) dhcp.ref = ipCheck.id
+ } else {
+ // Leased ip but no hostname? --> Maybe not waited long enough after DHCP deletion
+ let date = new Date()
+ const tenMin = 1000 * 60 * 10
+ const fiveMin = 1000 * 60 * 5
+ // Round up to the next 10-min mark for the error msg
+ // === Add 5 min to the time and round to the nearest one
+ const rounded = new Date(Math.round((date.getTime() + fiveMin) / tenMin) * tenMin)
+
+ return res.send(buildNameClientIpxeMenu(client, ['Client has a fixed IP but NO hostname was found.', 'Infoblox might not be ready after client deletion.', `Wait until ${rounded.toTimeString()} or enter a name and continue anyways ...`]))
+ }
+ }
+ } else { // End of DHCP Stuff
+ if (automatic) {
+ client.name = client.type + '_' + client.uuid
}
- }
- } else { // End of DHCP Stuff
- if (automatic) {
- client.name = client.type + '_' + client.uuid
}
}
}
// Client does not exist.
if (!client.parents) client.parents = []
+ if (!client.name) client.name = client.type + '_' + client.uuid
+ if (!client.type) client.type = 'CLIENT'
+
// TODO: Save all IPs? Maybe only primary ip?
const createClient = { name: client.name, description: client.type, ip: client.networks[0].ip, mac: client.networks[0].mac, uuid: client.uuid }
if (client.type === 'CLIENT') createClient.registrationState = await getNextHookScript(client.parents)
@@ -495,7 +506,7 @@ function getRecursiveParents (groupIds) {
async function parseHardwareInformation (data) {
let client = {
'parents': [], // TODO:
- 'type': '', // SERVER OR CLIENT
+ 'type': data.type ? data.type : 'CLIENT', // SERVER OR CLIENT
'uuid': '',
'networks': [], // { 'mac': '', 'ip': '' }
'system': {
@@ -509,8 +520,11 @@ async function parseHardwareInformation (data) {
'isEcc': false
},
'drives': [],
- 'gpus': []
+ 'gpus': [],
+ 'monitors': [],
+ 'contacts': []
}
+ if (data.name) client.name = data.name
// TODO: Rack and Bay stuff
@@ -641,9 +655,9 @@ async function parseHardwareInformation (data) {
let network = {
'name': ip.ifname,
'mac': ip.address,
- 'ip': '',
- 'ipv6': '',
- 'hostname': ''
+ 'ip': undefined,
+ 'ipv6': undefined,
+ 'hostname': undefined
}
for (let addr of ip['addr_info']) {
@@ -671,6 +685,25 @@ async function parseHardwareInformation (data) {
}
/* edid */
+ for (let rawEdid of data.edid) {
+ const edid = EdidReader.parse(rawEdid.edid)
+ client.monitors.push({
+ model: edid.modelName,
+ vendor: edid.vendor,
+ serialnumber: edid.serialNumber,
+ modes: edid.standardDisplayModes,
+ port: rawEdid.path.split('/')[4].substring(6),
+ resolution: {
+ width: edid.dtds[0].horActivePixels,
+ height: edid.dtds[0].vertActivePixels
+ },
+ dimensions: {
+ width: edid.displaySize[0],
+ height: edid.displaySize[1],
+ inch: Math.round(Math.sqrt(Math.pow(edid.displaySize[0], 2) + Math.pow(edid.displaySize[1], 2)) / 25.4)
+ }
+ })
+ }
/* lshw */
if (data.lshw && data.lshw.length > 0) {
@@ -681,15 +714,46 @@ async function parseHardwareInformation (data) {
client.gpus.push({
'manufacturer': gpu.vendor,
'model': gpu.product
- /*,
- 'memory': ,
- 'unit':
+ /*
+ 'memory': undefined,
+ 'unit': undefined,
*/
})
}
}
}
+ /* Contacts */
+ if (data.contacts && data.contacts.length > 0) {
+ for (let contact of data.contacts) {
+ client.contacts.push({
+ 'firstname': contact.firstname,
+ 'lastname': contact.lastname
+ })
+ }
+ }
+
+ /* Location */
+ if (data.location) {
+ // Server might get an name of the rack instead of an id
+ if (typeof data.location.parent === 'string' && isNaN(data.location.parent)) {
+ // Parent is not a number, so get the BAS ID for the object
+ const parent = await db.group.findOne({ where: { name: data.location.parent } })
+ // findOne only returns the first object with the matching name, so if the name isn't unique id should be used
+ client.parents.push(parent.id)
+ }
+
+ // Add bay and slot if given
+ if (data.location.bay || data.location.slot) {
+ client.location = {
+ ...(data.location.slot && {
+ slot: data.location.slot,
+ bay: data.location.bay ? data.location.bay : 0
+ })
+ }
+ }
+ }
+
return client
}