/* global __appdir */ const path = require('path') const fs = require('fs') const db = require(path.join(__appdir, 'lib', 'sequelize')) const eventHelper = require(path.join(__appdir, 'lib', 'eventhelper')) const config = require(path.join(__appdir, 'config', 'config')) const url = config.https.host + ':' + config.https.port async function getConfig (uuid, list) { const client = await db.client.findOne({ where: { uuid: uuid }, include: ['groups', 'events'] }) let configPath = [] // client not known, start registration if (client === null) { let config = { id: 'REGISTRATION', name: 'Registration Script' } if (!list) { config.script = fs.readFileSync(path.join(__appdir, 'ipxe', 'registration.ipxe'), 'utf8') return config } configPath.push(config) return configPath } // Client is in db, check for registration hooks. if (client.registrationState !== null) { // client is in registration state, load scripts var hook = await db.registrationhook.findOne({ where: { id: client.registrationState } }) let config = { id: 'HOOK', name: 'hook.name', hookId: hook.id, hookType: hook.type } if (!list) { if (hook.type === 'IPXE') { config.script = hook.script } else if (hook.type === 'BASH') { config.script = fs.readFileSync(path.join(__appdir, 'ipxe', 'minilinux.ipxe'), 'utf8') } return config } configPath.push(config) } // Check for event or direct configs let importantList = [] let eventList = [] let configList = [] await _checkParentConfigs(client.id, importantList, eventList, configList, !list) if (!list) { if (importantList.length) return importantList[0] else if (eventList.length) return eventList[0] else if (configList.length) return configList[0] } else { configPath = configPath.concat(importantList, eventList, configList) } // No config found, use default config let config = await _prepareConfig({ id: 'DEFAULT', source: { type: 'DEFAULT' } }) if (!list) return config configPath.push(config) return configPath } async function _checkParentConfigs (ids, importantList, eventList, configList, breakOnImportant, blackList = []) { let events = [] let configs = [] if (Array.isArray(ids)) { events = await db.event.findAll({ where: { '$groups.id$': ids }, include: ['groups', 'config'] }) let groups = await db.group.findAll({ where: { id: ids }, include: ['config'] }) groups.forEach(group => { if (group.configId) configs.push({ id: group.configId, source: { type: 'GROUP', id: group.id, name: group.name } }) }) } else { events = await db.event.findAll({ where: { '$clients.id$': ids }, include: ['clients', 'config'] }) let client = await db.client.findOne({ where: { id: ids }, include: ['config'] }) if (client && client.configId) configs = [{ id: client.configId, source: { type: 'CLIENT', id: client.id, name: client.name } }] } let importants = [] let nonImportants = [] events.forEach(event => { let eventTimes = JSON.parse(event.times) if (!eventHelper.isActive(eventTimes)) return if ((event.groups && event.groups.some(group => group.group_x_event.blacklist)) || (event.clients && event.clients.length && event.clients[0].client_x_event.blacklist)) { return blackList.push(event.id) } if (blackList.includes(event.id) || !event.configId) return let config = { id: event.configId, source: { type: event.important ? 'IMPORTANT_EVENT' : 'EVENT', id: event.id, name: event.name } } if (event.groups) config.source.groups = event.groups.map(x => ({ id: x.id, name: x.name })) if (event.important) importants.push(config) else nonImportants.push(config) }) if (importants.length > 1) importantList.push(await _createDynamicMenu(importants)) else if (importants.length === 1) importantList.push(await _prepareConfig(importants[0])) if (breakOnImportant && importantList.length) return if (nonImportants.length > 1) eventList.push(await _createDynamicMenu(nonImportants)) else if (nonImportants.length === 1) eventList.push(await _prepareConfig(nonImportants[0])) if (configs.length > 1) configList.push(await _createDynamicMenu(configs)) else if (configs.length === 1) configList.push(await _prepareConfig(configs[0])) let parents = [] if (Array.isArray(ids)) { parents = await db.group.findAll({ where: { '$subgroups.id$': ids }, include: ['subgroups'] }) } else { parents = await db.group.findAll({ where: { '$clients.id$': ids }, include: ['clients'] }) } if (parents.length) await _checkParentConfigs(parents.map(x => x.id), importantList, eventList, configList, breakOnImportant, blackList) } // create the config script from database async function _prepareConfig (configInfo, noScript) { let id = configInfo.id // If no id is given, find the default config const where = {} if (id === 'DEFAULT') where.isDefault = true else where.id = id const config = await db.config.findOne({ where, include: ['entries'], order: [[db.config.associations.entries, db.config.associations.entries.through, 'sortValue', 'ASC']] }) if (!config) return configInfo const result = { id: config.id, name: config.name, source: configInfo.source } if (noScript) return result if (config.script !== null && config.script !== '') { result.script = config.script return result } var script = '' var menuscript = '' script += '#!ipxe\r\n\r\n' script += ':start\r\n' script += 'menu ' + config.name + '\r\n' config.entries.forEach(entry => { script += 'item' if (entry.config_x_entry.keyBind !== null) { script += ' --key ' + entry.config_x_entry.keyBind } script += ' menuentry' + entry.id + ' ' if (entry.config_x_entry.customName !== null && entry.config_x_entry.customName !== '') { script += entry.config_x_entry.customName } else { script += entry.name } script += '\r\n' menuscript += ':' + 'menuentry' + entry.id + '\r\n' menuscript += entry.script + '\r\n\r\n' }) script += 'choose ' if (config.defaultEntry !== null && config.timeout !== null) { script += '--default menuentry' + config.defaultEntry + ' --timeout ' + config.timeout + ' ' } script += `target && goto \${target}\r\n\r\n` script += menuscript result.script = script return result } // create dynamic menu to load the different given configs for a client async function _createDynamicMenu (configInfos, noScript) { const ids = [] const idSourceMap = {} configInfos.forEach(configInfo => { ids.push(configInfo.id) idSourceMap[configInfo.id] = configInfo.source }) const configs = await db.config.findAll({ where: { id: ids } }) const result = { merged: true, id: JSON.stringify(configs.map(x => x.id)), configs: configs.map(x => ({ id: x.id, name: x.name, source: idSourceMap[x.id] })) } if (noScript) return result var script = '' var menuscript = '' var defaultentry = '' script += '#!ipxe\r\n\r\n' script += ':start\r\n' script += 'menu ' + 'Choose one configuration to boot' + '\r\n' configs.forEach(config => { script += 'item ' script += ' menuentry' + config.id + ' ' script += config.name script += '\r\n' // Last script processed is default script defaultentry = 'menuentry' + config.id menuscript += ':' + 'menuentry' + config.id + '\r\n' menuscript += 'chain ' + 'https://' + url + '/api/configloader/getconfig/' + config.id + '\r\n\r\n' }) script += 'choose --default ' + defaultentry + ' ' script += '--timeout 15 ' script += `target && goto \${target}\r\n\r\n` script += menuscript result.script = script return result } module.exports = { getConfig }