summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/.gitignore3
-rw-r--r--server/api/ipxe.js31
-rw-r--r--server/lib/shell.js107
-rw-r--r--webapp/src/components/IpxeBuilderModuleConfig.vue46
4 files changed, 132 insertions, 55 deletions
diff --git a/server/.gitignore b/server/.gitignore
index 3e9d832..66af4f4 100644
--- a/server/.gitignore
+++ b/server/.gitignore
@@ -4,6 +4,9 @@
/config/*
!/config/*.template.json
+/ipxe/ipxe_*
+/ipxe/log_*
+
.DS_Store
node_modules/
/public/
diff --git a/server/api/ipxe.js b/server/api/ipxe.js
index 549eb6f..5d95fa2 100644
--- a/server/api/ipxe.js
+++ b/server/api/ipxe.js
@@ -7,10 +7,6 @@ var router = express.Router()
var noAuthRouter = express.Router()
// GET requests.
-router.get('/build', (req, res) => {
- shell.buildIpxe(req, res)
-})
-
router.get('/:version/script', (req, res) => {
res.setHeader('content-type', 'text/plain')
res.sendFile(path.join(__appdir, 'ipxe', 'embedded_' + req.params.version + '.ipxe'))
@@ -64,14 +60,31 @@ router.put('/:version/:filename', (req, res) => {
* @return: Rebuild the ipxe.
*/
router.get('/:version/build', async (req, res) => {
- if (req.params.version === 'efi' || req.params.version === 'bios') await shell.buildIpxe(req, res)
- res.status(200).send({ status: 'success' })
+ if (req.params.version === 'efi' || req.params.version === 'bios') {
+ shell.buildIpxe(req, res)
+ } else {
+ res.status(400).send({ status: 'error', msg: 'Unknown ipxe version (' + req.params.version + ')' })
+ }
+})
+
+noAuthRouter.get('/:version/stop', async (req, res) => {
+ if (req.params.version === 'efi' || req.params.version === 'bios') {
+ shell.stopBuilding(req, res)
+ } else {
+ res.status(400).send({ status: 'error', msg: 'Unknown ipxe version (' + req.params.version + ')' })
+ }
})
router.get('/:version/clean', (req, res) => {
- if (req.params.version === 'efi') shell.clean('efi')
- else if (req.params.version === 'bios') shell.clean('bios')
- res.send()
+ if (req.params.version === 'efi' || req.params.version === 'bios') {
+ shell.clean(req, res)
+ } else {
+ res.status(400).send({ status: 'error', msg: 'Unknown ipxe version (' + req.params.version + ')' })
+ }
+})
+
+router.get('/:version/status', (req, res) => {
+ res.send({ status: 'SUCCESS', data: shell.status(req.params.version) })
})
module.exports.router = router
diff --git a/server/lib/shell.js b/server/lib/shell.js
index 080e5d6..8d609e4 100644
--- a/server/lib/shell.js
+++ b/server/lib/shell.js
@@ -1,18 +1,33 @@
-// Those packages needs to be installed to build ipxe:
-// sudo apt install liblzma-dev
-// sudo apt install mkisofs
-
/* global __appdir */
var path = require('path')
var shell = require('shelljs')
+// var child = require('child_process')
var ipxeGIT = 'git://git.ipxe.org/ipxe.git'
var io = require(path.join(__appdir, 'lib', 'socketio'))
const fs = require('fs')
+// Only one building process per version at a time.
+var building = { efi: false, bios: false }
+var make = {}
+
module.exports = {
buildIpxe: async function (req, res) {
const ipxeVersion = req.params.version
+ // Different make commands for efi / bios are needed.
+ var makeCmd = ''
+ // Only one building process can be running.
+ if (!building[ipxeVersion]) {
+ makeCmd = 'make bin-x86_64-efi/snponly.efi EMBED=' + path.join(__appdir, 'ipxe', 'embedded_' + ipxeVersion + '.ipxe') + ' TRUST=' + path.join(__appdir, 'bin', 'fullchain.pem')// + ' bin/undionly.kpxe'
+ updateInProgress(ipxeVersion, true)
+ } else {
+ res.send({ status: 'ALREADY_BUILDING', error: 'Building ' + ipxeVersion + '-iPXE is already in progress.' })
+ return
+ }
+
+ // Sending feedback, that the ipxe building progress started.
+ res.status(200).send({ status: 'SUCCESS', msg: 'Starting iPXE building process' })
+
// Cloning git.
sendToLog(ipxeVersion, 'Cloning git ...\n', 'primary')
await cloneIpxe(ipxeVersion)
@@ -25,20 +40,18 @@ module.exports = {
sendToLog(ipxeVersion, 'Make iPXE ...\n', 'primary')
shell.cd(path.join(__appdir, 'ipxe', 'ipxe_' + ipxeVersion, 'src'))
- // Different make command for efi / bios are needed.
- var makeCmd = ''
- if (ipxeVersion === 'efi') makeCmd = 'make bin-x86_64-efi/snponly.efi EMBED=' + path.join(__appdir, 'ipxe', 'embedded_' + ipxeVersion + '.ipxe') + ' TRUST=' + path.join(__appdir, 'bin', 'fullchain.pem')// + ' bin/undionly.kpxe'
- else if (ipxeVersion === 'bios') makeCmd = 'make EMBED=' + path.join(__appdir, 'ipxe', 'embedded_' + ipxeVersion + '.ipxe') + ' TRUST=' + path.join(__appdir, 'bin', 'fullchain.pem')// + ' bin/undionly.kpxe'
await new Promise((resolve, reject) => {
- var make = shell.exec(makeCmd, { async: true }, () => {
+ make[ipxeVersion] = shell.exec(makeCmd, { async: true }, () => {
+ // make[ipxeVersion] = child.exec(makeCmd, { async: true }, () => {
+ updateInProgress(ipxeVersion, false)
resolve()
})
// Send the output to the frontend log.
- make.stdout.on('data', data => {
+ make[ipxeVersion].stdout.on('data', data => {
sendToLog(ipxeVersion, data, 'normal')
})
- make.stderr.on('data', data => {
+ make[ipxeVersion].stderr.on('data', data => {
sendToLog(ipxeVersion, data, 'error')
})
})
@@ -48,19 +61,50 @@ module.exports = {
shell.mv(path.join(__appdir, 'ipxe', 'undionly.kpxe'), path.join(__appdir, 'ipxe', 'ipxe.' + ipxeVersion))
},
- clean: async function (ipxeVersion) {
+ stopBuilding: async function (req, res) {
+ // TODO: KILLING IS NOT WORKING.. fml
+ const process = make[req.params.version]
+ console.log(process)
+ if (process) {
+ console.log('KILLING IT °_°')
+ // process.stdin.pause()
+ // shell.kill(process.pid, 'SIGINT')
+ // const kill = 'kill -2 ' + process.pid
+ // console.log(kill)
+ // shell.exec(kill)
+ // process.kill("SIGINT")
+ // child.exec("kill -2 " + process.pid)
+ }
+ res.send({ status: 'SUCCESS', data: process })
+ },
+
+ clean: async function (req, res) {
+ const ipxeVersion = req.params.version
+ if (building[ipxeVersion]) {
+ res.send({ status: 'ALREADY_BUILDING', error: 'Can\'t clean, while building' + ipxeVersion + '-iPXE is in progress.' })
+ return
+ } else {
+ updateInProgress(ipxeVersion, true)
+ res.send({ status: 'SUCCESS', msg: 'Cleaning iPXE started' })
+ }
+
shell.cd(path.join(__appdir, 'ipxe'))
shell.rm('-rf', 'ipxe_' + ipxeVersion)
shell.rm(path.join(__appdir, 'ipxe', 'ipxe.' + ipxeVersion))
shell.rm(path.join(__appdir, 'ipxe', 'log_' + ipxeVersion + '.txt'))
+ updateInProgress(ipxeVersion, false)
sendToLog(ipxeVersion, 'iPXE files successfully cleaned', 'success', false)
+ },
+
+ status: function (ipxeVersion) {
+ return building[ipxeVersion]
}
}
async function cloneIpxe (ipxeVersion) {
// Check if git is installed on the server.
if (!shell.which('git')) {
- return { status: 'GIT_MISSING', error_message: 'Please install git on the server.' }
+ return { status: 'GIT_MISSING', error: 'Please install git on the server.' }
}
shell.cd(path.join(__appdir, 'ipxe'))
@@ -85,31 +129,26 @@ function copyConfigs (ipxeVersion) {
shell.cp(path.join(__appdir, 'ipxe', 'console_' + ipxeVersion + '.h'), path.join(__appdir, 'ipxe', 'ipxe_' + ipxeVersion, 'src', 'config', 'console.h'))
}
+function updateInProgress (ipxeVersion, inProgress) {
+ building[ipxeVersion] = inProgress
+ const event = ipxeVersion + ' inProgress'
+ io.in('broadcast ipxeBuild').emit(event, inProgress)
+}
+
function sendToLog (ipxeVersion, msg, status, log = true) {
- var date = new Date()
+ const date = new Date()
+ const pad = x => x < 10 ? '0' + x : x
var dateString = '[' + date.getFullYear() + '-'
+ dateString += pad(date.getMonth()) + '-'
+ dateString += pad(date.getDate()) + ' '
+ dateString += pad(date.getHours()) + ':'
+ dateString += pad(date.getMinutes()) + ':'
+ dateString += pad(date.getSeconds()) + ']'
- var month = parseInt(date.getMonth()) + 1
- if (month < 10) dateString += '0' + month + '-'
- else dateString += month + '-'
-
- if (parseInt(date.getDate()) < 10) dateString += '0' + date.getDate() + ' '
- else dateString += date.getDate() + ' '
-
- if (parseInt(date.getHours()) < 10) dateString += '0' + date.getHours() + ':'
- else dateString += date.getHours() + ':'
-
- if (parseInt(date.getMinutes()) < 10) dateString += '0' + date.getMinutes() + ':'
- else dateString += date.getMinutes() + ':'
-
- if (parseInt(date.getSeconds()) < 10) dateString += '0' + date.getSeconds()
- else dateString += date.getSeconds()
- dateString += ']'
-
- var logEntry = { date: dateString, status: status, msg: msg }
+ const logEntry = { date: dateString, status: status, msg: msg }
- var socket = ipxeVersion + ' log'
- io.in('broadcast ipxeBuild').emit(socket, logEntry)
+ const event = ipxeVersion + ' log'
+ io.in('broadcast ipxeBuild').emit(event, logEntry)
if (log) writeLog(ipxeVersion, logEntry)
}
diff --git a/webapp/src/components/IpxeBuilderModuleConfig.vue b/webapp/src/components/IpxeBuilderModuleConfig.vue
index e4f619a..4909227 100644
--- a/webapp/src/components/IpxeBuilderModuleConfig.vue
+++ b/webapp/src/components/IpxeBuilderModuleConfig.vue
@@ -15,7 +15,8 @@
"consoleSaved": "console.h saved successfully",
"buildingIpxe": "Building iPXE ...",
"cleanIpxe": "Clean iPXE",
- "cleaningIpxe": "Cleaning iPXE ..."
+ "cleaningIpxe": "Cleaning iPXE ...",
+ "alreadyBuiling": "The iPXE building process not finished"
},
"de": {
"efi": "EFI",
@@ -32,7 +33,8 @@
"consoleSaved": "console.h wurde erfolgreich gespeichert",
"buildingIpxe": "iPXE wird gebaut ...",
"cleanIpxe": "iPXE aufräumen",
- "cleaningIpxe": "iPXE wird aufgeräumt .."
+ "cleaningIpxe": "iPXE wird aufgeräumt ..",
+ "alreadyBuiling": "Der iPXE build-Prozess ist noch nicht abgeschlossen"
}
}
</i18n>
@@ -41,14 +43,22 @@
<div>
<v-subheader>{{ $t('ipxe') }}</v-subheader>
- <v-card style="padding-left: 24px;padding-right: 24px; padding-top: 12px; padding-bottom: 12px; height: 50vh; overflow: auto;" ref="log">
+ <v-card style="height: 588px;" ref="log">
+ <RecycleScroller :items="log" :item-height="21" style="height: 100%;">
+ <div slot-scope="{ item }" style="height: 21px;">
+ <pre :class="item.status + '--text'" style="margin-bottom: 0px"><span>{{ item.date }} {{ item.msg }}</span></pre>
+ </div>
+ </RecycleScroller>
+
+ <!--
+ <v-card style="padding-left: 24px;padding-right: 24px; padding-top: 12px; padding-bottom: 12px; height: 50vh; overflow: auto;" ref="log">
<template v-for="(entry, index) in log">
<pre :class="entry.status + '--text'" style="margin-bottom: 0px" :key="index"><span>{{ entry.date }} {{ entry.msg }}</span></pre>
- </template>
+ </template>-->
</v-card>
<div class="text-xs-right">
- <v-btn flat color="error" @click="cleanIpxe"><v-icon left>delete</v-icon>{{ $t('cleanIpxe') }}</v-btn>
- <v-btn flat color="primary" @click="buildIpxe"><v-icon left>gavel</v-icon>{{ $t('buildIpxe') }}</v-btn>
+ <v-btn flat color="error" @click="cleanIpxe" :disabled=disableButtons><v-icon left>delete</v-icon>{{ $t('cleanIpxe') }}</v-btn>
+ <v-btn flat color="primary" @click="buildIpxe" :disabled=disableButtons><v-icon left>gavel</v-icon>{{ $t('buildIpxe') }}</v-btn>
</div>
<v-subheader></v-subheader>
@@ -138,7 +148,8 @@ export default {
certificateExpanded: null,
generalExpanded: null,
consoleExpanded: null,
- log: []
+ log: [],
+ disableButtons: false
}
},
computed: {
@@ -174,12 +185,14 @@ export default {
},
buildIpxe () {
axios.get('/api/ipxe/' + this.ipxeVersion + '/build').then(result => {
- this.$snackbar({ color: 'primary', text: this.$tc('buildingIpxe') })
+ if (result.data.status === 'SUCCESS') this.$snackbar({ color: 'primary', text: this.$tc('buildingIpxe') })
+ else if (result.data.status === 'ALREADY_BUILDING') this.$snackbar({ color: 'error', text: this.$tc('alreadyBuiling') })
})
},
cleanIpxe () {
axios.get('/api/ipxe/' + this.ipxeVersion + '/clean').then(result => {
- this.$snackbar({ color: 'primary', text: this.$tc('cleaningIpxe') })
+ if (result.data.status === 'SUCCESS') this.$snackbar({ color: 'primary', text: this.$tc('cleaningIpxe') })
+ else if (result.data.status === 'ALREADY_BUILDING') this.$snackbar({ color: 'error', text: this.$tc('alreadyBuiling') })
})
}
},
@@ -203,17 +216,26 @@ export default {
for (var line in lines) {
if (lines[line] === '') continue
var attr = lines[line].split('\t')
- this.log.push({ date: attr[0], status: attr[1], msg: attr[2] })
+ this.log.push({ id: this.log.length, date: attr[0], status: attr[1], msg: attr[2] })
}
})
// Socket io event listeners
this.$socket.on(this.ipxeVersion + ' log', entry => {
- this.log.push({ msg: entry.msg, status: entry.status, date: entry.date })
+ this.log.push({ id: this.log.length, msg: entry.msg, status: entry.status, date: entry.date })
+ })
+
+ // Disable the buttons if a building process is running.
+ axios.get('/api/ipxe/' + this.ipxeVersion + '/status').then(result => {
+ this.disableButtons = result.data.data
+ })
+
+ this.$socket.on(this.ipxeVersion + ' inProgress', inProgress => {
+ this.disableButtons = inProgress
})
},
updated () {
- this.$refs.log.$el.scrollTop = this.$refs.log.$el.scrollHeight
+ this.$refs.log.$el.firstElementChild.scrollTop = this.$refs.log.$el.firstElementChild.scrollHeight
}
}
</script>