From 17759278184463f84e2dfdbaa93882d0d3dd5423 Mon Sep 17 00:00:00 2001 From: Jannik Schönartz Date: Tue, 28 Aug 2018 17:35:51 +0000 Subject: [registration/dhcp] Implement dhcp as external-backend Registration -> Registrations to match API guidelines. Fixed shell script to only build undionly.kpxe. Added infoblock external-backend. Removed dhcp from config.json Fixed ipxe scripts to match the registrations. --- server/api/registration.js | 147 --------------------- server/api/registrations.js | 125 ++++++++++++++++++ server/config/config.template.json | 3 - server/ipxe/default.ipxe | 64 +++++++++ server/ipxe/exitTestScript.ipxe | 57 -------- server/ipxe/ipxe.0 | Bin 0 -> 90057 bytes server/ipxe/main.ipxe | 30 +---- server/ipxe/registration.ipxe | 34 +++-- .../external-backends/backends/idoit-backend.js | 2 +- .../external-backends/backends/infoblox-backend.js | 95 +++++++++++++ server/lib/shell.js | 10 +- 11 files changed, 316 insertions(+), 251 deletions(-) delete mode 100644 server/api/registration.js create mode 100644 server/api/registrations.js create mode 100644 server/ipxe/default.ipxe delete mode 100644 server/ipxe/exitTestScript.ipxe create mode 100644 server/ipxe/ipxe.0 create mode 100644 server/lib/external-backends/backends/infoblox-backend.js (limited to 'server') diff --git a/server/api/registration.js b/server/api/registration.js deleted file mode 100644 index a5c1b6f..0000000 --- a/server/api/registration.js +++ /dev/null @@ -1,147 +0,0 @@ -/* global __appdir */ -var path = require('path') -const Infoblox = require('infoblox') -var express = require('express') -var router = express.Router() -var noAuthRouter = express.Router() -var db = require(path.join(__appdir, 'lib', 'sequelize')) -var dhcp = require(path.join(__appdir, 'config', 'config')).dhcp - -// GET requests. - -/* - * @return: - */ -router.get('/', (req, res) => { - var ipam = new Infoblox({ - ip: 'dhcp.uni-freiburg.de', - apiVersion: '1.7.1' - }) - ipam.login(dhcp.user, dhcp.password).then(function (r) { - if (r) { - // Get the network from the ip. - // ipam.getHost('10.21.9.78').then(function (response) { - ipam.getNetworkFromIp('10.21.9.78').then(function (response) { - // ipam.getIpsFromSubnet('10.21.9.0/24').then(function (response) { - // ipam.list('record:host').then(function (response) { - // ipam.getDomain().then(function (response) { - response = JSON.parse(response) - // ipam.getNext(response[0]._ref, 1).then(r => { - res.send(response) - // }) - // res.send(JSON.parse(response)) - }) - } - // res.status(200).send({ status: 'work in progress ...' }) - }) -}) - -router.get('/setdhcptest', (req, res) => { - var ipam = new Infoblox({ - ip: 'dhcp.uni-freiburg.de', - apiVersion: '1.7.1' - }) - ipam.login('js603', 'Iwjp!DFhk4').then(function (r) { - if (r) { - ipam.create('record:host?_return_fields%2B=na13me,ipv4addrs&_return_as_object=1', {'name': 'wapiTest.lp.privat', 'ipv4addrs': [{'ipv4addr': '10.21.9.141', 'mac': 'aa:bb:cc:11:22:21'}]}).then(function (response) { - res.send(response) - }) - } - // res.status(200).send({ status: 'work in progress ...' }) - }) -}) - -module.exports.router = router - -// GET requests. - -// POST requests. - -/* - * - * @return: - */ -noAuthRouter.post('/client', (req, res) => { - // const mac = req.body.mac - // const uuid = req.body.uuid - // const ip = req.body.ip - // const name = req.body.name - // console.log(name.concat(' ', ip, ' ', mac, ' ', uuid)) - - var script = '#!ipxe\r\n' - script.concat(`console --picture \${img} --x 800 --y 600 || shell\r\n`) - db.group.findAll({ where: { '$parents.id$': null }, include: ['parents'] }).then(groups => { - groups.forEach(g => { - script = script.concat('echo', ' [', g.id, '] ', g.name, '\r\n') - }) - - script = script.concat('read group\r\n') - script = script.concat('params\r\n') - script = script.concat(`param id \${group}\r\n`) - script = script.concat('chain https://bas.stfu-kthx.net:8888/api/registration/group##params\r\n') - res.status(200).send(script) - }) -}) - -noAuthRouter.post('/group', (req, res) => { - const id = req.body.id - console.log(id) - if (id === '0') { - db.group.findAll({ where: { '$parents.id$': null }, include: ['parents'] }).then(groups => { - if (groups) { - res.send(buildIpxeMenu(id, 'Root', groups)) - } else { - res.status(404).end() - } - }) - } else { - db.group.findOne({ where: { id: id }, include: ['parents', 'subgroups', 'clients'] }).then(group => { - if (group) { - res.send(buildIpxeMenu(id, group.name, group.subgroups)) - } else { - res.status(404).end() - } - }) - } -}) - -noAuthRouter.post('/add', (req, res) => { - const mac = req.body.mac - const uuid = req.body.uuid - const ip = req.body.ip - const name = req.body.name - const parentId = req.body.id - db.client.create({ name: name, ip: ip, mac: mac, uuid: uuid }).then(client => { - client.addGroup(parentId) - res.send('#ipxe\r\nshell') - }) - console.log(name.concat(' ', ip, ' ', mac, ' ', uuid)) -}) - -module.exports.noAuthRouter = noAuthRouter - -function buildIpxeMenu (id, name, groups) { - var script = '#!ipxe\r\n' - script.concat(`console --picture \${img} --x 800 --y 600 || shell\r\n`) - var menuscript = '' - script = script.concat(':start\r\n') - script = script.concat('menu Choose the group you want the client to be saved in\r\n') - var counter = '1' - groups.forEach(group => { - // script = script.concat('echo', ' [', subgroup.id, '] ', subgroup.name, '\r\n') - script = script.concat('item --key ', counter, ' ', counter, ' [', group.id, '] ', group.name, '\r\n') - menuscript = menuscript.concat(':', counter, '\r\n', 'params\r\nparam id ', group.id, '\r\nchain https://bas.stfu-kthx.net:8888/api/registration/group##params\r\n\r\n') - counter++ - }) - script = script.concat('item select Add client to ', name, '\r\n') - menuscript = menuscript.concat(`:select\r\necho Enter client name\r\nread clientname\r\nparams\r\nparam name \${clientname}\r\n`) - menuscript = menuscript.concat('param id ', id, `\r\nparam mac \${net0/mac}\r\nparam uuid \${uuid}\r\nparam ip \${net0/ip}\r\n`) - menuscript = menuscript.concat('chain https://bas.stfu-kthx.net:8888/api/registration/add##params\r\n\r\n') - if (id !== '0') { - script = script.concat('item reset Go to start\r\n') - menuscript = menuscript.concat(':reset\r\nparams\r\nparam id ', 0, '\r\nchain --replace https://bas.stfu-kthx.net:8888/api/registration/group##params\r\n\r\n') - } - script = script.concat(`choose target && goto \${target}\r\n\r\n`) - script = script.concat(menuscript) - return script -} diff --git a/server/api/registrations.js b/server/api/registrations.js new file mode 100644 index 0000000..7537124 --- /dev/null +++ b/server/api/registrations.js @@ -0,0 +1,125 @@ +/* global __appdir */ +var path = require('path') +var express = require('express') +var router = express.Router() +var noAuthRouter = express.Router() +var db = require(path.join(__appdir, 'lib', 'sequelize')) +const ExternalBackends = require(path.join(__appdir, 'lib', 'external-backends')) + +// GET requests. + +/* + * @return: + */ +router.get('/', (req, res) => { + db.backend.findOne({ where: { type: 'infoblox' } }).then(result => { + const b = new ExternalBackends() + const instance = b.getInstance(result.type) + instance.test(result.credentials).then(result => { + res.status(200).send(result) + }) + }) +}) + +module.exports.router = router + +// GET requests. + +// POST requests. + +/* + * + * @return: + */ +noAuthRouter.post('/client', (req, res) => { + // const mac = req.body.mac + // const uuid = req.body.uuid + // const ip = req.body.ip + // const name = req.body.name + // console.log(name.concat(' ', ip, ' ', mac, ' ', uuid)) + + var script = '#!ipxe\r\n' + script.concat(`console --picture \${img} --x 800 --y 600 || shell\r\n`) + db.group.findAll({ where: { '$parents.id$': null }, include: ['parents'] }).then(groups => { + groups.forEach(g => { + script = script.concat('echo', ' [', g.id, '] ', g.name, '\r\n') + }) + + script = script.concat('read group\r\n') + script = script.concat('params\r\n') + script = script.concat(`param id \${group}\r\n`) + script = script.concat('chain https://bas.stfu-kthx.net:8888/api/registrations/group##params\r\n') + res.status(200).send(script) + }) +}) + +noAuthRouter.post('/group', (req, res) => { + const id = req.body.id + console.log(id) + if (id === '0') { + db.group.findAll({ where: { '$parents.id$': null }, include: ['parents'] }).then(groups => { + if (groups) { + res.send(buildIpxeMenu(id, 'Root', groups)) + } else { + res.status(404).end() + } + }) + } else { + db.group.findOne({ where: { id: id }, include: ['parents', 'subgroups', 'clients'] }).then(group => { + if (group) { + res.send(buildIpxeMenu(id, group.name, group.subgroups)) + } else { + res.status(404).end() + } + }) + } +}) + +noAuthRouter.post('/add', (req, res) => { + const mac = req.body.mac + const uuid = req.body.uuid + const ip = req.body.ip + const name = req.body.name + const parentId = req.body.id + db.client.findOne({ where: { uuid: uuid } }).then(client => { + if (client) res.status(200).send('#!ipxe\r\necho Client already exists\r\necho Press any key to continue ...\r\nread x\r\nreboot') + else { + db.client.create({ name: name, ip: ip, mac: mac, uuid: uuid }).then(client => { + if (parentId) { + client.addGroup(parentId) + } + res.send('#!ipxe\r\nreboot') + }) + } + }) +}) + +module.exports.noAuthRouter = noAuthRouter + +function buildIpxeMenu (id, name, groups) { + var script = '#!ipxe\r\n' + script.concat(`console --picture \${img} --x 800 --y 600 || shell\r\n`) + var menuscript = '' + script = script.concat(':start\r\n') + script = script.concat('menu Choose the group you want the client to be saved in\r\n') + var counter = '1' + groups.forEach(group => { + // script = script.concat('echo', ' [', subgroup.id, '] ', subgroup.name, '\r\n') + script = script.concat('item --key ', counter, ' ', counter, ' [', group.id, '] ', group.name, '\r\n') + menuscript = menuscript.concat(':', counter, '\r\n', 'params\r\nparam id ', group.id, '\r\nchain https://bas.stfu-kthx.net:8888/api/registrations/group##params\r\n\r\n') + counter++ + }) + script = script.concat('item select Add client to ', name, '\r\n') + menuscript = menuscript.concat(`:select\r\necho Enter client name\r\nread clientname\r\nparams\r\nparam name \${clientname}\r\n`) + menuscript = menuscript.concat('param id ', id, `\r\nparam mac \${net0/mac}\r\nparam uuid \${uuid}\r\nparam ip \${net0/ip}\r\n`) + menuscript = menuscript.concat('chain https://bas.stfu-kthx.net:8888/api/registrations/add##params\r\n\r\n') + if (id !== '0') { + script = script.concat('item reset Go to start\r\n') + menuscript = menuscript.concat(':reset\r\nparams\r\nparam id ', 0, '\r\nchain https://bas.stfu-kthx.net:8888/api/registrations/group##params\r\n\r\n') + } + script = script.concat('item exit Exit manual registration\r\n') + menuscript = menuscript.concat(':exit\r\nexit 1\r\n\r\n') + script = script.concat(`choose target && goto \${target}\r\n\r\n`) + script = script.concat(menuscript) + return script +} diff --git a/server/config/config.template.json b/server/config/config.template.json index 6ad7ad5..75e0c4f 100644 --- a/server/config/config.template.json +++ b/server/config/config.template.json @@ -1,8 +1,5 @@ { "https": { "port": "" - }, "dhcp": { - "user": "", - "password": "" } } diff --git a/server/ipxe/default.ipxe b/server/ipxe/default.ipxe new file mode 100644 index 0000000..e070ca6 --- /dev/null +++ b/server/ipxe/default.ipxe @@ -0,0 +1,64 @@ +#!ipxe + +# Wallpaper +set img tftp://10.8.102.124/ipxeWallpaper3_scale.png || shell +console --picture ${img} --x 800 --y 600 || shell + +:start +menu Please choose a webserver to load the ipxe menu: +item bwlehrpool bwLehrpool +item reg Registration +item pxelnx PxeLinux +item c32boot C32Boot +item exit Exit +item exit0 Exit0 +item exit1 Exit1 +item sh [Shell] +choose target && goto ${target} + +:bwlehrpool +chain --replace http://132.230.4.2/tftp/ipxelinux.0 + +:reg +set crosscert http://ca.ipxe.org/auto/ +chain --replace https://bas.stfu-kthx.net:8888/api/ipxe/load/registration || +goto start + +:exit +exit || +goto start + +:exit0 +exit 0 || +goto start + +:exit1 +exit 1 || +goto start + +:pxelnx +# set 210:string https://bas.stfu-kthx.net:8888/ +# chain \${210:string}pxelinux.0 || goto start +# chain https://bas.stfu-kthx.net:8888/pxelinux.0 +# set next-server bas-stfu-kthx.net:8888 +# set 209:string https://bas.stfu-kthx.net:8888/pxelinux.cfg +# imgload pxelinux.0 +set net0/next-server 10.8.102.124 || +set netX/next-server 10.8.102.124 || +set next-server 10.8.102.124 || +# set 209:string pxelinux.cfg/default +# set 210:string bas.stfu-kthx.net +# shell || +boot tftp://10.8.102.124/pxelinux.0 || +goto start + +:c32boot +set net0/next-server 10.8.102.124 || +set netX/next-server 10.8.102.124 || +set next-server 10.8.102.124 || +boot tftp://10.8.102.124/chain.c32 || +goto start + +:sh +shell || +goto start \ No newline at end of file diff --git a/server/ipxe/exitTestScript.ipxe b/server/ipxe/exitTestScript.ipxe deleted file mode 100644 index 51ca1bc..0000000 --- a/server/ipxe/exitTestScript.ipxe +++ /dev/null @@ -1,57 +0,0 @@ -#!ipxe -dhcp - -:start -menu Please choose a webserver to load the ipxe menu: -item reg Registration -item pxelnx PxeLinux -item c32boot C32Boot -item exit Exit -item exit0 Exit0 -item exit1 Exit1 -item sh [Shell] -choose target && goto ${target} - -:reg -set crosscert http://ca.ipxe.org/auto/ -chain --replace https://bas.stfu-kthx.net:8888/api/ipxe/load/registration || -goto start - -:exit -exit || -goto start - -:exit0 -exit 0 || -goto start - -:exit1 -exit 1 || -goto start - -:pxelnx -# set 210:string https://bas.stfu-kthx.net:8888/ -# chain \${210:string}pxelinux.0 || goto start -# chain https://bas.stfu-kthx.net:8888/pxelinux.0 -# set next-server bas-stfu-kthx.net:8888 -# set 209:string https://bas.stfu-kthx.net:8888/pxelinux.cfg -# imgload pxelinux.0 -set net0/next-server 10.8.102.124 || -set netX/next-server 10.8.102.124 || -set next-server 10.8.102.124 || -# set 209:string pxelinux.cfg/default -# set 210:string bas.stfu-kthx.net -# shell || -boot tftp://bas.stfu-kthx.net/pxelinux.0 || -goto start - -:c32boot -set net0/next-server 10.8.102.124 || -set netX/next-server 10.8.102.124 || -set next-server 10.8.102.124 || -boot tftp://10.8.102.124/chain.c32 || -goto start - -:sh -shell || -goto start \ No newline at end of file diff --git a/server/ipxe/ipxe.0 b/server/ipxe/ipxe.0 new file mode 100644 index 0000000..aa09a89 Binary files /dev/null and b/server/ipxe/ipxe.0 differ diff --git a/server/ipxe/main.ipxe b/server/ipxe/main.ipxe index f77e58d..e470108 100644 --- a/server/ipxe/main.ipxe +++ b/server/ipxe/main.ipxe @@ -1,28 +1,6 @@ #!ipxe -dhcp +ifopen +shell -# Wallpaper -set img http://christophermckinney.net/wp-content/uploads/2017/08/Wallpaper.png -console --picture ${img} --x 800 --y 600 - -:start -menu Please choose a webserver to load the ipxe menu: -item js Jannik -item uw Udo -item ch Chris -item sh [Shell] -choose target && goto ${target} - -:js -set crosscert http://ca.ipxe.org/auto/ -chain --replace https://bas.stfu-kthx.net:8888/api/ipxe/load/script || -goto start -:uw -chain http://10.4.9.115/boot.php || -goto start -:ch -chain http://10.4.9.122/boot.php || -goto start -:sh -shell || -goto start +#set crosscert http://ca.ipxe.org/auto/ +chain https://bas.stfu-kthx.net:8888/api/configloader/${uuid} \ No newline at end of file diff --git a/server/ipxe/registration.ipxe b/server/ipxe/registration.ipxe index 51d89f2..1011765 100644 --- a/server/ipxe/registration.ipxe +++ b/server/ipxe/registration.ipxe @@ -1,5 +1,4 @@ #!ipxe -dhcp # Wallpaper set crosscert http://ca.ipxe.org/auto/ @@ -10,22 +9,31 @@ console --picture ${img} --x 800 --y 600 || shell :start menu Initializing client registration -item --key i init Initialize +item --key a automatic Automatic registration +item --key m manual Manual registration item --key l localboot Localboot item --key r reboot Reboot item --key p poweroff Power Off item --key s sh [Shell] -choose --default init --timeout 15000 target && goto ${target} || goto init +choose --default automatic --timeout 15000 target && goto ${target} || goto automatic :localboot exit0 || exit1 || goto start -:init +:automatic +params +param name unnamed +param mac ${net0/mac} +param uuid ${uuid} +param ip ${net0/ip} +chain https://bas.stfu-kthx.net:8888/api/registrations/add##params + +:manual params param id 0 -chain https://bas.stfu-kthx.net:8888/api/registration/group##params || +chain https://bas.stfu-kthx.net:8888/api/registrations/group##params || goto start :reboot @@ -35,12 +43,12 @@ reboot poweroff :sh -#login -echo Enter the password to access the shell -read pw -iseq ${pw} shell || goto start -clear pw -#iseq ${password} sh || goto start -#clear username -#clear password +login +#echo Enter the password to access the shell +#read pw +#iseq ${pw} shell || goto start +#clear pw +iseq ${password} sh || goto start +clear username +clear password shell \ No newline at end of file diff --git a/server/lib/external-backends/backends/idoit-backend.js b/server/lib/external-backends/backends/idoit-backend.js index 5d94e41..6bfe001 100644 --- a/server/lib/external-backends/backends/idoit-backend.js +++ b/server/lib/external-backends/backends/idoit-backend.js @@ -249,7 +249,7 @@ class IdoitBackend extends ExternalBackends { console.log(response.data.error) return { success: false, error: response.data.error.message, msg: response.data.error.data.error } } else { - return { success: false, msg: 'UNNOWN ERROR' } + return { success: false, error: 'UNNOWN_ERROR' } } } } diff --git a/server/lib/external-backends/backends/infoblox-backend.js b/server/lib/external-backends/backends/infoblox-backend.js new file mode 100644 index 0000000..f980b8b --- /dev/null +++ b/server/lib/external-backends/backends/infoblox-backend.js @@ -0,0 +1,95 @@ +/* global __appdir */ +const path = require('path') +const ExternalBackends = require(path.join(__appdir, 'lib', 'external-backends')) +const Infoblox = require('infoblox') + +class InfobloxBackend extends ExternalBackends { + // ############################################################################ + // ######################## needed functions ################################# + + /* + * Returns the credential structure / fields, defined in the backends. + */ + getCredentials () { + return [ + { type: 'text', id: 1, name: 'API url', icon: 'link' }, + { type: 'text', id: 2, name: 'API version', icon: 'info' }, + { type: 'text', id: 3, name: 'Username', icon: 'person_outline' }, + { type: 'password', id: 4, name: 'Password', icon: 'vpn_key', show: false } + ] + } + + /* + * Checks the connection of a given backend. + * infoblox: If we can login the connection to the server and also the login is successfull. + * + * return: { success: , status: '', error: '' } + */ + async checkConnection (credentials) { + var c = this.mapCredentials(credentials) + + var ipam = new Infoblox({ + ip: c.url, + apiVersion: c.version + }) + return ipam.login(c.username, c.password).then(response => { + if (response) { + console.log('wefkin') + return { success: true } + } else { + return { success: false, error: 'TEST' } + } + }) + } + // ############################################################################ + // ####################### helper/optional functions ######################### + // Helper function, to map the array of credential objects into a single js object. + mapCredentials (credentials) { + const c = JSON.parse(credentials) + var mapped = { + url: c.find(x => x.id === 1).value, + version: c.find(x => x.id === 2).value, + username: c.find(x => x.id === 3).value, + password: c.find(x => x.id === 4).value + } + + return mapped + } + + // #### TEST FUNCTIONS ### + test (credentials) { + var c = this.mapCredentials(credentials) + + var ipam = new Infoblox({ + ip: c.url, + apiVersion: c.version + }) + + var promise = new Promise((resolve, reject) => { + ipam.login(c.username, c.password).then(response => { + if (response) { + // ipam.create('record:host?_return_fields%2B=na13me,ipv4addrs&_return_as_object=1', {'name': 'wapiTest.lp.privat', 'ipv4addrs': [{'ipv4addr': '10.21.9.141', 'mac': 'aa:bb:cc:11:22:21'}]}).then(function (response) { + // return response + // }) + // Get the network from the ip. + // ipam.getHost('10.21.9.78').then(function (response) { + ipam.getNetworkFromIp('10.21.9.78').then(response => { + // ipam.getIpsFromSubnet('10.21.9.0/24').then(function (response) { + // ipam.list('record:host').then(function (response) { + // ipam.getDomain().then(function (response) { + response = JSON.parse(response) + // ipam.getNext(response[0]._ref, 1).then(r => { + resolve(response) + // }) + // res.send(JSON.parse(response)) + }) + } else { + return { success: false, error: 'TEST' } + } + }) + }) + return promise + } +} + +module.exports = InfobloxBackend diff --git a/server/lib/shell.js b/server/lib/shell.js index e0782f1..37de779 100644 --- a/server/lib/shell.js +++ b/server/lib/shell.js @@ -20,13 +20,15 @@ module.exports = { shell.rm(path.join(__appdir, 'ipxe', 'ipxe', 'src', 'config', 'console.h')) shell.cp(path.join(__appdir, 'ipxe', 'console.h'), path.join(__appdir, 'ipxe', 'ipxe', 'src', 'config')) // var make = 'make EMBED=' + path.join(__appdir, 'ipxe', 'main.ipxe'); - var make = 'make EMBED=' + path.join(__appdir, 'ipxe', 'main.ipxe') + ' TRUST=' + path.join(__appdir, 'bin', 'fullchain.pem') + var make = 'make EMBED=' + path.join(__appdir, 'ipxe', 'main.ipxe') + ' TRUST=' + path.join(__appdir, 'bin', 'fullchain.pem') + ' bin/undionly.kpxe' // shell.env.PATH = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin'; shell.env.DEBUG = '' shell.exec(make, function (code, stdout, stderr) { - shell.rm(path.join(__appdir, 'tftp', 'ipxe.0')) - shell.cp('bin/ipxe.pxe', path.join(__appdir, 'tftp')) - shell.mv(path.join(__appdir, 'tftp', 'ipxe.pxe'), path.join(__appdir, 'tftp', 'ipxe.0')) + // shell.rm(path.join(__appdir, 'tftp', 'ipxe.0')) + shell.rm(path.join(__appdir, 'ipxe', 'ipxe.0')) + // shell.cp('bin/undionly.kpxe', path.join(__appdir, 'tftp')) + shell.cp('bin/undionly.kpxe', path.join(__appdir, 'ipxe')) + shell.mv(path.join(__appdir, 'ipxe', 'undionly.kpxe'), path.join(__appdir, 'ipxe', 'ipxe.0')) // shell.rm('-rf', 'ipxe'); return res.status(200).send({ status: 'success' }) }) -- cgit v1.2.3-55-g7522