From: Jason Ish Date: Thu, 7 Dec 2017 13:18:06 +0000 (-0600) Subject: -D, --data-dir to change the data directory X-Git-Tag: 1.0.0b1~29 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=472eb4da570426b185cf1d1337b4e0b4d834f0d0;p=thirdparty%2Fsuricata-update.git -D, --data-dir to change the data directory By default /var/lib/suricata is used. But for various reasons including permissions and testing it can be useful to change this. The data directory serves as the prefix for suricata-update work directories, including rules/ and update/sources, and update/cache. Addresses issue: https://redmine.openinfosecfoundation.org/issues/2334 --- diff --git a/suricata/update/config.py b/suricata/update/config.py index 2190d88..7aa99ea 100644 --- a/suricata/update/config.py +++ b/suricata/update/config.py @@ -22,10 +22,16 @@ import yaml logger = logging.getLogger() -DEFAULT_STATE_DIRECTORY = "/var/lib/suricata" +DEFAULT_DATA_DIRECTORY = "/var/lib/suricata" + +# Cache directory - relative to the data directory. +CACHE_DIRECTORY = os.path.join("update", "cache") + +# Source directory - relative to the data directory. +SOURCE_DIRECTORY = os.path.join("update", "sources") # Configuration keys. -STATE_DIRECTORY_KEY = "state-directory" +DATA_DIRECTORY_KEY = "data-directory" CACHE_DIRECTORY_KEY = "cache-directory" IGNORE_KEY = "ignore" DISABLE_CONF_KEY = "disable-conf" @@ -33,6 +39,7 @@ ENABLE_CONF_KEY = "enable-conf" MODIFY_CONF_KEY = "modify-conf" DROP_CONF_KEY = "drop-conf" LOCAL_CONF_KEY = "local" +OUTPUT_KEY = "output" DEFAULT_UPDATE_YAML_PATH = "/etc/suricata/update.yaml" @@ -64,12 +71,18 @@ def get(key): return None def set_state_dir(directory): - _config[STATE_DIRECTORY_KEY] = directory + _config[DATA_DIRECTORY_KEY] = directory def get_state_dir(): - if STATE_DIRECTORY_KEY in _config: - return _config[STATE_DIRECTORY_KEY] - return DEFAULT_STATE_DIRECTORY + """Get the data directory. This is more of the Suricata state + directory than a specific Suricata-Update directory, and is used + as the root directory for Suricata-Update data. + """ + if os.getenv("DATA_DIRECTORY"): + return os.getenv("DATA_DIRECTORY") + if DATA_DIRECTORY_KEY in _config: + return _config[DATA_DIRECTORY_KEY] + return DEFAULT_DATA_DIRECTORY def set_cache_dir(directory): """Set an alternate cache directory.""" @@ -79,7 +92,13 @@ def get_cache_dir(): """Get the cache directory.""" if CACHE_DIRECTORY_KEY in _config: return _config[CACHE_DIRECTORY_KEY] - return os.path.join(_args.output, ".cache") + return os.path.join(get_state_dir(), CACHE_DIRECTORY) + +def get_output_dir(): + """Get the rule output directory.""" + if OUTPUT_KEY in _config: + return _config[OUTPUT_KEY] + return os.path.join(get_state_dir(), "rules") def args(): """Return sthe parsed argument object.""" @@ -119,7 +138,7 @@ def init(args): for local in args.local: logger.debug("Adding local ruleset to config: %s", local) _config[LOCAL_CONF_KEY].append(local) - elif arg == "data_dir": + elif arg == "data_dir" and args.data_dir: logger.debug("Setting data directory to %s", args.data_dir) _config[DATA_DIRECTORY_KEY] = args.data_dir elif getattr(args, arg): diff --git a/suricata/update/main.py b/suricata/update/main.py index 141ffa6..113ba53 100644 --- a/suricata/update/main.py +++ b/suricata/update/main.py @@ -823,7 +823,7 @@ def test_suricata(suricata_path): if not config.get("no-merge"): if not suricata.update.engine.test_configuration( suricata_path, os.path.join( - config.get("output"), DEFAULT_OUTPUT_RULE_FILENAME)): + config.get_output_dir(), DEFAULT_OUTPUT_RULE_FILENAME)): return False else: if not suricata.update.engine.test_configuration( @@ -944,9 +944,6 @@ def _main(): if len(sys.argv) == 1 or sys.argv[1].startswith("-"): sys.argv.insert(1, "update") - # Support the Python argparse style of configuration file. - parser = argparse.ArgumentParser() - # Arguments that are common to all sub-commands. common_parser = argparse.ArgumentParser(add_help=False) common_parser.add_argument( @@ -959,8 +956,13 @@ def _main(): "-q", "--quiet", action="store_true", default=False, help="Be quiet, warning and error messages only") common_parser.add_argument( - "-o", "--output", metavar="", dest="output", - default="/var/lib/suricata/rules", help="Directory to write rules to") + "-D", "--data-dir", metavar="", dest="data_dir", + help="Data directory (default: /var/lib/suricata)") + + # Create the root parser with the common_parser as a parent, + # allowing the common options to be specified before or after the + # sub-command. + parser = argparse.ArgumentParser(parents=[common_parser]) subparsers = parser.add_subparsers(dest="subcommand", metavar="") @@ -968,6 +970,9 @@ def _main(): update_parser = subparsers.add_parser( "update", add_help=False, parents=[common_parser]) + update_parser.add_argument( + "-o", "--output", metavar="", dest="output", + help="Directory to write rules to") update_parser.add_argument("--suricata", metavar="", help="Path to Suricata program") update_parser.add_argument("--suricata-version", metavar="", @@ -1063,6 +1068,12 @@ def _main(): args = parser.parse_args() + # Go verbose or quiet sooner than later. + if args.verbose: + logger.setLevel(logging.DEBUG) + if args.quiet: + logger.setLevel(logging.WARNING) + try: config.init(args) except Exception as err: @@ -1081,11 +1092,6 @@ def _main(): logger.error("--%s not implemented", arg) return 1 - if args.verbose: - logger.setLevel(logging.DEBUG) - if args.quiet: - logger.setLevel(logging.WARNING) - logger.debug("This is suricata-update version %s (rev: %s); Python: %s" % ( version, revision, sys.version.replace("\n", "- "))) @@ -1278,43 +1284,40 @@ def _main(): # Fixup flowbits. resolve_flowbits(rulemap, disabled_rules) - # Don't allow an empty output directory. - if not args.output: - logger.error("No output directory provided.") - return 1 - # Check that output directory exists. - if not os.path.exists(args.output): + if not os.path.exists(config.get_output_dir()): try: - os.makedirs(args.output, mode=0o770) + os.makedirs(config.get_output_dir(), mode=0o770) except Exception as err: logger.error( "Output directory does not exist and could not be created: %s", - args.output) + config.get_output_dir()) return 1 # Check that output directory is writable. - if not os.access(args.output, os.W_OK): - logger.error("Output directory is not writable: %s", args.output) + if not os.access(config.get_output_dir(), os.W_OK): + logger.error( + "Output directory is not writable: %s", config.get_output_dir()) return 1 # Backup the output directory. logger.info("Backing up current rules.") backup_directory = util.mktempdir() - shutil.copytree(args.output, os.path.join( + shutil.copytree(config.get_output_dir(), os.path.join( backup_directory, "backup"), ignore=copytree_ignore_backup) if not args.no_merge: # The default, write out a merged file. output_filename = os.path.join( - args.output, DEFAULT_OUTPUT_RULE_FILENAME) + config.get_output_dir(), DEFAULT_OUTPUT_RULE_FILENAME) file_tracker.add(output_filename) write_merged(os.path.join(output_filename), rulemap) else: for filename in files: file_tracker.add( - os.path.join(args.output, os.path.basename(filename))) - write_to_directory(args.output, files, rulemap) + os.path.join( + config.get_output_dir(), os.path.basename(filename))) + write_to_directory(config.get_output_dir(), files, rulemap) if args.yaml_fragment: file_tracker.add(args.yaml_fragment) @@ -1338,7 +1341,8 @@ def _main(): if not test_suricata(suricata_path): logger.error("Suricata test failed, aborting.") logger.error("Restoring previous rules.") - copytree(os.path.join(backup_directory, "backup"), args.output) + copytree( + os.path.join(backup_directory, "backup"), config.get_output_dir()) return 1 if not config.args().no_reload and config.get("reload-command"): diff --git a/suricata/update/sources.py b/suricata/update/sources.py index 8acd44e..aa942d5 100644 --- a/suricata/update/sources.py +++ b/suricata/update/sources.py @@ -32,14 +32,10 @@ logger = logging.getLogger() DEFAULT_SOURCE_INDEX_URL = "https://www.openinfosecfoundation.org/rules/index.yaml" SOURCE_INDEX_FILENAME = "index.yaml" -DEFAULT_SOURCE_DIRECTORY = "/var/lib/suricata/update/sources" def get_source_directory(): """Return the directory where source configuration files are kept.""" - if os.getenv("SOURCE_DIRECTORY"): - return os.getenv("SOURCE_DIRECTORY") - else: - return DEFAULT_SOURCE_DIRECTORY + return os.path.join(config.get_state_dir(), config.SOURCE_DIRECTORY) def get_index_filename(): return os.path.join(config.get_cache_dir(), SOURCE_INDEX_FILENAME) diff --git a/tests/docker-centos-7/run.sh b/tests/docker-centos-7/run.sh index c4599b8..23e52f0 100755 --- a/tests/docker-centos-7/run.sh +++ b/tests/docker-centos-7/run.sh @@ -12,7 +12,7 @@ test_commands() { test -e /var/lib/suricata/rules/suricata.rules suricata-update update-sources - test -e /var/lib/suricata/rules/.cache/index.yaml + test -e /var/lib/suricata/update/cache/index.yaml suricata-update enable-source oisf/trafficid test -e /var/lib/suricata/update/sources/et-open.yaml