summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUdo Walter2019-11-27 18:20:15 +0100
committerUdo Walter2019-11-27 18:20:15 +0100
commitf28f21b2f67f5e152e6e9d13814150a4adf316c7 (patch)
tree263c88400d5061d0660cde0f20b44ceeefcabaa3
parent[server/external-backends/infoblox] Add infoblox fix for a client registratio... (diff)
downloadbas-f28f21b2f67f5e152e6e9d13814150a4adf316c7.tar.gz
bas-f28f21b2f67f5e152e6e9d13814150a4adf316c7.tar.xz
bas-f28f21b2f67f5e152e6e9d13814150a4adf316c7.zip
[configloader] bugfixes in the beta configloader:
add hook sources correct handeling of multiple sources remove merging of multiple sources with the same config
-rw-r--r--server/api/configloader.js18
-rw-r--r--server/lib/confighelper.js187
-rw-r--r--webapp/src/components/ConfigChip.vue47
3 files changed, 155 insertions, 97 deletions
diff --git a/server/api/configloader.js b/server/api/configloader.js
index ba395d0..dc3a29d 100644
--- a/server/api/configloader.js
+++ b/server/api/configloader.js
@@ -7,10 +7,12 @@ var noAuthRouter = decorateApp(express.Router())
const config = require(path.join(__appdir, 'config', 'config'))
const url = config.https.host + ':' + config.https.port
const configHelper = require(path.join(__appdir, 'lib', 'confighelper'))
+const log = require(path.join(__appdir, 'lib', 'log'))
noAuthRouter.getAsync(['/test/group/:id', '/test/group/'], async (req, res) => {
const list = req.query.list !== undefined && req.query.list !== 'false'
- const config = await configHelper.getGroupConfig(req.params.id, list)
+ const group = await db.group.findOne({ where: { id: req.params.id } })
+ const config = await configHelper.getGroupConfig(group, list)
if (!config) return res.status(404).end()
if (!list) {
res.set('Content-Type', 'text/plain')
@@ -22,8 +24,18 @@ noAuthRouter.getAsync(['/test/group/:id', '/test/group/'], async (req, res) => {
noAuthRouter.getAsync(['/test/:uuid', '/test/'], async (req, res) => {
const list = req.query.list !== undefined && req.query.list !== 'false'
- const config = await configHelper.getConfig(req.params.uuid, list)
+ const client = await db.client.findOne({ where: { uuid: req.params.uuid } })
+ const config = await configHelper.getConfig(client, list)
if (!list) {
+ const logEntry = {
+ category: 'CLIENT_BOOT',
+ description: 'Client booted iPXE config [' + config.id + '] ' + config.name + '.\n' +
+ 'Client UUID: ' + req.params.uuid + '\n' +
+ 'Config ID: ' + config.id + '\n' +
+ 'Config Name: ' + config.name,
+ }
+ if (client) logEntry.clientId = client.id
+ log(logEntry)
res.set('Content-Type', 'text/plain')
res.send(config.script)
} else {
@@ -125,7 +137,7 @@ noAuthRouter.getAsync('/:uuid', async (req, res) => {
}
// No config found, use default config
// await sendFilePromise(res, path.join(__appdir, 'ipxe', 'default.ipxe'))
- res.send(await configHelper.getDefaultConfig(client))
+ res.send(configHelper.getDefaultConfig(client))
})
// load config by given id
diff --git a/server/lib/confighelper.js b/server/lib/confighelper.js
index 5843725..6773bd0 100644
--- a/server/lib/confighelper.js
+++ b/server/lib/confighelper.js
@@ -3,11 +3,11 @@ 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
+const serverConfig = require(path.join(__appdir, 'config', 'config'))
+const url = serverConfig.https.host + ':' + serverConfig.https.port
-async function getConfig (uuid, list) {
- const client = await db.client.findOne({ where: { uuid: uuid } })
+
+async function getConfig (client, list) {
let configPath = []
// client not known, start registration
@@ -25,7 +25,7 @@ async function getConfig (uuid, list) {
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 }
+ let config = { id: 'HOOK' + hook.id, name: hook.name, source: { type: hook.type + '_HOOK', id: hook.id, name: hook.name, } }
if (!list) {
if (hook.type === 'IPXE') {
config.script = hook.script
@@ -34,123 +34,139 @@ async function getConfig (uuid, list) {
}
return config
}
+ if (hook.type === 'BASH') config.name = 'Minilinux'
+ else config.name = hook.name
configPath.push(config)
}
// Check for event or direct configs
- let importantList = []
- let eventList = []
- let configList = []
- await _checkParentConfigs(client.id, importantList, eventList, configList, !list)
+ const configs = await _checkParentConfigs(client.id, !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.push(...importantList, ...eventList, ...configList)
+ if (configs.length) {
+ if (!list) return configs[0]
+ else configPath.push(...configs)
}
// No config found, use default config
let config = await _prepareConfig({ id: 'DEFAULT', source: { type: 'DEFAULT' } })
+ if (config === null) config = { id: 'DEFAULT', name: 'Fallback Default', script: getDefaultConfig(client), source: { type: 'DEFAULT' } }
+
if (!list) return config
configPath.push(config)
return configPath
}
-async function getGroupConfig (groupId, list) {
- const group = await db.group.findOne({ where: { id: groupId } })
+
+async function getGroupConfig (group, list) {
if (!group) return
let configPath = []
// Check for event or direct configs
- let importantList = []
- let eventList = []
- let configList = []
- await _checkParentConfigs([group.id], importantList, eventList, configList, !list)
+ const configs = await _checkParentConfigs(group.id, !list, false)
if (!list) {
- if (importantList.length) return importantList[0]
- else if (eventList.length) return eventList[0]
- else if (configList.length) return configList[0]
+ if (configs.length) return configs[0]
} else {
- configPath.push(...importantList, ...eventList, ...configList)
+ configPath.push(...configs)
}
// No config found, use default config
let config = await _prepareConfig({ id: 'DEFAULT', source: { type: 'DEFAULT' } })
+ if (config === null) config = { id: 'DEFAULT', name: 'Fallback Default', script: getDefaultConfig({}), 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 } }]
- }
+async function _checkParentConfigs (id, breakOnImportant, isClient = true) {
+ const importantList = []
+ const eventList = []
+ const configList = []
+ const blackList = []
+ const seenGroupsList = isClient ? [] : [id]
+ let parents = isClient ? [] : [id]
- let importants = []
- let nonImportants = []
+ do {
- events.forEach(event => {
- let eventTimes = JSON.parse(event.times)
- if (!eventHelper.isActive(eventTimes)) return
+ let events = []
+ let configs = []
- 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 (isClient) {
+ events = await db.event.findAll({ where: { '$clients.id$': id }, include: ['clients', 'config'] })
+ let client = await db.client.findOne({ where: { id: id }, include: ['config'] })
+ if (client && client.configId) configs = [{ id: client.configId, source: { type: 'CLIENT', id: client.id, name: client.name } }]
+ } else {
+ events = await db.event.findAll({ where: { '$groups.id$': parents }, include: ['groups', 'config'] })
+ let groups = await db.group.findAll({ where: { id: parents }, include: ['config'] })
+ groups.forEach(group => {
+ if (group.configId) configs.push({ id: group.configId, source: { type: 'GROUP', id: group.id, name: group.name } })
+ })
}
- if (blackList.includes(event.id) || !event.configId) return
+ let importants = []
+ let nonImportants = []
+
+ events.forEach(event => {
+ let eventTimes = JSON.parse(event.times)
+ if (!eventHelper.isActive(eventTimes)) return
- let config = {
- id: event.configId,
- source: {
- type: event.important ? 'IMPORTANT_EVENT' : 'EVENT',
- id: event.id,
- name: event.name
+ 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 (event.groups) config.source.groups = event.groups.map(x => ({ id: x.id, name: x.name }))
+ if (blackList.includes(event.id) || !event.configId) return
- if (event.important) importants.push(config)
- else nonImportants.push(config)
- })
+ let config = {
+ id: event.configId,
+ source: {
+ type: event.important ? 'IMPORTANT_EVENT' : 'EVENT',
+ id: event.id,
+ name: event.name
+ }
+ }
- if (importants.length > 1) importantList.push(await _createDynamicMenu(importants))
- else if (importants.length === 1) importantList.push(await _prepareConfig(importants[0]))
+ if (event.groups) config.source.groups = event.groups.map(x => ({ id: x.id, name: x.name }))
- if (breakOnImportant && importantList.length) return
+ if (event.important) importants.push(config)
+ else nonImportants.push(config)
+ })
- if (nonImportants.length > 1) eventList.push(await _createDynamicMenu(nonImportants))
- else if (nonImportants.length === 1) eventList.push(await _prepareConfig(nonImportants[0]))
+ if (importants.length > 1) importantList.push(await _createDynamicMenu(importants))
+ else if (importants.length === 1) importantList.push(await _prepareConfig(importants[0]))
- if (configs.length > 1) configList.push(await _createDynamicMenu(configs))
- else if (configs.length === 1) configList.push(await _prepareConfig(configs[0]))
+ if (breakOnImportant && importantList.length) break
- 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)
+ 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]))
+
+
+ if (isClient) {
+ parents = (await db.group.findAll({ where: { '$clients.id$': id }, include: ['clients'] })).map(x => x.id)
+ isClient = false
+ } else {
+ parents = (await db.group.findAll({ where: { '$subgroups.id$': parents }, include: ['subgroups'] })).map(x => x.id)
+ }
+
+ for (let i = parents.length - 1; i >= 0; i--) {
+ if (seenGroupsList.includes(parents[i])) parents.splice(i, 1)
+ }
+
+ seenGroupsList.push(...parents)
+
+ } while (parents.length)
+
+ return [...importantList, ...eventList, ...configList]
}
+
// create the config script from database
async function _prepareConfig (configInfo, noScript) {
let id = configInfo.id
@@ -161,7 +177,7 @@ async function _prepareConfig (configInfo, noScript) {
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
+ if (!config) return null
const result = { id: config.id, name: config.name, source: configInfo.source }
@@ -201,19 +217,30 @@ async function _prepareConfig (configInfo, noScript) {
return result
}
+
// create dynamic menu to load the different given configs for a client
async function _createDynamicMenu (configInfos, noScript) {
const ids = []
const idSourceMap = {}
- console.log(configInfos)
+ for (let i in configInfos) {
+ let id = configInfos[i].id
+ let source = configInfos[i].source
+
+ if (!ids.includes(id)) ids.push(id)
+
+ if (idSourceMap[id] === undefined) idSourceMap[id] = source
+ else if (Array.isArray(idSourceMap[id])) idSourceMap[id].push(source)
+ else idSourceMap[id] = [idSourceMap[id], source]
+ }
- configInfos.forEach(configInfo => {
- ids.push(configInfo.id)
- idSourceMap[configInfo.id] = configInfo.source
+ if (ids.length === 1) return await _prepareConfig({
+ id: ids[0],
+ source: idSourceMap[ids[0]]
})
const configs = await db.config.findAll({ where: { id: ids } })
+
const result = {
merged: true,
id: JSON.stringify(configs.map(x => x.id)),
@@ -249,8 +276,9 @@ async function _createDynamicMenu (configInfos, noScript) {
return result
}
+
// Creates a default overview config, when there is no default config in the frontend.
-async function getDefaultConfig (client) {
+function getDefaultConfig (client) {
let script = '#!ipxe\r\n\r\n'
script += ':start\r\n'
script += 'menu ' + 'Client is successfully registrated' + '\r\n'
@@ -280,4 +308,5 @@ async function getDefaultConfig (client) {
return script
}
+
module.exports = { getConfig, getGroupConfig, getDefaultConfig }
diff --git a/webapp/src/components/ConfigChip.vue b/webapp/src/components/ConfigChip.vue
index f278fe3..7ae0d08 100644
--- a/webapp/src/components/ConfigChip.vue
+++ b/webapp/src/components/ConfigChip.vue
@@ -27,25 +27,18 @@
<div>
<div v-if="active" class="success--text" style="text-align: center; font-weight: bold; font-size: 1.2em">{{ $t('active') }}</div>
<div v-if="assigned" class="primary--text" style="text-align: center; font-weight: bold; font-size: 1.2em">{{ $t('assigned') }}</div>
- <div v-if="config.source">
- <table>
- <tr><td class="config-source-key">{{ $t('source') }}</td><td>{{ config.source.type }}</td></tr>
- <tr v-if="config.source.id"><td class="config-source-key">{{ $t('id') }}</td><td>{{ config.source.id }}</td></tr>
- <tr v-if="config.source.name"><td class="config-source-key">{{ $t('name') }}</td><td>{{ config.source.name }}</td></tr>
- </table>
- </div>
- <div v-else-if="config.configs">
- <div v-for="(subConfig, index) in config.configs" :key="subConfig.id">
+ <v-divider v-if="active || assigned" style="margin-bottom: 4px"></v-divider>
+ <div>
+ <div v-for="(source, index) in sources" :key="source.data.id">
<v-divider v-if="index > 0" style="margin-bottom: 4px"></v-divider>
- <div style="text-align: center; font-weight: bold;">[{{ subConfig.id}}] {{ subConfig.name }}</div>
+ <div style="text-align: center; font-weight: bold;">{{ source.title }}</div>
<table>
- <tr><td class="config-source-key">{{ $t('source') }}</td><td>{{ subConfig.source.type }}</td></tr>
- <tr v-if="subConfig.source.id"><td class="config-source-key">{{ $t('id') }}</td><td>{{ subConfig.source.id }}</td></tr>
- <tr v-if="subConfig.source.name"><td class="config-source-key">{{ $t('name') }}</td><td>{{ subConfig.source.name }}</td></tr>
+ <tr><td class="config-source-key">{{ $t('source') }}</td><td>{{ source.data.type }}</td></tr>
+ <tr v-if="source.data.id"><td class="config-source-key">{{ $t('id') }}</td><td>{{ source.data.id }}</td></tr>
+ <tr v-if="source.data.name"><td class="config-source-key">{{ $t('name') }}</td><td>{{ source.data.name }}</td></tr>
</table>
</div>
</div>
- <span v-else>{{ config.name || config.id }}</span>
</div>
</v-tooltip>
</template>
@@ -79,10 +72,34 @@ export default {
return ''
},
isEvent () {
- return this.config.source && (this.config.source.type === 'IMPORTANT_EVENT' || this.config.source.type === 'EVENT')
+ return this.sources.some(source => (source.data.type === 'IMPORTANT_EVENT' || source.data.type === 'EVENT'))
+ },
+ sources () {
+ return this.getSources(this.config)
}
},
methods: {
+ getSources (config) {
+ const sources = []
+ if (config.merged) {
+ config.configs.forEach(c => {
+ sources.push(...this.getSources(c))
+ })
+ } else {
+ if (Array.isArray(config.source)) {
+ sources.push(...config.source.map(source => ({
+ title: '[' + config.id + '] ' + config.name,
+ data: source
+ })))
+ } else {
+ sources.push({
+ title: '[' + config.id + '] ' + config.name,
+ data: config.source
+ })
+ }
+ }
+ return sources
+ }
}
}
</script>