Browse Source

[2380] added minimal post-load zone checks

JINMEI Tatuya 12 years ago
parent
commit
d08ad5667f

+ 23 - 0
src/bin/loadzone/loadzone.py.in

@@ -204,6 +204,28 @@ class LoadZoneRunner:
                              self._zone_class)
             raise LoadFailure(str(ex))
 
+    def _post_load_checks(self):
+        '''Perform minimal validity checks on the loaded zone.
+
+        We do this ourselves because the underlying library currently
+        doesn't do any checks.  Once the library support post-load validation
+        this check should be removed.
+
+        '''
+        datasrc_client = DataSourceClient(self._datasrc_type,
+                                          self._datasrc_config)
+        _, finder = datasrc_client.find_zone(self._zone_name) # should succeed
+        result = finder.find(self._zone_name, RRType.SOA())[0]
+        if result is not finder.SUCCESS:
+            self._post_load_warning('zone has no SOA')
+        result = finder.find(self._zone_name, RRType.NS())[0]
+        if result is not finder.SUCCESS:
+            self._post_load_warning('zone has no NS')
+
+    def _post_load_warning(self, msg):
+        logger.warn(LOADZONE_POSTLOAD_ISSUE, self._zone_name,
+                    self._zone_class, msg)
+
     def run(self):
         '''Top-level method, simply calling other helpers'''
 
@@ -211,6 +233,7 @@ class LoadZoneRunner:
             self._parse_args()
             self._do_load()
             logger.info(LOADZONE_DONE, self._zone_name, self._zone_class)
+            self._post_load_checks()
             return 0
         except BadArgument as ex:
             logger.error(LOADZONE_ARGUMENT_ERROR, ex)

+ 2 - 0
src/bin/loadzone/loadzone_messages.mes

@@ -29,3 +29,5 @@
 % LOADZONE_LOADING Loaded %1 RRs into %2/%3, continued
 
 % LOADZONE_DONE Load zone %1/%2 completed
+
+% LOADZONE_POSTLOAD_ISSUE New version of zone %1/%2 has an issue: %3

+ 2 - 0
src/bin/loadzone/tests/Makefile.am

@@ -4,6 +4,8 @@ PYTESTS = loadzone_test.py
 EXTRA_DIST = $(PYTESTS)
 EXTRA_DIST += testdata/example.org.zone
 EXTRA_DIST += testdata/broken-example.org.zone
+EXTRA_DIST += testdata/example-nosoa.org.zone
+EXTRA_DIST += testdata/example-nons.org.zone
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
 # required by loadable python modules.

+ 40 - 2
src/bin/loadzone/tests/loadzone_test.py

@@ -125,6 +125,8 @@ class TestLoadZoneRunner(unittest.TestCase):
         """Check that the given SOA RR exists and matches the expected string
 
         If soa_txt is None, the zone is expected to be non-existent.
+        Otherwise, if soa_txt is False, the zone should exist but SOA is
+        expected to be missing.
 
         """
 
@@ -135,8 +137,11 @@ class TestLoadZoneRunner(unittest.TestCase):
             return
         self.assertEqual(client.SUCCESS, result)
         result, rrset, _ = finder.find(zone_name, RRType.SOA())
-        self.assertEqual(finder.SUCCESS, result)
-        self.assertEqual(soa_txt, rrset.to_text())
+        if soa_txt:
+            self.assertEqual(finder.SUCCESS, result)
+            self.assertEqual(soa_txt, rrset.to_text())
+        else:
+            self.assertEqual(finder.NXRRSET, result)
 
     def test_load_update(self):
         '''successful case to loading new contents to an existing zone.'''
@@ -190,6 +195,39 @@ class TestLoadZoneRunner(unittest.TestCase):
         # _do_load() should have once created the zone but then canceled it.
         self.__check_zone_soa(None, zone_name=Name('example.com'))
 
+    def __common_post_load_setup(self, zone_file):
+        '''Common setup procedure for post load tests.'''
+        # replace the LoadZoneRunner's original _post_load_warning() for
+        # inspection
+        self.__warnings = []
+        self.__runner._post_load_warning = \
+            lambda msg: self.__warnings.append(msg)
+
+        # perform load and invoke checks
+        self.__common_load_setup()
+        self.__runner._zone_file = zone_file
+        self.__check_zone_soa(ORIG_SOA_TXT)
+        self.__runner._do_load()
+        self.__runner._post_load_checks()
+
+    def test_load_fail_create_cancel(self):
+        '''Load succeeds but warns about missing SOA, should cause warn'''
+        self.__common_load_setup()
+        self.__common_post_load_setup(LOCAL_TESTDATA_PATH +
+                                      '/example-nosoa.org.zone')
+        self.__check_zone_soa(False)
+        self.assertEqual(1, len(self.__warnings))
+        self.assertEqual('zone has no SOA', self.__warnings[0])
+
+    def test_load_fail_create_cancel(self):
+        '''Load succeeds but warns about missing NS, should cause warn'''
+        self.__common_load_setup()
+        self.__common_post_load_setup(LOCAL_TESTDATA_PATH +
+                                      '/example-nons.org.zone')
+        self.__check_zone_soa(NEW_SOA_TXT)
+        self.assertEqual(1, len(self.__warnings))
+        self.assertEqual('zone has no NS', self.__warnings[0])
+
     def test_run_success(self):
         '''Check for the top-level method.
 

+ 10 - 0
src/bin/loadzone/tests/testdata/example-nons.org.zone

@@ -0,0 +1,10 @@
+;; Intentionally missing SOA for testing post-load checks
+example.org.    3600    IN  SOA (
+		ns.example.org.
+		admin.example.org.
+		1235
+		3600		;1H
+		1800		;30M
+		2419200
+		7200)
+ns.example.org.	3600    IN  A 192.0.2.1

+ 3 - 0
src/bin/loadzone/tests/testdata/example-nosoa.org.zone

@@ -0,0 +1,3 @@
+;; Intentionally missing SOA for testing post-load checks
+example.org.    3600    IN  NS ns.example.org.
+ns.example.org.	3600    IN  A 192.0.2.1