Skip to content

Instantly share code, notes, and snippets.

@czechnology
Last active January 3, 2024 16:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save czechnology/fb989fc0ee740c7b9945a9620d60ab6b to your computer and use it in GitHub Desktop.
Save czechnology/fb989fc0ee740c7b9945a9620d60ab6b to your computer and use it in GitHub Desktop.
Simple tool to parse the BMC web console of a Nokia Airframe rack server and retrieve the MAC addresses of all available interfaces. Output as ASCII table or tab-separated values (for simple copying to a spreadsheet).
#!/usr/bin/env python
"""
Simple tool to parse the BMC web console of a Nokia Airframe rack server and
retrieve the MAC addresses of all available interfaces. Output as ASCII table
or tab-separated values (for simple copying to a spreadsheet).
Example usage:
./bmc.py -u admin -p admin 10.11.12.101 10.11.12.102 10.11.12.103
Tested with BMC Web UI version 1.00.0, KVM Remote Console Utility Version
1.70.0. Modifications may be required for other versions of the console.
Requires: Requests lib (http://docs.python-requests.org)
Author: Martin Kulhavy
License: GPL
"""
import argparse
import ast
import json
import re
import sys
import requests
import urllib3
from requests import Session
__author__ = "Martin Kulhavy"
class BmcWebClient:
def __init__(self, host, user, passwd):
self.host = host
self.user = user
self.passwd = passwd
self.session = None
self.session_cookie = None
def login(self):
if not self.session:
self.session = Session()
url = "https://%s/rpc/WEBSES/create.asp" % self.host
data = {"WEBVAR_USERNAME": self.user, "WEBVAR_PASSWORD": self.passwd}
resp = self.session.post(url, data, verify=False)
dynamic_data_match = re.search(
'//Dynamic Data Begin\s*'
'WEBVAR_JSONVAR_WEB_SESSION =\s*'
'(.+?)\s*'
'(//Dynamic data end\s*)?$',
resp.text, re.DOTALL)
if not dynamic_data_match:
raise Exception("Unexpected response: \n%s" % resp.text)
dynamic_data = dynamic_data_match.group(1)
# The data is not a valid JSON so instead of parsing,
# let's just use regex
m = re.search("'SESSION_COOKIE'\s*:\s*'([^']+)'", dynamic_data)
if not m:
raise Exception("No session cookie received")
self.session_cookie = m.group(1)
m = re.search("'BMC_IP_ADDR'\s*:\s*'([.0-9]+)'", dynamic_data)
if not m or m.group(1) != self.host:
raise Exception("Wrong BMC host")
return self.session_cookie
def _session_get(self, path):
url = 'https://' + self.host
url += path if path.startswith('/') else '/' + path
cookies = {'SessionCookie': self.session_cookie, 'Username': self.user}
return self.session.get(url, cookies=cookies, verify=False)
def get_system_mac(self):
if not self.session:
self.login()
path = "/rpc/getsystemmac.asp"
resp = self._session_get(path)
dynamic_data_match = re.search(
'//Dynamic Data Begin\s*'
'WEBVAR_JSONVAR_HL_GETSYSTEMMACINFO =\s*{\s*'
'WEBVAR_STRUCTNAME_HL_GETSYSTEMMACINFO\s*:\s*'
'(.+?)\s*'
',\s*HAPI_STATUS\s*:\s*0\s*};',
resp.text, re.DOTALL)
if not dynamic_data_match:
raise Exception("Unexpected response: \n%s" % resp.text)
dynamic_data = dynamic_data_match.group(1)
system_mac_info = json.loads(dynamic_data.replace("'", '"'))
interfaces = []
for intf in system_mac_info:
if not intf:
continue
name_match = re.match('^(.+)\s*:\s*[:0-9a-f]{17}',
intf['MAC_ADDRESS_STR'], re.IGNORECASE)
if name_match:
name = name_match.group(1).strip()
else:
name = intf['MAC_ADDRESS_STR']
interfaces.append({'name': name, 'mac': intf['MAC_ADDRESS']})
return interfaces
def main(hosts, user, passwd, output_format='ascii'):
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
if output_format == 'ascii':
line_format = '| {0:<15} | {1:<17} | {2:30} |'
elif output_format == 'tsv':
line_format = '{0}\t{1}\t{2}'
else:
raise ValueError('Unknown format')
# Print values
if output_format == 'ascii':
table_separator = '+{0:-<17}+{0:-<19}+{0:-<32}+'.format('')
print(table_separator)
print(line_format.format(
'BMC host/IP', 'MAC address', 'Name (if available)'))
print(table_separator)
for host in hosts:
client = BmcWebClient(host, user, passwd)
macs = client.get_system_mac()
for mac in macs:
print(line_format.format(host, mac['mac'], mac['name']))
if output_format == 'ascii':
print(table_separator)
if __name__ == "__main__":
desc = ("Simple tool to parse the BMC web console of a Nokia Airframe "
"rack server and retrieve the MAC addresses of all available "
"interfaces. Output as ASCII table or tab-separated values"
"(for simple copying to a spreadsheet).\n"
"Example usage: ./bmc.py -u admin -p admin "
"10.11.12.101 10.11.12.102 10.11.12.103")
epi = "Author: Martin Kulhavy, 2017"
parser = argparse.ArgumentParser(description=desc, epilog=epi)
parser.add_argument('-u', '--user', default='admin',
help="Username to log in with to the BMC console")
parser.add_argument('-p', '--passwd', default='admin',
help="Password to log in with to the BMC console")
parser.add_argument('-f', '--format', default='ascii',
choices=['ascii', 'tsv'],
help="Output format (ASCII table, tab-separated values")
parser.add_argument('host', nargs='+',
help="One or more hosts to connect to")
parsed = parser.parse_args(sys.argv[1:])
main(hosts=parsed.host, user=parsed.user, passwd=parsed.passwd,
output_format=parsed.format)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment