Fix DBHandle checking with concurrent processes.

`make tests` fails with another osquery process running.
The backing-store check happens after a config plugin is setUp and
the initial load occures. This may involve calls to cached keys, the
check should occur pre-config initialize.
This commit is contained in:
Teddy Reed 2015-06-01 21:49:21 -07:00
parent 7d4142b28c
commit 33f53809ad
6 changed files with 44 additions and 24 deletions

View File

@ -141,6 +141,11 @@ inline void additionalScheduledQuery(const std::string& name,
ScheduledQuery query;
query.query = node.second.get<std::string>("query", "");
query.interval = node.second.get<int>("interval", 0);
if (query.interval == 0) {
VLOG(1) << "Setting invalid interval=0 to 84600 for query: " << name;
query.interval = 86400;
}
// This is a candidate for a catch-all iterator with a catch for boolean type.
query.options["snapshot"] = node.second.get<bool>("snapshot", false);

View File

@ -134,8 +134,13 @@ Initializer::Initializer(int& argc, char**& argv, ToolType tool)
auto homedir = osqueryHomeDirectory();
if (osquery::pathExists(homedir).ok() ||
boost::filesystem::create_directory(homedir)) {
osquery::FLAGS_database_path = homedir + "/shell.db";
osquery::FLAGS_extensions_socket = homedir + "/shell.em";
// Only apply user/shell-specific paths if not overridden by CLI flag.
if (Flag::isDefault("database_path")) {
osquery::FLAGS_database_path = homedir + "/shell.db";
}
if (Flag::isDefault("extension_socket")) {
osquery::FLAGS_extensions_socket = homedir + "/shell.em";
}
}
}
@ -268,6 +273,16 @@ void Initializer::start() {
FLAGS_disable_extensions = true;
}
// Check the backing store by allocating and exiting on error.
if (!DBHandle::checkDB()) {
LOG(ERROR) << binary_ << " initialize failed: Could not open RocksDB";
if (isWorker()) {
::exit(EXIT_CATASTROPHIC);
} else {
::exit(EXIT_FAILURE);
}
}
// Bind to an extensions socket and wait for registry additions.
osquery::startExtensionManager();
@ -290,16 +305,6 @@ void Initializer::start() {
// Load the osquery config using the default/active config plugin.
Config::load();
// Check the backing store by allocating and exiting on error.
if (!DBHandle::checkDB()) {
LOG(ERROR) << binary_ << " initialize failed: Could not create DB handle";
if (isWorker()) {
::exit(EXIT_CATASTROPHIC);
} else {
::exit(EXIT_FAILURE);
}
}
// Initialize the status and result plugin logger.
initActivePlugin("logger", FLAGS_logger_plugin);
initLogger(binary_);

View File

@ -69,13 +69,16 @@ const std::vector<std::string> kDomains = {
kPersistentSettings, kQueries, kEvents
};
FLAG(string,
database_path,
"/var/osquery/osquery.db",
"If using a disk-based backing store, specify a path");
CLI_FLAG(string,
database_path,
"/var/osquery/osquery.db",
"If using a disk-based backing store, specify a path");
FLAG_ALIAS(std::string, db_path, database_path);
FLAG(bool, database_in_memory, false, "Keep osquery backing-store in memory");
CLI_FLAG(bool,
database_in_memory,
false,
"Keep osquery backing-store in memory");
FLAG_ALIAS(bool, use_in_memory_database, database_in_memory);
/////////////////////////////////////////////////////////////////////////////
@ -108,7 +111,7 @@ DBHandle::DBHandle(const std::string& path, bool in_memory) {
cf_name, rocksdb::ColumnFamilyOptions()));
}
VLOG(1) << "Opening DB handle: " << path;
VLOG(1) << "Opening RocksDB handle: " << path;
auto s = rocksdb::DB::Open(options_, path, column_families_, &handles_, &db_);
if (!s.ok()) {
throw std::runtime_error(s.ToString());

View File

@ -166,8 +166,7 @@ void loadExtensions() {
void loadModules() {
auto status = loadModules(FLAGS_modules_autoload);
if (!status.ok()) {
VLOG(1) << "Modules autoload contains invalid paths: "
<< FLAGS_modules_autoload;
VLOG(1) << "Could not autoload modules: " << status.what();
}
}
@ -182,7 +181,7 @@ Status loadExtensions(const std::string& loadfile) {
}
return Status(0, "OK");
}
return Status(1, "Cannot read extensions autoload file");
return Status(1, "Failed reading: " + loadfile);
}
Status loadModuleFile(const std::string& path) {
@ -213,7 +212,7 @@ Status loadModules(const std::string& loadfile) {
// Return an aggregate failure if any load fails (invalid search path).
return status;
}
return Status(1, "Cannot read modules autoload file");
return Status(1, "Failed reading: " + loadfile);
}
Status extensionPathActive(const std::string& path, bool use_timeout = false) {

View File

@ -25,7 +25,7 @@ from urlparse import parse_qs
EXAMPLE_CONFIG = {
"schedule": {
"tls_proc": {"query": "select * from processes"},
"tls_proc": {"query": "select * from processes", "interval": 0},
}
}
@ -109,7 +109,7 @@ class RealSimpleHandler(BaseHTTPRequestHandler):
# The osquery TLS config plugin calls the TLS enroll plugin to retrieve
# a node_key, then submits that key alongside config/logger requests.
if "node_key" not in request or request["node_key"] != ENROLL_SECRET:
if "node_key" not in request or request["node_key"] not in NODE_KEYS:
self._reply(FAILED_ENROLL_RESPONSE)
return
self._reply(EXAMPLE_CONFIG)

View File

@ -14,6 +14,7 @@ from __future__ import print_function
#from __future__ import unicode_literals
import os
import random
import unittest
# osquery-specific testing utils
@ -23,6 +24,9 @@ class OsqueryiTest(unittest.TestCase):
def setUp(self):
self.binary = os.path.join(test_base.ARGS.build, "osquery", "osqueryi")
self.osqueryi = test_base.OsqueryWrapper(self.binary)
self.dbpath = "%s%s" % (
test_base.CONFIG["options"]["database_path"],
str(random.randint(1000, 9999)))
def test_error(self):
'''Test that we throw an error on bad query'''
@ -35,6 +39,7 @@ class OsqueryiTest(unittest.TestCase):
proc = test_base.TimeoutRunner([
self.binary,
"--config_check",
"--database_path=%s" % (self.dbpath),
"--config_path=test.config"], 2)
self.assertEqual(proc.stdout, "")
print (proc.stdout)
@ -46,6 +51,7 @@ class OsqueryiTest(unittest.TestCase):
proc = test_base.TimeoutRunner([
self.binary,
"--config_check",
"--database_path=%s" % (self.dbpath),
"--config_path=/this/path/does/not/exist"], 2)
self.assertNotEqual(proc.stderr, "")
print (proc.stdout)
@ -56,6 +62,7 @@ class OsqueryiTest(unittest.TestCase):
proc = test_base.TimeoutRunner([
self.binary,
"--config_check",
"--database_path=%s" % (self.dbpath),
"--config_path=test.badconfig"], 2)
self.assertNotEqual(proc.stderr, "")
self.assertEqual(proc.proc.poll(), 1)
@ -64,6 +71,7 @@ class OsqueryiTest(unittest.TestCase):
proc = test_base.TimeoutRunner([
self.binary,
"--config_check",
"--database_path=%s" % (self.dbpath),
"--config_plugin=does_not_exist"], 2)
self.assertNotEqual(proc.stderr, "")
self.assertNotEqual(proc.proc.poll(), 0)