]> www.infradead.org Git - users/hch/xfsprogs.git/commitdiff
xfs_scrubbed: check events against schema
authorDarrick J. Wong <djwong@kernel.org>
Wed, 7 Aug 2024 22:54:56 +0000 (15:54 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 14 Aug 2024 03:08:27 +0000 (20:08 -0700)
Validate that the event objects that we get from the kernel actually
obey the schema that the kernel publishes.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
libxfs/Makefile
scrub/Makefile
scrub/xfs_scrubbed.in

index 458bb7d6113bcfc07bd246ac94c4345476a992e1..daf453d943057725cef769cb5552324a6159d956 100644 (file)
@@ -154,20 +154,24 @@ LTLIBS = $(LIBPTHREAD) $(LIBRT)
 # don't try linking xfs_repair with a debug libxfs.
 DEBUG = -DNDEBUG
 
-default: ltdepend $(LTLIBRARY)
+JSON_SCHEMAS=xfs_healthmon.schema.json
+
+default: ltdepend $(LTLIBRARY) $(JSON_SCHEMAS)
 
 # set up include/xfs header directory
 include $(BUILDRULES)
 
 install: default
-       $(INSTALL) -m 755 -d $(PKG_INC_DIR)
+       $(INSTALL) -m 755 -d $(PKG_DATA_DIR)
+       $(INSTALL) -m 644 $(JSON_SCHEMAS) $(PKG_DATA_DIR)
 
 install-headers: $(addsuffix -hdrs, $(PKGHFILES))
 
 %-hdrs:
        $(Q)$(LN_S) -f $(CURDIR)/$* $(TOPDIR)/include/xfs/$*
 
-install-dev: install
+install-dev: default
+       $(INSTALL) -m 755 -d $(PKG_INC_DIR)
        $(INSTALL) -m 644 $(PKGHFILES) $(PKG_INC_DIR)
 
 # We need to install the headers before building the dependencies.  If we
index 78c3097b59fe348aefaf0da81717f4744345a5c8..32363161f8aa4e6484b6f3f904db6063d3293566 100644 (file)
@@ -133,6 +133,7 @@ xfs_scrubbed: xfs_scrubbed.in $(builddefs)
        $(Q)$(SED) -e "s|@sbindir@|$(PKG_SBIN_DIR)|g" \
                   -e "s|@scrub_svcname@|$(scrub_svcname)|g" \
                   -e "s|@pkg_version@|$(PKG_VERSION)|g" \
+                  -e "s|@pkg_data_dir@|$(PKG_DATA_DIR)|g" \
                   < $< > $@
        $(Q)chmod a+x $@
 
index 9c7aec47836a92a6093466ceffad6dbccf34afad..abe0761f0e608bf2730304fbe6dbf2da804a7eac 100644 (file)
@@ -17,6 +17,52 @@ import errno
 import ctypes
 from concurrent.futures import ProcessPoolExecutor
 
+try:
+       # Not all systems will have this json schema validation libarary,
+       # so we make it optional.
+       import jsonschema
+
+       def init_validation(args):
+               '''Initialize event json validation.'''
+               try:
+                       with open(args.event_schema) as fp:
+                               schema_js = json.load(fp)
+               except Exception as e:
+                       print(f"{args.event_schema}: {e}", file = sys.stderr)
+                       return
+
+               try:
+                       vcls = jsonschema.validators.validator_for(schema_js)
+                       vcls.check_schema(schema_js)
+                       validator = vcls(schema_js)
+               except jsonschema.exceptions.SchemaError as e:
+                       print(f"{args.event_schema}: {e.message}",
+                                       file = sys.stderr)
+                       return
+               except Exception as e:
+                       print(f"{args.event_schema}: {e}", file = sys.stderr)
+                       return
+
+               def v(i):
+                       e = jsonschema.exceptions.best_match(validator.iter_errors(i))
+                       if e:
+                               print(f"{printf_prefix}: {e.message}",
+                                               file = sys.stderr)
+                               return False
+                       return True
+
+               return v
+
+except:
+       def init_validation(args):
+               if args.require_validation:
+                       print("JSON schema validation not available.",
+                                       file = sys.stderr)
+                       return
+
+               return lambda instance: True
+
+validator_fn = None
 debug = False
 log = False
 everything = False
@@ -175,6 +221,12 @@ def handle_event(event):
 
        global log
 
+       # Ignore any event that doesn't pass our schema.  This program must
+       # not try to handle a newer kernel that say things that it is not
+       # prepared to handle.
+       if not validator_fn(event):
+               return
+
        stringify_timestamp(event)
        if log:
                log_event(event)
@@ -212,6 +264,7 @@ def main():
        global log
        global printf_prefix
        global everything
+       global validator_fn
 
        parser = argparse.ArgumentParser( \
                        description = "XFS filesystem health monitoring demon.")
@@ -225,6 +278,11 @@ def main():
                        action = "store_true")
        parser.add_argument('mountpoint', default = None, nargs = '?',
                        help = 'XFS filesystem mountpoint to target.')
+       parser.add_argument('--require-validation', action = 'store_true', \
+                       help = argparse.SUPPRESS)
+       parser.add_argument('--event-schema', type = str, \
+                       default = '@pkg_data_dir@/xfs_healthmon.schema.json', \
+                       help = argparse.SUPPRESS)
        args = parser.parse_args()
 
        if args.V:
@@ -235,6 +293,10 @@ def main():
                parser.error("the following arguments are required: mountpoint")
                return 1
 
+       validator_fn = init_validation(args)
+       if not validator_fn:
+               return 1
+
        if args.debug:
                debug = True
        if args.log: