From 5fbd058f8ac7e13d1593dde996715cf534edec8b Mon Sep 17 00:00:00 2001 From: Jannik Schönartz Date: Mon, 31 Aug 2020 17:33:34 +0000 Subject: npm install needed [ipxe builder] Rework to link directorys instead of single files --- server/api/ipxe.js | 67 ++++++++++++++++++++++++++++++++++++++++++++++-- server/lib/shell.js | 59 +++++++++++++++++++++++++++++++++++++----- server/package-lock.json | 33 +++++++++++++++++++----- server/package.json | 3 ++- 4 files changed, 147 insertions(+), 15 deletions(-) (limited to 'server') diff --git a/server/api/ipxe.js b/server/api/ipxe.js index b807c00..e232cda 100644 --- a/server/api/ipxe.js +++ b/server/api/ipxe.js @@ -7,13 +7,16 @@ const { decorateApp } = require('@awaitjs/express') var router = decorateApp(express.Router()) var noAuthRouter = express.Router() const log = require(path.join(__appdir, 'lib', 'log')) +const buildLinkPath = path.join(__appdir, 'ipxe', 'current_builds') +const buildsPath = path.join(__appdir, 'ipxe', 'builds') +const sanitize = require('sanitize-filename') // Permission check middleware router.all('/:x', async (req, res, next) => { switch (req.method) { case 'GET': switch (req.params.x) { - case 'script': case 'certificate': case 'general': case 'console': case 'log': case 'config': case 'status': + case 'script': case 'certificate': case 'general': case 'console': case 'log': case 'config': case 'status': case 'builds': if (!await req.user.hasPermission('ipxe.view')) return res.status(403).send({ error: 'Missing permission', permission: 'ipxe.view' }) break @@ -157,7 +160,7 @@ router.getAsync('/build', async (req, res) => { delete require.cache[require.resolve(path.join(__appdir, 'config', 'ipxe'))] const config = require(path.join(__appdir, 'config', 'ipxe')) - const build = await shell.buildIpxe(config.targets.build.join(' '), config.repository, config.branch) + const build = await shell.buildIpxe(config.targets.build, config.repository, config.branch) res.send(build) }) @@ -185,6 +188,66 @@ router.get('/status', (req, res) => { res.send({ status: 'SUCCESS', data: shell.status(req.params.version) }) }) +/* + * Return a json of all available builds in /ipxe/builds + * { 'YYYY-M-DD_h-m-s': { type: '', children: { ... }, selected: }} + */ +router.get('/builds', (req, res) => { + // Reads directory of the builded ipxe targets /ipxe/builds + let recursiveDirectory = shell.readdirRecursive(buildsPath) + let linkname = fs.readlinkSync(buildLinkPath).split('/').slice(-1)[0] + for (let buildDir of recursiveDirectory) { + buildDir.selected = (buildDir.name === linkname) + } + res.send(recursiveDirectory) +}) + +/* + * Recreates the symlinks to the selected target. + */ +router.post('/builds', (req, res) => { + let buildname = sanitize(req.body.build) + const buildDir = fs.readdirSync(buildsPath) + + if (buildDir.includes(buildname)) { + // Recreate the symlink + return res.send(shell.forceSymlink(path.join(buildsPath, buildname), buildLinkPath)) + } else return res.send({ status: 'ERROR', error: 'BUILD_NOT_FOUND' }) +}) + +/* + * Renames the directory of the builds + */ +router.post('/builds/:buildname', (req, res) => { + const buildname = sanitize(req.params.buildname) + const newname = sanitize(req.body.name) + + const buildDir = fs.readdirSync(buildsPath) + + // Check if the build exists and the destination don't + if (!buildDir.includes(buildname)) return res.send({ status: 'ERROR', error: 'BUILD_NOT_FOUND' }) + if (buildDir.includes(newname)) return res.send({ status: 'ERROR', error: 'BUILD_ALREADY_EXISTS' }) + + // Rename the build + fs.renameSync(path.join(buildsPath, buildname), path.join(buildsPath, newname)) + + // Check if the link has to be changed (if the current default build was renamed) + let linkname = fs.readlinkSync(buildLinkPath).split('/').slice(-1)[0] + if (linkname === buildname) shell.forceSymlink(path.join(buildsPath, newname), buildLinkPath) + + return res.send({ status: 'SUCCESS' }) +}) + +router.delete('/builds/:buildname', (req, res) => { + let buildname = sanitize(req.params.buildname) + + const buildDir = fs.readdirSync(buildsPath) + if (buildDir.includes(buildname)) { + shell.forceDeleteBuild(path.join(__appdir, 'ipxe', 'builds', buildname)) + return res.send() + } else return res.send({ status: 'ERROR', error: 'BUILDS_NOT_FOUND' }) +}) + module.exports.router = router noAuthRouter.get('/load/script', (req, res) => { diff --git a/server/lib/shell.js b/server/lib/shell.js index ed2f4cd..29986de 100644 --- a/server/lib/shell.js +++ b/server/lib/shell.js @@ -6,7 +6,7 @@ const fs = require('fs') // Only one building process per version at a time. module.exports = { - buildIpxe: async function (buildParameter = '', gitURL = 'http://git.ipxe.org/ipxe.git', gitBranch = '') { + buildIpxe: async function (buildParameters = [], gitURL = 'http://git.ipxe.org/ipxe.git', gitBranch = '') { var makeCmd = '' // Only one building process can be running. (lock the ipxe directory) @@ -14,7 +14,7 @@ module.exports = { // If file is already locked // if (false) return { status: 'ALREADY_BUILDING', error: 'iPXE-building process is already in progress.' } - makeCmd = 'make ' + buildParameter + makeCmd = 'make ' + buildParameters.join(' ') makeCmd += ' EMBED=' + path.join(__appdir, 'ipxe', 'embedded.ipxe') makeCmd += ' TRUST=' + path.join(__appdir, 'bin', 'fullchain.pem') @@ -53,11 +53,21 @@ module.exports = { } else sendToLog(data, 'error') }) }) - // Copy and rename the ipxe file. - // sendToLog('Copying ipxe file ...\n', 'primary') - // shell.cp('bin/undionly.kpxe', path.join(__appdir, 'ipxe')) - // shell.mv(path.join(__appdir, 'ipxe', 'undionly.kpxe'), path.join(__appdir, 'ipxe', 'ipxe.' + ipxeVersion)) + + // Copy and rename the ipxe file to the __appdir/ipxe/builds/ dir. + sendToLog('Copying ipxe file(s) ...\n', 'primary') + const date = new Date() + const timestamp = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + '_' + date.getHours() + '-' + date.getMinutes() + '-' + date.getSeconds() + + for (let buildtarget of buildParameters) { + const target = buildtarget.split('/') + shell.mkdir('-p', path.join(__appdir, 'ipxe', 'builds', timestamp, target[0])) + shell.cp(path.join(__appdir, 'ipxe', 'ipxeGIT', 'src', buildtarget), path.join(__appdir, 'ipxe', 'builds', timestamp, target[0], target[1])) + sendToLog('Copyed ' + buildtarget, 'success') + } + sendToLog('Finished copying\n', 'success') // sendToLog(ipxeVersion, 'done\n', 'success') + // shell.mv(path.join(__appdir, 'ipxe', 'undionly.kpxe'), path.join(__appdir, 'ipxe', 'ipxe.' + ipxeVersion)) // updateInProgress(ipxeVersion, false) }, @@ -88,6 +98,43 @@ module.exports = { status: function (ipxeVersion) { return false + }, + + /* Changes or creates a symbolic link to a builded ipxe */ + forceSymlink: function (source, dest) { + // Because of the shelljs lib is bugged handle broken links deletetion myself + var destinationExists + try { + fs.lstatSync(dest) + destinationExists = true + } catch (err) { + destinationExists = false + } + + if (destinationExists) { + fs.unlinkSync(dest) + } + + const ln = shell.ln('-sf', source, dest) + if (ln.stderr) return { status: 'ERROR', error: ln.stderr } + else return { status: 'SUCCESS' } + }, + + readdirRecursive: function (buildsPath) { + let structure = [] + const directory = fs.readdirSync(buildsPath) + for (let obj of directory) { + if (!fs.lstatSync(path.join(buildsPath, obj)).isDirectory()) { + structure.push({ name: obj, type: 'file' }) + } else { + structure.push({ name: obj, type: 'directory', children: this.readdirRecursive(path.join(buildsPath, obj)) }) + } + } + return structure + }, + + forceDeleteBuild: function (buildsPath) { + shell.rm('-rf', path.join(buildsPath)) } } diff --git a/server/package-lock.json b/server/package-lock.json index 3b0bdee..4754263 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -2152,9 +2152,9 @@ } }, "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" }, "invert-kv": { "version": "1.0.0", @@ -3605,6 +3605,14 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "sanitize-filename": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "requires": { + "truncate-utf8-bytes": "^1.0.0" + } + }, "secure-password": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/secure-password/-/secure-password-3.1.0.tgz", @@ -3739,9 +3747,9 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, "shelljs": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", - "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", "requires": { "glob": "^7.0.0", "interpret": "^1.0.0", @@ -4479,6 +4487,14 @@ "punycode": "^1.4.1" } }, + "truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=", + "requires": { + "utf8-byte-length": "^1.0.1" + } + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", @@ -4564,6 +4580,11 @@ } } }, + "utf8-byte-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", + "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/server/package.json b/server/package.json index b236fd1..3d794ed 100644 --- a/server/package.json +++ b/server/package.json @@ -26,10 +26,11 @@ "require-directory": "^2.1.1", "rrule": "^2.6.0", "safe-timers": "^1.1.0", + "sanitize-filename": "^1.6.3", "secure-password": "^3.1.0", "sequelize": "^4.43.0", "sequelize-cli": "^4.1.1", - "shelljs": "^0.8.3", + "shelljs": "^0.8.4", "socket.io": "^2.2.0", "standard": "^11.0.1", "syswide-cas": "^5.3.0", -- cgit v1.2.3-55-g7522