From b9f994e71d1bc9548ca1ef127db8c8600d8d92c5 Mon Sep 17 00:00:00 2001 From: david Date: Mon, 13 Jul 2009 05:34:13 +0000 Subject: [PATCH] Add script output to Ndiff XML output. --- ndiff/docs/ndiff.dtd | 13 +++-- ndiff/ndiff | 122 ++++++++++++++++++++++++++++++++++++++++--- ndiff/ndifftest.py | 13 ++++- 3 files changed, 136 insertions(+), 12 deletions(-) diff --git a/ndiff/docs/ndiff.dtd b/ndiff/docs/ndiff.dtd index 93c816afe..d72647841 100644 --- a/ndiff/docs/ndiff.dtd +++ b/ndiff/docs/ndiff.dtd @@ -76,7 +76,7 @@ version 0, which was rather different. --> - + @@ -93,13 +93,13 @@ version 0, which was rather different. --> - + - + @@ -113,12 +113,17 @@ version 0, which was rather different. --> extrainfo CDATA #IMPLIED tunnel CDATA #IMPLIED> + + - + + + diff --git a/ndiff/ndiff b/ndiff/ndiff index 35edb60d3..0e040c3df 100755 --- a/ndiff/ndiff +++ b/ndiff/ndiff @@ -174,6 +174,12 @@ class Host(object): os_elem.appendChild(self.os_to_dom_fragment(document, os)) elem.appendChild(os_elem) + if len(self.script_results) > 0: + hostscript_elem = document.createElement(u"hostscript") + for sr in self.script_results: + hostscript_elem.appendChild(sr.to_dom_fragment(document)) + elem.appendChild(hostscript_elem) + frag.appendChild(elem) return frag @@ -260,7 +266,8 @@ class Port(object): d = cmp(self.spec, other.spec) if d != 0: return d - return cmp((self.spec, self.service), (other.spec, other.service)) + return cmp((self.spec, self.service, self.script_results), + (other.spec, other.service, other.script_results)) def to_dom_fragment(self, document): frag = document.createDocumentFragment() @@ -272,6 +279,8 @@ class Port(object): state_elem.setAttribute(u"state", self.state) elem.appendChild(state_elem) elem.appendChild(self.service.to_dom_fragment(document)) + for sr in self.script_results: + elem.appendChild(sr.to_dom_fragment(document)) frag.appendChild(elem) return frag @@ -450,6 +459,7 @@ class HostDiff(object): self.ports = [] self.port_diffs = {} self.os_diffs = [] + self.script_result_diffs = [] self.cost = 0 self.diff() @@ -492,6 +502,9 @@ class HostDiff(object): self.extraports_changed = True self.cost += 1 + self.script_result_diffs = ScriptResultDiff.diff_lists(self.host_a.script_results, self.host_b.script_results) + self.cost += len(self.script_result_diffs) + def include_diff(self, diff): # Don't include the diff if the states are only extraports. Include all # diffs, even those with cost == 0, in verbose mode. @@ -684,6 +697,28 @@ class HostDiff(object): if os_elem.hasChildNodes(): host_elem.appendChild(os_elem) + # Host script changes. + if len(self.script_result_diffs) > 0 or verbose: + hostscript_elem = document.createElement(u"hostscript") + if len(host_a.script_results) == 0 and len(host_b.script_results) == 0: + pass + elif len(host_b.script_results) == 0: + a_elem = document.createElement(u"a") + for sr in host_a.script_results: + a_elem.appendChild(sr.to_dom_fragment(document)) + a_elem.appendChild(hostscript_elem) + host_elem.appendChild(a_elem) + elif len(host_a.script_results) == 0: + b_elem = document.createElement(u"b") + for sr in host_b.script_results: + b_elem.appendChild(sr.to_dom_fragment(document)) + b_elem.appendChild(hostscript_elem) + host_elem.appendChild(b_elem) + else: + for sr_diff in self.script_result_diffs: + hostscript_elem.appendChild(sr_diff.to_dom_fragment(document)) + host_elem.appendChild(hostscript_elem) + hostdiff_elem.appendChild(host_elem) return frag @@ -694,6 +729,7 @@ class PortDiff(object): def __init__(self, port_a, port_b): self.port_a = port_a self.port_b = port_b + self.script_result_diffs = [] self.cost = 0 self.diff() @@ -708,6 +744,9 @@ class PortDiff(object): if self.port_a.service != self.port_b.service: self.cost += 1 + self.script_result_diffs = ScriptResultDiff.diff_lists(self.port_a.script_results, self.port_b.script_results) + self.cost += len(self.script_result_diffs) + # PortDiffs are inserted into a Table and then printed, not printed out # directly. That's why this class has append_to_port_table instead of # print_text. @@ -736,14 +775,83 @@ class PortDiff(object): frag = document.createDocumentFragment() portdiff_elem = document.createElement(u"portdiff") frag.appendChild(portdiff_elem) - a_elem = document.createElement(u"a") - b_elem = document.createElement(u"b") - portdiff_elem.appendChild(a_elem) - portdiff_elem.appendChild(b_elem) + if self.port_a.spec == self.port_b.spec and self.port_a.state == self.port_b.state: + port_elem = document.createElement(u"port") + port_elem.setAttribute(u"portid", unicode(self.port_a.spec[0])) + port_elem.setAttribute(u"protocol", self.port_a.spec[1]) + if self.port_a.state is not None: + state_elem = document.createElement(u"state") + state_elem.setAttribute(u"state", self.port_a.state) + port_elem.appendChild(state_elem) + if self.port_a.service == self.port_b.service: + port_elem.appendChild(self.port_a.service.to_dom_fragment(document)) + else: + a_elem = document.createElement(u"a") + a_elem.appendChild(self.port_a.service.to_dom_fragment(document)) + port_elem.appendChild(a_elem) + b_elem = document.createElement(u"b") + b_elem.appendChild(self.port_b.service.to_dom_fragment(document)) + port_elem.appendChild(b_elem) + for sr_diff in self.script_result_diffs: + port_elem.appendChild(sr_diff.to_dom_fragment(document)) + portdiff_elem.appendChild(port_elem) + else: + a_elem = document.createElement(u"a") + a_elem.appendChild(self.port_a.to_dom_fragment(document)) + portdiff_elem.appendChild(a_elem) + b_elem = document.createElement(u"b") + b_elem.appendChild(self.port_b.to_dom_fragment(document)) + portdiff_elem.appendChild(b_elem) - a_elem.appendChild(self.port_a.to_dom_fragment(document)) - b_elem.appendChild(self.port_b.to_dom_fragment(document)) + return frag +class ScriptResultDiff(object): + def __init__(self, sr_a, sr_b): + """One of sr_a and sr_b may be None.""" + self.sr_a = sr_a + self.sr_b = sr_b + + def diff_lists(a, b): + """Return a list of ScriptResultDiffs from two sorted lists of + ScriptResults.""" + diffs = [] + i = 0 + j = 0 + # This algorithm is like a merge of sorted lists. + while i < len(a) and j < len(b): + if a[i].id < b[j].id: + diffs.append(ScriptResultDiff(a[i], None)) + i += 1 + elif a[i].id > b[j].id: + diffs.append(ScriptResultDiff(None, b[j])) + j += 1 + else: + if a[i].output != b[j].output or verbose: + diffs.append(ScriptResultDiff(a[i], b[j])) + i += 1 + j += 1 + while i < len(a): + diffs.append(ScriptResultDiff(a[i], None)) + i += 1 + while j < len(b): + diffs.append(ScriptResultDiff(None, b[j])) + j += 1 + return diffs + diff_lists = staticmethod(diff_lists) + + def to_dom_fragment(self, document): + frag = document.createDocumentFragment() + if self.sr_a is not None and self.sr_b is not None and self.sr_a == self.sr_b: + frag.appendChild(self.sr_a.to_dom_fragment(document)) + else: + if self.sr_a is not None: + a_elem = document.createElement(u"a") + a_elem.appendChild(self.sr_a.to_dom_fragment(document)) + frag.appendChild(a_elem) + if self.sr_b is not None: + b_elem = document.createElement(u"b") + b_elem.appendChild(self.sr_b.to_dom_fragment(document)) + frag.appendChild(b_elem) return frag class Table(object): diff --git a/ndiff/ndifftest.py b/ndiff/ndifftest.py index d42f84f99..9be1a4b07 100755 --- a/ndiff/ndifftest.py +++ b/ndiff/ndifftest.py @@ -323,7 +323,7 @@ class scan_diff_test(unittest.TestCase): diff = ScanDiff(a, b) scan_apply_diff(a, diff) diff = ScanDiff(a, b) - self.assertEqual(len(diff.host_diffs), 0, "%d != 0 in pair %s" % (len(diff.host_diffs), str(pair))) + self.assertEqual(diff.host_diffs, {}) self.assertEqual(set(diff.hosts), set(diff.host_diffs.keys())) class parse_port_list_test(unittest.TestCase): @@ -712,4 +712,15 @@ def host_apply_diff(host, diff): else: host.ports[port.spec] = diff.port_diffs[port].port_b + for sr_diff in diff.script_result_diffs: + sr_a = sr_diff.sr_a + sr_b = sr_diff.sr_b + if sr_a is None: + host.script_results.append(sr_b) + elif sr_b is None: + host.script_results.remove(sr_a) + else: + host.script_results[host.script_results.index(sr_a)] = sr_b + host.script_results.sort() + unittest.main()