Merge lp:~rvb/maas-test/bmc-params-1 into lp:maas-test

Proposed by Raphaël Badin
Status: Merged
Merged at revision: 49
Proposed branch: lp:~rvb/maas-test/bmc-params-1
Merge into: lp:maas-test
Diff against target: 116 lines (+79/-1)
2 files modified
maastest/tests/test_utils.py (+56/-0)
maastest/utils.py (+23/-1)
To merge this branch: bzr merge lp:~rvb/maas-test/bmc-params-1
Reviewer Review Type Date Requested Status
Julian Edwards (community) Disapprove
Graham Binns (community) Approve
Review via email: mp+196107@code.launchpad.net

Commit message

Add utility to parse nmap output.

Description of the change

This is the first branch in a series of branches aimed at adding a fully-automated, non-interactive testing mode where all the BMC details (MAC address, username and password) are given on the command line and then used to power up the node instead of asking the user to do that manually.

This branch adds a simple utility: a parser for the output of nmap. We will use nmap to scan the network and find the IP address of the BMC given its MAC address.

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) :
review: Approve
lp:~rvb/maas-test/bmc-params-1 updated
48. By Raphaël Badin

Merge trunk.

Revision history for this message
Julian Edwards (julian-edwards) wrote :

You need to rethink this, please don't use NMAP. It is largely disallowed on many networks.

There is a utility for working out IPs from MACs, it's called "arp". Better still perhaps use ipmiping.

review: Disapprove

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'maastest/tests/test_utils.py'
--- maastest/tests/test_utils.py 2013-11-20 11:48:59 +0000
+++ maastest/tests/test_utils.py 2013-11-21 14:36:23 +0000
@@ -15,6 +15,7 @@
15import os.path15import os.path
16import platform16import platform
17from subprocess import PIPE17from subprocess import PIPE
18from textwrap import dedent
18import time19import time
1920
20import distro_info21import distro_info
@@ -244,3 +245,58 @@
244 self.assertEqual(supported, utils.get_supported_series())245 self.assertEqual(supported, utils.get_supported_series())
245 else:246 else:
246 self.assertEqual(supported, utils.get_supported_series())247 self.assertEqual(supported, utils.get_supported_series())
248
249
250class TestExtractMAPIPMapping(testtools.TestCase):
251
252 def test_extract_mac_ip_mapping_parses_output(self):
253 NMAP_XML_OUTPUT = dedent("""
254 <nmaprun scanner="nmap" args="nmap -sP -oX - 192.168.2.0/24">
255 <host>
256 <address addr="192.168.2.2" addrtype="ipv4"/>
257 <address addr="00:9C:02:A2:82:74" addrtype="mac"/>
258 </host>
259 <host>
260 <address addr="192.168.2.4" addrtype="ipv4"/>
261 <address addr="00:9C:02:A0:4D:0A" addrtype="mac"/>
262 </host>
263 </nmaprun>
264 """)
265 expected_result = {
266 '00:9C:02:A2:82:74': '192.168.2.2',
267 '00:9C:02:A0:4D:0A': '192.168.2.4',
268 }
269 self.assertEqual(
270 expected_result, utils.extract_mac_ip_mapping(NMAP_XML_OUTPUT))
271
272 def test_extract_mac_ip_mapping_returns_uppercase_mac(self):
273 NMAP_XML_OUTPUT = dedent("""
274 <nmaprun scanner="nmap" args="nmap -sP -oX - 192.168.2.0/24">
275 <host>
276 <address addr="192.168.2.2" addrtype="ipv4"/>
277 <address addr="AA:bb:cc:dd:ee:FF" addrtype="mac"/>
278 </host>
279 </nmaprun>
280 """)
281 expected_result = {'AA:BB:CC:DD:EE:FF': '192.168.2.2'}
282 self.assertEqual(
283 expected_result, utils.extract_mac_ip_mapping(NMAP_XML_OUTPUT))
284
285 def test_extract_mac_ip_mapping_with_empty_doc(self):
286 self.assertEqual(
287 {}, utils.extract_mac_ip_mapping('<nmaprun></nmaprun>'))
288
289 def test_extract_mac_ip_mapping_with_missing_info(self):
290 # If either the IP address of the MAC address is missing in a host
291 # definition, the host entry is not considered.
292 NMAP_XML_OUTPUT = dedent("""
293 <nmaprun scanner="nmap" args="nmap -sP -oX - 192.168.2.0/24">
294 <host>
295 <address addr="192.168.2.2" addrtype="ipv4"/>
296 </host>
297 <host>
298 <address addr="00:9C:02:A0:4D:0A" addrtype="mac"/>
299 </host>
300 </nmaprun>
301 """)
302 self.assertEqual({}, utils.extract_mac_ip_mapping(NMAP_XML_OUTPUT))
247303
=== modified file 'maastest/utils.py'
--- maastest/utils.py 2013-11-20 11:50:18 +0000
+++ maastest/utils.py 2013-11-21 14:36:23 +0000
@@ -33,6 +33,7 @@
33 )33 )
3434
35import distro_info35import distro_info
36from lxml import etree
36from testtools.content import Content37from testtools.content import Content
37from testtools.content_type import ContentType38from testtools.content_type import ContentType
3839
@@ -64,7 +65,6 @@
64 api_root = '/api/1.0/'65 api_root = '/api/1.0/'
65 return api_root + path66 return api_root + path
6667
67
68BINARY = ContentType("application", "octet-stream")68BINARY = ContentType("application", "octet-stream")
6969
7070
@@ -137,3 +137,25 @@
137 cut_off_index = (137 cut_off_index = (
138 supported.index('precise') if 'precise' in supported else 0)138 supported.index('precise') if 'precise' in supported else 0)
139 return supported[cut_off_index:]139 return supported[cut_off_index:]
140
141
142def extract_mac_ip_mapping(nmap_xml_scan):
143 """Extract the IP->MAC address mapping from the result of a nmap scan.
144
145 The returned mapping uses uppercase MAC addresses.
146
147 :param nmap_xml_scan: The XML result of scanning a network using nmap.
148 Scanning a network using nmap is typically done by running:
149 `nmap -sP <network_definition> -oX -`.
150 :type nmap_xml_scan: string
151 """
152 parser = etree.XMLParser(remove_blank_text=True)
153 xml_doc = etree.fromstring(nmap_xml_scan, parser)
154 hosts = xml_doc.xpath("/nmaprun/host")
155 mapping = {}
156 for host in hosts:
157 ips = host.xpath("address[@addrtype='ipv4']/@addr")
158 macs = host.xpath("address[@addrtype='mac']/@addr")
159 if len(ips) == 1 and len(macs) == 1:
160 mapping[macs[0].upper()] = ips[0]
161 return mapping

Subscribers

People subscribed via source and target branches