Add support for not automatically starting applications
There are cases where we want a debug application (web server is a
reasonable example) which doesn't start up automatically, but can be
started on demand. Add an "autostart" to the application config entry
to signal this.
Change-Id: Id88ec8a164f42adb73902e2f0ba30c9d1ecea5c9
Signed-off-by: Austin Schuh <austin.schuh@bluerivertech.com>
diff --git a/aos/configuration.fbs b/aos/configuration.fbs
index bfac6a2..3401b43 100644
--- a/aos/configuration.fbs
+++ b/aos/configuration.fbs
@@ -143,6 +143,9 @@
// List of arguments to be passed to application
args:[string] (id: 4);
+
+ // Indicates that application should be executed on boot.
+ autostart:bool = true (id: 6);
}
// Per node data and connection information.
diff --git a/aos/events/logging/logger_test.cc b/aos/events/logging/logger_test.cc
index 8d8a2a6..eebb594 100644
--- a/aos/events/logging/logger_test.cc
+++ b/aos/events/logging/logger_test.cc
@@ -2549,9 +2549,9 @@
}
constexpr std::string_view kCombinedConfigSha1(
- "4503751edc96327493562f0376f0d6daac172927c0fd64d04ce5d67505186c0b");
+ "cad3b6838a518ab29470771a959b89945ee034bc7a738080fd1713a1dce51b1f");
constexpr std::string_view kSplitConfigSha1(
- "918a748432c5e70a971dfd8934968378bed04ab61cf2efcd35b7f6224053c247");
+ "aafdd7e43d1942cce5b3e2dd8c6b9706abf7068a43501625a33b7cdfddf6c932");
INSTANTIATE_TEST_SUITE_P(
All, MultinodeLoggerTest,
diff --git a/aos/starter/BUILD b/aos/starter/BUILD
index 5cff4cc..cc7ea04 100644
--- a/aos/starter/BUILD
+++ b/aos/starter/BUILD
@@ -34,6 +34,7 @@
"//aos/events:pingpong_config",
"//aos/events:pong",
],
+ shard_count = 3,
target_compatible_with = ["@platforms//os:linux"],
deps = [
":starter_rpc_lib",
diff --git a/aos/starter/starter_test.cc b/aos/starter/starter_test.cc
index dea27e9..f174032 100644
--- a/aos/starter/starter_test.cc
+++ b/aos/starter/starter_test.cc
@@ -12,6 +12,9 @@
using aos::testing::ArtifactPath;
+namespace aos {
+namespace starter {
+
TEST(StarterdTest, StartStopTest) {
const std::string config_file =
ArtifactPath("aos/events/pingpong_config.json");
@@ -69,7 +72,8 @@
ASSERT_TRUE(aos::starter::SendCommandBlocking(
aos::starter::Command::STOP, "ping", config_msg,
std::chrono::seconds(3)));
- }).detach();
+ })
+ .detach();
test_stage = 3;
break;
}
@@ -196,3 +200,78 @@
starter.Cleanup();
starterd_thread.join();
}
+
+TEST(StarterdTest, Autostart) {
+ const std::string config_file =
+ ArtifactPath("aos/events/pingpong_config.json");
+
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig(config_file);
+
+ const std::string test_dir = aos::testing::TestTmpDir();
+
+ auto new_config = aos::configuration::MergeWithConfig(
+ &config.message(), absl::StrFormat(
+ R"({"applications": [
+ {
+ "name": "ping",
+ "executable_name": "%s",
+ "args": ["--shm_base", "%s/aos"],
+ "autostart": false
+ },
+ {
+ "name": "pong",
+ "executable_name": "%s",
+ "args": ["--shm_base", "%s/aos"]
+ }
+ ]})",
+ ArtifactPath("aos/events/ping"), test_dir,
+ ArtifactPath("aos/events/pong"), test_dir));
+
+ const aos::Configuration *config_msg = &new_config.message();
+
+ // Set up starter with config file
+ aos::starter::Starter starter(config_msg);
+
+ // Create an event loop to watch for the application starting up.
+ aos::ShmEventLoop watcher_loop(config_msg);
+ watcher_loop.SkipAosLog();
+
+ watcher_loop
+ .AddTimer([&watcher_loop] {
+ watcher_loop.Exit();
+ FAIL();
+ })
+ ->Setup(watcher_loop.monotonic_now() + std::chrono::seconds(7));
+
+ watcher_loop.MakeWatcher(
+ "/aos", [&watcher_loop](const aos::starter::Status &status) {
+ const aos::starter::ApplicationStatus *ping_app_status =
+ FindApplicationStatus(status, "ping");
+ const aos::starter::ApplicationStatus *pong_app_status =
+ FindApplicationStatus(status, "pong");
+ if (ping_app_status == nullptr || pong_app_status == nullptr) {
+ return;
+ }
+
+ if (ping_app_status->has_state() &&
+ ping_app_status->state() != aos::starter::State::STOPPED) {
+ watcher_loop.Exit();
+ FAIL();
+ }
+ if (pong_app_status->has_state() &&
+ pong_app_status->state() == aos::starter::State::RUNNING) {
+ watcher_loop.Exit();
+ SUCCEED();
+ }
+ });
+
+ std::thread starterd_thread([&starter] { starter.Run(); });
+ watcher_loop.Run();
+
+ starter.Cleanup();
+ starterd_thread.join();
+}
+
+} // namespace starter
+} // namespace aos
diff --git a/aos/starter/starterd_lib.cc b/aos/starter/starterd_lib.cc
index 1c32be3..ff8bff9 100644
--- a/aos/starter/starterd_lib.cc
+++ b/aos/starter/starterd_lib.cc
@@ -23,6 +23,7 @@
args_(1),
user_(application->has_user() ? FindUid(application->user()->c_str())
: std::nullopt),
+ autostart_(application->autostart()),
event_loop_(event_loop),
start_timer_(event_loop_->AddTimer([this] {
status_ = aos::starter::State::RUNNING;
@@ -33,9 +34,7 @@
if (kill(pid_, SIGKILL) == 0) {
LOG(WARNING) << "Sent SIGKILL to " << name_ << " pid: " << pid_;
}
- }))
-
-{}
+ })) {}
void Application::DoStart() {
if (status_ != aos::starter::State::WAITING) {
@@ -481,7 +480,9 @@
#endif
for (auto &application : applications_) {
- application.second.Start();
+ if (application.second.autostart()) {
+ application.second.Start();
+ }
}
event_loop_.Run();
diff --git a/aos/starter/starterd_lib.h b/aos/starter/starterd_lib.h
index 38a11d6..cd4b40a 100644
--- a/aos/starter/starterd_lib.h
+++ b/aos/starter/starterd_lib.h
@@ -95,6 +95,8 @@
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>
&args);
+ bool autostart() const { return autostart_; }
+
private:
void DoStart();
@@ -124,6 +126,7 @@
aos::monotonic_clock::time_point start_time_, exit_time_;
bool queue_restart_ = false;
bool terminating_ = false;
+ bool autostart_ = true;
aos::starter::State status_ = aos::starter::State::STOPPED;
aos::starter::LastStopReason stop_reason_ =