summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJannik Schönartz2019-03-25 06:43:55 +0100
committerJannik Schönartz2019-03-25 06:43:55 +0100
commit752d9c18bb531544f28bdbfd00b5eb922e07d3d8 (patch)
tree5c4773c2556b0a3aa928574c7ef63a996113c22d
parenteslint fix (diff)
downloadbas-752d9c18bb531544f28bdbfd00b5eb922e07d3d8.tar.gz
bas-752d9c18bb531544f28bdbfd00b5eb922e07d3d8.tar.xz
bas-752d9c18bb531544f28bdbfd00b5eb922e07d3d8.zip
[external-backends/idoit] Add server rack segmentation & add multiple ip support
-rw-r--r--server/api/registration.js11
-rwxr-xr-xserver/ipxe/bash_scripts/addServer.sh158
-rwxr-xr-xserver/ipxe/bash_scripts/grepSystemInfoRework.sh2
-rw-r--r--server/ipxe/registration.ipxe2
-rw-r--r--server/lib/external-backends/backends/idoit-backend.js163
5 files changed, 296 insertions, 40 deletions
diff --git a/server/api/registration.js b/server/api/registration.js
index 4891e31..20e8618 100644
--- a/server/api/registration.js
+++ b/server/api/registration.js
@@ -109,7 +109,7 @@ noAuthRouter.post('/group', (req, res) => {
/*
* Add method for adding a client or server.
*/
-noAuthRouter.postAsync('/', async (req, res) => {
+noAuthRouter.postAsync('/clients', async (req, res) => {
let client = req.body.client
if (typeof client === 'string') client = JSON.parse(client)
@@ -128,13 +128,16 @@ noAuthRouter.postAsync('/', async (req, res) => {
// Client does not exist.
if (!client.parents) client.parents = []
- const createClient = { name: client.name, description: client.type, ip: client.network.ip, mac: client.network.mac, uuid: client.uuid }
+ // TODO: Save all IPs? Maybe only primary ip?
+ // const createClient = { name: client.name, description: client.type, ip: client.network.ip, mac: client.network.mac, uuid: client.uuid }
+ const createClient = { name: client.name, description: client.type, ip: client.networks[0].ip, mac: client.networks[0].mac, uuid: client.uuid }
if (client.type === 'CLIENT') createClient.registrationState = await getNextHookScript(client.parents)
const newClient = await db.client.create(createClient)
client.id = newClient.id
// Add groups to the client.
- if (client.parents.length === 0) client.parents = await ipHelper.getGroups(client.network.ip)
+ // if (client.parents.length === 0) client.parents = await ipHelper.getGroups(client.network.ip)
+ if (client.parents.length === 0) client.parents = await ipHelper.getGroups(client.networks[0].ip)
client.parents.forEach(pid => { newClient.addGroup(pid) })
log({ category: 'CLIENT_REGISTRATION', description: 'Client added successfully.', clientId: newClient.id })
@@ -144,7 +147,7 @@ noAuthRouter.postAsync('/', async (req, res) => {
else return res.send(result)
})
-noAuthRouter.postAsync('/:uuid', async (req, res) => {
+noAuthRouter.postAsync('/clients/:uuid', async (req, res) => {
let client = req.body.client
// Add the name to the ram modules.
diff --git a/server/ipxe/bash_scripts/addServer.sh b/server/ipxe/bash_scripts/addServer.sh
index ad6e3aa..69088bf 100755
--- a/server/ipxe/bash_scripts/addServer.sh
+++ b/server/ipxe/bash_scripts/addServer.sh
@@ -1,21 +1,90 @@
#!/bin/bash
-json_data()
-{
- cat << EOF
+
+
+# We mostly do not care about the return value in function local variable
+# assignments. So we can write the declaration and assignment in one line.
+
+
+
+die() {
+ echo -e "$*" 1>&2
+ exit 1
+}
+
+
+
+usage() {
+ local file="$(basename "$0")"
+
+ die "$file {-r|--rack}=<rack>" \
+ "{-s|--slot}=<slot>" \
+ "[{-b|--bay}=<bay>]" \
+ "[{-i|--interface=<vlan_interface>}]" \
+ "[--rack-height=<height_in_u>]"
+}
+
+
+
+parse_mgmt() {
+ local host="$1"; shift
+
+ local dev="$(ipmitool lan print 1)"
+ cat <<END
+ {
+ "ip": "$(awk '/IP Address\s+:/ {print $4}' <<<"$dev")",
+ "mac": "$(awk '/MAC Address\s+:/ {print $4}' <<<"$dev")",
+ "hostname": "$host.rz.privat"
+ }
+END
+}
+
+
+
+parse_ips() {
+ local host="$1"; shift
+ local if="$1"; shift
+
+ # Requires `moreutils` to be installed, but easier to parse and less error
+ # prone.
+ local ip_frag="$(ifdata -pa "$if" | cut -d. -f3-)"
+ local mac="$(ifdata -ph "$if")"
+ cat <<END
+ {
+ "ip": "10.19.$ip_frag",
+ "mac": "$mac",
+ "hostname": "$host.bwcloud.privat"
+ },
+ {
+ "ip": "10.16.$ip_frag",
+ "mac": "$mac",
+ "hostname": "$host.nemo.privat"
+ }
+END
+}
+
+
+
+json_data() {
+ local pos=$(( rack_height - slot + 1 ))
+ local hostname="$(hostname -s)"
+
+ cat << EOF
{
"client": {
- "parents": [709403],
+ "parents": [$rack],
"type": "SERVER",
+ "name": "$hostname",
"uuid": "$(dmidecode -q -s system-uuid | grep -v '^#' | head -n 1 | tr '[a-z]' '[A-Z]')",
- "network": {
- "mac": "$(ip addr show | grep -Eo -m 1 'ether\s.*\sbrd' | awk '{print $2}')",
- "ip": "$(hostname -I | awk '{print $1}')"
- },
+ "networks": [
+$(parse_mgmt "$hostname"),
+$(parse_ips "$hostname" "$interface")
+ ],
"location": {
"option": "Horizontal",
- "insertion": "Back",
- "pos": 46
+ "insertion": "Front and backside",
+ "slot": $pos,
+ "bay": 1
},
"formfactor": {
"formfactor": "19\"",
@@ -27,5 +96,70 @@ json_data()
EOF
}
-curl -d "$(json_data)" -H "Content-Type: application/json" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registration
-# curl --data "$(json_data)" -H "Content-Type: application/json" -X POST --insecure https://bas.stfu-kthx.net:8888/api/registration \ No newline at end of file
+
+
+args=$(
+ getopt -o b:i:r:s:h \
+ -l bay:,interface:,rack:,rack-height:,slot:,help \
+ -n "$0" \
+ -- \
+ "$@"
+) || usage
+eval set -- "$args"
+
+
+
+bay=0
+interface=boot0.259
+slot=
+rack=
+rack_height=47
+while true; do
+ case "$1" in
+ -b|--bay)
+ bay="$2"
+ echo "Note: This is currently a no-op."
+ echo "Bays need to be implemented first!"
+ shift 2
+ ;;
+ -d|--interface)
+ interface="$2"
+ shift 2
+ ;;
+ -r|--rack)
+ rack="$2"
+ shift 2
+ ;;
+ --rack-height)
+ rack_height="$2";
+ shift 2
+ ;;
+ -s|--slot)
+ slot="$2"
+ shift 2
+ ;;
+ --)
+ shift
+ break
+ ;;
+ -h|--help|*)
+ usage
+ ;;
+ esac
+done
+[[ -z $slot || -z $rack ]] && usage
+
+
+
+case "$rack" in
+ 36|n36|r3s6) rack=19034 ;;
+ 47|n47|r4s7) rack=19045 ;;
+ *) die "Error: unknown rack!" ;;
+esac
+
+(( slot > 47 || slot < 1 )) && die "Error: Slot not in valid range!"
+
+
+
+# json_data
+curl -d "$(json_data)" -H "Content-Type: application/json" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registration/clients
diff --git a/server/ipxe/bash_scripts/grepSystemInfoRework.sh b/server/ipxe/bash_scripts/grepSystemInfoRework.sh
index bdc59b8..ad553fa 100755
--- a/server/ipxe/bash_scripts/grepSystemInfoRework.sh
+++ b/server/ipxe/bash_scripts/grepSystemInfoRework.sh
@@ -168,4 +168,4 @@ EOF
# curl --data "state=6" --insecure https://bas.stfu-kthx.net:8888/api/registrations/$UUID/state
# curl -d "name=Client_$UUID&sys_manufacturer=$MANUFACTURER&sys_model=$MODEL&sys_serial=$SERIAL&cpu_model=$CPU_MODEL&cpu_manufacturer=$CPU_MANUFACTURER&cpu_type=$CPU_TYPE&cpu_cores=$CPU_CORES&cpu_frequency=$CPU_FREQUENCY&ram_size=$RAM_SIZE&ram_manufacturer=$RAM_MANUFACTURER&ram_type=$RAM_TYPE&ram_isecc=$RAM_ISECC&ram_formfactor=$RAM_FORMFACTOR&drives=${DRIVES[*]}" -H "Content-Type: application/x-www-form-urlencoded" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registration/$UUID/update
#echo $(json_data)
-curl -d "$(json_data)" -H "Content-Type: application/json" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registration/$UUID \ No newline at end of file
+curl -d "$(json_data)" -H "Content-Type: application/json" -X POST --insecure https://bas.intra.uni-freiburg.de/api/registration/clients/$UUID \ No newline at end of file
diff --git a/server/ipxe/registration.ipxe b/server/ipxe/registration.ipxe
index 40d6a2a..53f4b01 100644
--- a/server/ipxe/registration.ipxe
+++ b/server/ipxe/registration.ipxe
@@ -27,7 +27,7 @@ goto start
:automatic
params
param ipxe true
-param client { "type": "CLIENT", "uuid": "${uuid}", "purpose": "Pool PC", "network": { "ip": "${net0/ip}", "mac": "${net0/mac}" } }
+param client { "type": "CLIENT", "uuid": "${uuid}", "purpose": "Pool PC", "networks": [{ "ip": "${net0/ip}", "mac": "${net0/mac}" }] }
chain https://bas.intra.uni-freiburg.de/api/registration##params
:key
diff --git a/server/lib/external-backends/backends/idoit-backend.js b/server/lib/external-backends/backends/idoit-backend.js
index ce7680a..c76b6bf 100644
--- a/server/lib/external-backends/backends/idoit-backend.js
+++ b/server/lib/external-backends/backends/idoit-backend.js
@@ -181,19 +181,121 @@ class IdoitBackend extends ExternalBackends {
} else if (client.type === 'SERVER') {
params['type'] = 5
- if (client.location) params.categories.C__CATG__LOCATION = { 'data': { 'parent': client.parentId, 'option': client.location.assembly, 'insertion': client.location.insertion, 'pos': client.location.pos } }
+ if (client.location && !client.location.bay) params.categories.C__CATG__LOCATION = { 'data': { 'parent': client.parentId, 'option': client.location.assembly, 'insertion': client.location.insertion, 'pos': client.location.slot } }
if (client.formfactor) params.categories.C__CATG__FORMFACTOR = { 'data': { 'formfactor': client.formfactor, 'rackunits': client.formfactor.rackunits } }
+
+ // Rack segmentation
+ if (client.location.bay) {
+ // Get all assigned objects of the rack (parentid) to check for existing rack segments at slot position.
+ const rackobjectsBody = this.getBody('cmdb.category.read', { 'apikey': c.apikey, 'object': client.parentId, 'objID': client.parentId, 'category': 'C__CATG__OBJECT' }, 'get_rack_objects')
+ const rackobjects = await this.axiosRequest(c.url, [rackobjectsBody], headers)
+
+ // Get the name of the rack
+ const rackBody = this.getBody('cmdb.category.read', { 'apikey': c.apikey, 'object': client.parentId, 'objID': client.parentId, 'category': 'C__CATG__GLOBAL' }, 'get_rack')
+ const rack = await this.axiosRequest(c.url, [rackBody], headers)
+ const rackName = rack[0].result[0].title
+
+ let objectPositionBodies = []
+
+ // For each segmentation object in the rack get the slot number
+ for (let obj in rackobjects[0].result) {
+ const object = rackobjects[0].result[obj]
+ if (object.assigned_object.type !== 'C__OBJTYPE__RACK_SEGMENT') continue
+ objectPositionBodies.push(this.getBody('cmdb.category.read', { 'apikey': c.apikey, 'object': object.objID, 'objID': object.objID, 'category': 'C__CATG__LOCATION' }, 'get_rack_object_position_' + object.objID))
+ }
+ let objectPositions = await this.axiosRequest(c.url, objectPositionBodies, headers)
+ if (objectPositions.length >= 1) objectPositions = objectPositions.filter(x => parseInt(x.result[0].pos.title) === parseInt(client.location.slot))
+
+ // There should only be one segment object for the rack slot if so set it as parent
+ var chassisId
+ if (objectPositions.length === 1) chassisId = parseInt(objectPositions[0].result[0].objID)
+ else {
+ // Create a new rack segment
+ const createSegmentParamObject = {
+ 'apikey': c.apikey,
+ 'type': 92,
+ 'title': rackName + ' Slot ' + client.location.slot,
+ 'categories': {
+ 'C__CATS__CHASSIS': {
+ 'data': {
+ 'front_x': 4,
+ 'front_y': 2,
+ 'rear_x': 0,
+ 'rear_y': 0
+ }
+ },
+ 'C__CATS__CHASSIS_SLOT': [
+ {
+ 'title': 'Bay 1',
+ 'insertion': 'front',
+ 'from_x': 0,
+ 'to_x': 0,
+ 'from_y': 0,
+ 'to_y': 1
+ },
+ {
+ 'title': 'Bay 2',
+ 'insertion': 'front',
+ 'from_x': 1,
+ 'to_x': 1,
+ 'from_y': 0,
+ 'to_y': 1
+ },
+ {
+ 'title': 'Bay 3',
+ 'insertion': 'front',
+ 'from_x': 2,
+ 'to_x': 2,
+ 'from_y': 0,
+ 'to_y': 1
+ },
+ {
+ 'title': 'Bay 4',
+ 'insertion': 'front',
+ 'from_x': 3,
+ 'to_x': 3,
+ 'from_y': 0,
+ 'to_y': 1
+ }
+ ],
+ 'C__CATG__LOCATION': {
+ 'data': {
+ 'parent': parseInt(client.parentId),
+ 'option': client.location.option,
+ 'insertion': client.location.insertion,
+ 'pos': client.location.slot
+ }
+ }
+ }
+ }
+
+ const createSegmentParam = this.getBody('cmdb.object.create', createSegmentParamObject, 'create_segment')
+ const createSegment = await this.axiosRequest(c.url, [createSegmentParam], headers)
+ chassisId = createSegment[0].result.id
+
+ // Set the new rack units height. (Needs an extra request, why? I DONT KNOW... idoit...)
+ const setSegmentSizeParams = this.getBody('cmdb.category.save', { 'apikey': c.apikey,
+ 'object': chassisId,
+ 'objID': chassisId,
+ 'category': 'C__CATG__FORMFACTOR',
+ 'data': { 'rackunits': client.formfactor.rackunits } }, 'set_segment_size')
+ await this.axiosRequest(c.url, [setSegmentSizeParams], headers)
+ }
+ }
}
// Add categories to the object
if (client.uuid) params.categories.C__CATG__MODEL = { 'data': { 'productid': client.uuid } }
- if (client.network) {
- // TOOD:
- // First read if there are current entries.
- // Delete the previous entries.
- // Finally create the new entry.
-
- if (client.network.ip) params.categories.C__CATG__IP = { 'data': { 'category_id': 1, 'ipv4_address': client.network.ip } }
+ if (client.networks) {
+ params.categories.C__CATG__IP = []
+ for (let network of client.networks) {
+ let networkparams = {}
+ if (network.ip) networkparams.ipv4_address = network.ip
+ if (network.hostname) networkparams.hostname = network.hostname
+ if (network.domain) networkparams.domain = network.domain
+ if (network.net) networkparams.net = network.net
+ params.categories.C__CATG__IP.push(networkparams)
+ }
}
// Send the create request.
@@ -205,27 +307,44 @@ class IdoitBackend extends ExternalBackends {
else if (requestCreate[0].error) return { error: 'IDOIT_ERROR', message: requestCreate[0].error.message }
// Add mac address: Network port is a subcategory of network so it need an extra request.
- if (client.network && client.network.mac) {
- params.categories.C__CATG__NETWORK_PORT = { 'data': { 'category_id': 1, 'mac': client.network.mac } }
- const paramsMac = {
- 'object': requestCreate[0].result.id,
- 'objID': requestCreate[0].result.id,
- 'category': 'C__CATG__NETWORK_PORT',
- 'data': {
- 'category_id': 1,
- 'mac': client.network.mac
- },
- 'apikey': c.apikey
+ let macRequests = []
+ if (client.networks) {
+ for (let index in client.networks) {
+ const network = client.networks[index]
+ // For the idresses
+ // network.id = requestCreate[0].result.categories.C__CATG__IP[index]
+
+ const paramsMac = {
+ 'object': requestCreate[0].result.id,
+ 'objID': requestCreate[0].result.id,
+ 'category': 'C__CATG__NETWORK_PORT',
+ 'data': {
+ 'mac': network.mac
+ },
+ 'apikey': c.apikey
+ }
+ const bodyMac = this.getBody('cmdb.category.save', paramsMac, 'add_mac_address')
+ const response = await this.axiosRequest(c.url, [bodyMac], headers)
+ macRequests.push(response)
}
- const bodyMac = this.getBody('cmdb.category.save', paramsMac, 'add_mac_address')
- await this.axiosRequest(c.url, [bodyMac], headers)
+ }
+
+ // If chassis id is set, assign the object to the chassis bay
+ if (chassisId) {
+ const bay = client.location.bay + ''
+ const assignToSlotBody = this.getBody('cmdb.category.save', { 'apikey': c.apikey,
+ 'objID': chassisId,
+ 'object': chassisId,
+ 'category': 'C__CATS__CHASSIS_DEVICES',
+ 'data': { 'assigned_device': requestCreate[0].result.id, 'assigned_slots': [bay] } }, 'assign_to_slot')
+ await this.axiosRequest(c.url, [assignToSlotBody], headers)
}
// Purpose for Clients:
// 1 = Production | 5 = PVS
// 2 = Test | 7 = Pool PC
// 3 = Quality Assurance | 8 = Mitarbeiter Arbeitsplatz
- return { succes: true, id: requestCreate[0].result.id, type: params.type, message: requestCreate[0].result.message }
+ return { succes: true, id: requestCreate[0].result.id, type: params.type, message: requestCreate[0].result.message, macRequests: macRequests }
}
/*