From f0808189575e7024d0ad100dfb71b18810ec79de Mon Sep 17 00:00:00 2001 From: Jannik Schönartz Date: Sun, 14 Apr 2019 02:46:53 +0000 Subject: [server/external-backends] Add delete method for the infoblox backend & add infoblox client mappings method --- server/api/backends.js | 21 ++++++++ server/api/registration.js | 10 +++- .../external-backends/backends/infoblox-backend.js | 57 ++++++++++++++++++++-- server/lib/external-backends/index.js | 2 +- .../20190413172133-change-externalid-type.js | 31 ++++++++++++ server/models/backend.js | 4 +- 6 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 server/migrations/20190413172133-change-externalid-type.js (limited to 'server') diff --git a/server/api/backends.js b/server/api/backends.js index e92999a..f3de01f 100644 --- a/server/api/backends.js +++ b/server/api/backends.js @@ -301,6 +301,27 @@ router.get('/:id/import', (req, res) => { }) }) +/* + * Adds the client mapping from the backend to the client with the same mac address. + */ +router.getAsync('/:id/mapping', async (req, res) => { + const id = req.params.id + const backend = await db.backend.findOne({ where: { id: id } }) + + if (backend) { + const b = new ExternalBackends() + const instance = b.getInstance(backend.type) + const objects = await instance.getObjects(backend.credentials) + + for (let index in objects) { + const object = objects[index] + const client = await db.client.findOne({ where: { mac: object.mac } }) + await backend.addMappedClients(client, { through: { externalId: object.id } }) + } + return res.status(200).send() + } else return res.status(500).send() +}) + // No auth router for now but those client based methods should better be in the clients api. // TODO: Move to clients? // TODO: receive files should be authenticated! diff --git a/server/api/registration.js b/server/api/registration.js index 5638747..4ab7cbc 100644 --- a/server/api/registration.js +++ b/server/api/registration.js @@ -135,17 +135,19 @@ noAuthRouter.postAsync('/clients', async (req, res) => { // If there is no ip, we don't need DHCP checks. // Only the first ip address is checked! client.networks[0] + let dhcp = false if (client.networks.length >= 1) { const network = client.networks[0] // Get the dhcp backend. Only one dhcp backend can exist else -> conflict. - const dhcp = await backendHelper.getDhcp() + dhcp = await backendHelper.getDhcp() let ipSelection = false - let setIpError = undefined + let setIpError if (dhcp) { if (automatic) { // Set the name of the client if it's not set if (!client.name) client.name = client.type + '_' + client.uuid const setIp = await dhcp.instance.setIp(dhcp.backend.credentials, network.ip, network.mac, undefined, true) + dhcp.ref = setIp.ref // Check for errors. if (!setIp.error) { // Client ip set successfully @@ -157,6 +159,7 @@ noAuthRouter.postAsync('/clients', async (req, res) => { // If networks.dhcp is set the user already choose the ip and we have to set it now. if (!client.name) return res.send(buildNameClientIpxeMenu(client)) const setIp = await dhcp.instance.setIp(dhcp.backend.credentials, network.dhcp, network.mac, client.name) + dhcp.ref = setIp.ref // Check for errors. if (setIp.error) { // Setting the client ip failed @@ -190,6 +193,9 @@ noAuthRouter.postAsync('/clients', async (req, res) => { const newClient = await db.client.create(createClient) client.id = newClient.id + // Add dhcp backend mapping + if (dhcp) dhcp.backend.addMappedClients(newClient, { through: { externalId: dhcp.ref } }) + // Add groups to the client. if (client.parents.length === 0) client.parents = await ipHelper.getGroups(client.networks[0].ip) client.parents.forEach(pid => { newClient.addGroup(pid) }) diff --git a/server/lib/external-backends/backends/infoblox-backend.js b/server/lib/external-backends/backends/infoblox-backend.js index 6076217..2671491 100644 --- a/server/lib/external-backends/backends/infoblox-backend.js +++ b/server/lib/external-backends/backends/infoblox-backend.js @@ -132,7 +132,7 @@ class InfobloxBackend extends ExternalBackends { return { error: 'ERROR_INFOBLOX', msg: createHost.text } } else { if (!name) return { ip: createHost.result.ipv4addr } - else return { host: createHost.result.ipv4addrs[0].host, ip: createHost.result.ipv4addrs[0].ipv4addr } + else return { host: createHost.result.ipv4addrs[0].host, ip: createHost.result.ipv4addrs[0].ipv4addr, id: createHost.result._ref } } } @@ -140,6 +140,41 @@ class InfobloxBackend extends ExternalBackends { return true } + async deleteObjects (credentials, objectIds) { + const c = this.mapCredentials(credentials) + + const ipam = new Infoblox({ + ip: c.url, + apiVersion: c.version + }) + const login = await ipam.login(c.username, c.password) + if (!login) return { error: 'LOGIN_FAILED' } + + for (let index in objectIds) { + const ref = objectIds[index] + await ipam.delete(ref) + } + } + + async getObjects (credentials) { + const c = this.mapCredentials(credentials) + + const ipam = new Infoblox({ + ip: c.url, + apiVersion: c.version + }) + const login = await ipam.login(c.username, c.password) + if (!login) return { error: 'LOGIN_FAILED' } + + let result = [] + const records = JSON.parse(await ipam.list('record:host?zone=lp.privat')) + for (let index in records) { + const record = records[index] + result.push({ id: record._ref, mac: record.ipv4addrs[0].mac, ip: record.ipv4addrs[0].ipv4addr }) + } + return result + } + // ############################################################################ // ####################### helper/optional functions ######################### // Helper function, to map the array of credential objects into a single js object. @@ -170,33 +205,47 @@ class InfobloxBackend extends ExternalBackends { // Get network from ip result['getNetworkFromIp'] = JSON.parse(await ipam.getNetworkFromIp('10.21.9.78')) // Get host - // result["getHost.78"] = JSON.parse(await ipam.getHost('10.21.9.78')) + result['getHost.78'] = JSON.parse(await ipam.getHost('10.21.9.78')) // result["getHost.219"] = JSON.parse(await ipam.getHost('10.21.9.219')) + result['getHost.12'] = JSON.parse(await ipam.getHost('10.21.9.12')) + // Get ips from subnet // result["getIpsFromSubnet"] = JSON.parse(await ipam.getIpsFromSubnet('10.21.9.0/24')) + // List records // result["list"] = JSON.parse(await ipam.list('record:host')) + // Get Domain result['getDomain'] = await ipam.getDomain() + // Get next ip // result["getNextIp.1"] = await ipam.getNext(result["getNetworkFromIp"][0]._ref, 1) + // Get next 20 ips // result["getNextIp.20"] = await ipam.getNext(result["getNetworkFromIp"][0]._ref, 20) // Create Host // result['createHost'] = await ipam.create('record:host?_return_fields%2B=ipv4addrs&_return_as_object=1', {'name': 'wapiTest2.lp.privat', 'ipv4addrs': [{'ipv4addr': '10.21.9.218', 'mac': 'aa:bb:cc:11:22:21'}]}) + /* result['create'] = await ipam.create('record:host?_return_fields%2B=ipv4addrs&_return_as_object=1', { 'name': 'test.lp.privat', 'ipv4addrs': [ { - 'ipv4addr': 'func:nextavailableip:' + result['getNetworkFromIp'][0].network, + //'ipv4addr': 'func:nextavailableip:' + result['getNetworkFromIp'][0].network, + 'ipv4addr': '10.21.9.206', 'mac': 'aa:bb:cc:11:22:21' } ] }) - result['create'] */ + + // Delete stuff + // result["getHost.173"] = JSON.parse(await ipam.getHost('10.21.9.173')) + // result["deleteHost.173"] = JSON.parse(await ipam.delete(result["getHost.173"][0]._ref)) + // result["deleteHost.206"] = JSON.parse(await ipam.delete('record:host/ZG5zLmhvc3QkLl9kZWZhdWx0LnByaXZhdC5scC50ZXN0:test.lp.privat/default')) + + result['allrecords'] = JSON.parse(await ipam.list('record:host?zone=lp.privat')) return result } } diff --git a/server/lib/external-backends/index.js b/server/lib/external-backends/index.js index 8dcae5a..9716b36 100644 --- a/server/lib/external-backends/index.js +++ b/server/lib/external-backends/index.js @@ -69,7 +69,7 @@ class ExternalBackends { * * Returns a list of all objects in the backend. */ - async getObjects (credendtials) { + async getObjects (credentials) { return { error: 'NOT_IMPLEMENTED_EXCEPTION', message: 'The provided backend does not have a getObjects method' } } diff --git a/server/migrations/20190413172133-change-externalid-type.js b/server/migrations/20190413172133-change-externalid-type.js new file mode 100644 index 0000000..e1a0c33 --- /dev/null +++ b/server/migrations/20190413172133-change-externalid-type.js @@ -0,0 +1,31 @@ +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction((t) => { + return Promise.all([ + queryInterface.changeColumn('backend_x_client', 'externalId', { + allowNull: false, + type: Sequelize.STRING + }), + queryInterface.changeColumn('backend_x_group', 'externalId', { + allowNull: false, + type: Sequelize.STRING + }) + ]) + }) + }, + + down: (queryInterface, Sequelize) => { + return queryInterface.sequelize.transaction((t) => { + return Promise.all([ + queryInterface.changeColumn('backend_x_client', 'externalId', { + allowNull: false, + type: Sequelize.INTEGER + }), + queryInterface.changeColumn('backend_x_group', 'externalId', { + allowNull: false, + type: Sequelize.INTEGER + }) + ]) + }) + } +} diff --git a/server/models/backend.js b/server/models/backend.js index 37203e6..705cd0f 100644 --- a/server/models/backend.js +++ b/server/models/backend.js @@ -34,13 +34,13 @@ module.exports = (sequelize, DataTypes) => { var BackendXGroup = sequelize.define('backend_x_group', { backendId: { type: DataTypes.INTEGER, primaryKey: true }, groupId: { type: DataTypes.INTEGER, primaryKey: false }, - externalId: { type: DataTypes.INTEGER, primaryKey: true }, + externalId: { type: DataTypes.STRING, primaryKey: true }, externalType: DataTypes.STRING }, { timestamps: false, freezeTableName: true }) var BackendXClient = sequelize.define('backend_x_client', { backendId: { type: DataTypes.INTEGER, primaryKey: true }, clientId: { type: DataTypes.INTEGER, primaryKey: false }, - externalId: { type: DataTypes.INTEGER, primaryKey: true }, + externalId: { type: DataTypes.STRING, primaryKey: true }, externalType: DataTypes.STRING }, { timestamps: false, freezeTableName: true }) -- cgit v1.2.3-55-g7522