Merge "Remove autos for the at home challanges"
diff --git a/aos/starter/starter_cmd.cc b/aos/starter/starter_cmd.cc
index 5f67c4b..8257e3b 100644
--- a/aos/starter/starter_cmd.cc
+++ b/aos/starter/starter_cmd.cc
@@ -23,6 +23,32 @@
{"stop", aos::starter::Command::STOP},
{"restart", aos::starter::Command::RESTART}};
+const aos::Node *MaybeMyNode(const aos::Configuration *configuration) {
+ if (!configuration->has_nodes()) {
+ return nullptr;
+ }
+
+ return aos::configuration::GetMyNode(configuration);
+}
+
+bool ValidApplication(const aos::Configuration *config,
+ std::string_view application_name) {
+ const aos::Node *node = MaybeMyNode(config);
+ const aos::Application *application =
+ aos::configuration::GetApplication(config, node, application_name);
+ if (application == nullptr) {
+ if (node) {
+ std::cout << "Unknown application '" << application_name << "' on node '"
+ << node->name()->string_view() << "'" << std::endl;
+ } else {
+ std::cout << "Unknown application '" << application_name << "'"
+ << std::endl;
+ }
+ return false;
+ }
+ return true;
+}
+
void PrintKey() {
absl::PrintF("%-30s %-8s %-6s %-9s\n", "Name", "State", "PID", "Uptime");
}
@@ -43,8 +69,8 @@
}
}
-bool GetStarterStatus(int argc, char **argv, const aos::Configuration *config) {
- if (argc == 1) {
+// Prints the status for all applications.
+void GetAllStarterStatus(const aos::Configuration *config) {
// Print status for all processes.
const auto optional_status = aos::starter::GetStarterStatus(config);
if (optional_status) {
@@ -58,10 +84,25 @@
} else {
LOG(WARNING) << "No status found";
}
+}
+
+// Handles the "status" command. Returns true if the help message should be
+// printed.
+bool GetStarterStatus(int argc, char **argv, const aos::Configuration *config) {
+ if (argc == 1) {
+ GetAllStarterStatus(config);
} else if (argc == 2) {
// Print status for the specified process.
const auto application_name =
aos::starter::FindApplication(argv[1], config);
+ if (application_name == "all") {
+ GetAllStarterStatus(config);
+ return false;
+ }
+
+ if (!ValidApplication(config, application_name)) {
+ return false;
+ }
auto status = aos::starter::GetStatus(application_name, config);
PrintKey();
PrintApplicationStatus(&status.message(), aos::monotonic_clock::now());
@@ -72,12 +113,63 @@
return false;
}
+// Sends the provided command to all applications. Prints the success text on
+// success, and failure text on failure.
+void InteractWithAll(const aos::Configuration *config,
+ const aos::starter::Command command,
+ std::string_view success_text,
+ std::string_view failure_text) {
+ const auto optional_status = aos::starter::GetStarterStatus(config);
+ if (optional_status) {
+ auto status = *optional_status;
+ const aos::Node *my_node = MaybeMyNode(config);
+ std::vector<std::pair<aos::starter::Command, std::string_view>> commands;
+
+ for (const aos::Application *application : *config->applications()) {
+ // Ignore any applications which aren't supposed to be started on this
+ // node.
+ if (!aos::configuration::ApplicationShouldStart(config, my_node,
+ application)) {
+ continue;
+ }
+
+ const std::string_view application_name =
+ application->name()->string_view();
+ if (!application->autostart()) {
+ const aos::starter::ApplicationStatus *application_status =
+ aos::starter::FindApplicationStatus(status.message(),
+ application_name);
+ if (application_status->state() == aos::starter::State::STOPPED) {
+ std::cout << "Skipping " << application_name
+ << " because it is STOPPED\n";
+ continue;
+ }
+ }
+
+ commands.emplace_back(command, application_name);
+ }
+
+ // Restart each running process
+ if (aos::starter::SendCommandBlocking(commands, config,
+ chrono::seconds(5))) {
+ std::cout << success_text << "all \n";
+ } else {
+ std::cout << failure_text << "all \n";
+ }
+ } else {
+ LOG(WARNING) << "Starter not running";
+ }
+}
+
+// Handles the "start", "stop", and "restart" commands. Returns true if the
+// help message should be printed.
bool InteractWithProgram(int argc, char **argv,
const aos::Configuration *config) {
const char *command_string = argv[0];
if (argc != 2) {
- LOG(ERROR) << "The \"" << command_string
- << "\" command requires an application name as an argument.";
+ LOG(ERROR)
+ << "The \"" << command_string
+ << "\" command requires an application name or 'all' as an argument.";
return true;
}
@@ -85,59 +177,44 @@
CHECK(command_search != kCommandConversions.end())
<< "Internal error: \"" << command_string
<< "\" is not in kCommandConversions.";
-
const aos::starter::Command command = command_search->second;
- const auto application_name = aos::starter::FindApplication(argv[1], config);
+
+ std::string_view success_text;
+ const std::string failure_text =
+ std::string("Failed to ") + std::string(command_string) + " ";
+ switch (command) {
+ case aos::starter::Command::START:
+ success_text = "Successfully started ";
+ break;
+ case aos::starter::Command::STOP:
+ success_text = "Successfully stopped ";
+ break;
+ case aos::starter::Command::RESTART:
+ success_text = "Successfully restarted ";
+ break;
+ }
+
+ const std::string_view application_name =
+ aos::starter::FindApplication(argv[1], config);
+ if (application_name == "all") {
+ InteractWithAll(config, command, success_text, failure_text);
+ return false;
+ }
+ if (!ValidApplication(config, application_name)) {
+ return false;
+ }
+
if (aos::starter::SendCommandBlocking(command, application_name, config,
chrono::seconds(5))) {
- switch (command) {
- case aos::starter::Command::START:
- std::cout << "Successfully started " << application_name << '\n';
- break;
- case aos::starter::Command::STOP:
- std::cout << "Successfully stopped " << application_name << '\n';
- break;
- case aos::starter::Command::RESTART:
- std::cout << "Successfully restarted " << application_name << '\n';
- break;
- }
+ std::cout << success_text << application_name << '\n';
} else {
- std::cout << "Failed to " << command_string << ' ' << application_name
- << '\n';
+ std::cout << failure_text << application_name << '\n';
}
return false;
}
-bool RestartAll(int argc, char **, const aos::Configuration *config) {
- if (argc == 1) {
- const auto optional_status = aos::starter::GetStarterStatus(config);
- if (optional_status) {
- auto status = *optional_status;
- for (const aos::starter::ApplicationStatus *app_status :
- *status.message().statuses()) {
- const auto application_name = aos::starter::FindApplication(
- app_status->name()->string_view(), config);
-
- // Restart each running process
-
- if (aos::starter::SendCommandBlocking(aos::starter::Command::RESTART,
- application_name, config,
- chrono::seconds(5))) {
- std::cout << "Successfully restarted " << application_name << '\n';
- } else {
- std::cout << "Failed to restart " << application_name << '\n';
- return true;
- }
- }
- } else {
- LOG(WARNING) << "No processes found";
- }
- } else {
- LOG(ERROR) << "The \"restart_all\" command requires only zero arguments.";
- return true;
- }
- return false;
-}
+bool Help(int /*argc*/, char ** /*argv*/,
+ const aos::Configuration * /*config*/);
// This is the set of subcommands we support. Each subcommand accepts argc and
// argv from its own point of view. So argv[0] is always the name of the
@@ -145,14 +222,34 @@
// The subcommand returns true if there was an error parsing the command line
// arguments. It returns false when the command line arguments are parsed
// successfully.
-static const std::unordered_map<
- std::string, std::function<bool(int argc, char **argv,
- const aos::Configuration *config)>>
- kCommands{{"status", GetStarterStatus},
- {"start", InteractWithProgram},
- {"stop", InteractWithProgram},
- {"restart", InteractWithProgram},
- {"restart_all", RestartAll}};
+static const std::vector<
+ std::tuple<std::string,
+ std::function<bool(int argc, char **argv,
+ const aos::Configuration *config)>,
+ std::string_view>>
+ kCommands{
+ {"help", Help, ""},
+ {"status", GetStarterStatus,
+ " [application], Returns the status of the provided application, "
+ "or all applications by default"},
+ {"start", InteractWithProgram,
+ " application, Starts the provided application, "
+ "or all applications if all is provided"},
+ {"stop", InteractWithProgram,
+ " application, Stops the provided application, "
+ "or all applications if all is provided"},
+ {"restart", InteractWithProgram,
+ " application, Restarts the provided application, "
+ "or all applications if all is provided"}};
+
+bool Help(int /*argc*/, char ** /*argv*/,
+ const aos::Configuration * /*config*/) {
+ std::cout << "Valid commands are:" << std::endl;
+ for (auto entry : kCommands) {
+ std::cout << " - " << std::get<0>(entry) << std::get<2>(entry) << std::endl;
+ }
+ return false;
+}
} // namespace
@@ -168,19 +265,23 @@
parsing_failed = true;
} else {
const char *command = argv[1];
- auto it = kCommands.find(command);
+ auto it = std::find_if(
+ kCommands.begin(), kCommands.end(),
+ [command](const std::tuple<
+ std::string,
+ std::function<bool(int argc, char **argv,
+ const aos::Configuration *config)>,
+ std::string_view> &t) { return std::get<0>(t) == command; });
+
if (it == kCommands.end()) {
parsing_failed = true;
} else {
- parsing_failed = it->second(argc - 1, argv + 1, &config.message());
+ parsing_failed = std::get<1>(*it)(argc - 1, argv + 1, &config.message());
}
}
if (parsing_failed) {
- LOG(ERROR) << "Parsing failed. Valid commands are:";
- for (auto entry : kCommands) {
- LOG(ERROR) << " - " << entry.first;
- }
+ Help(argc - 1, argv + 1, &config.message());
return 1;
}
diff --git a/aos/starter/starterd_lib.cc b/aos/starter/starterd_lib.cc
index 9066a78..19051bb 100644
--- a/aos/starter/starterd_lib.cc
+++ b/aos/starter/starterd_lib.cc
@@ -15,7 +15,8 @@
namespace starter {
Application::Application(const aos::Application *application,
- aos::ShmEventLoop *event_loop)
+ aos::ShmEventLoop *event_loop,
+ std::function<void()> on_change)
: name_(application->name()->string_view()),
path_(application->has_executable_name()
? application->executable_name()->string_view()
@@ -38,7 +39,8 @@
LOG(WARNING) << "Failed to stop, sending SIGKILL to '" << name_
<< "' pid: " << pid_;
}
- })) {}
+ })),
+ on_change_(on_change) {}
void Application::DoStart() {
if (status_ != aos::starter::State::WAITING) {
@@ -69,6 +71,7 @@
start_timer_->Setup(event_loop_->monotonic_now() +
std::chrono::seconds(1));
}
+ on_change_();
return;
}
@@ -134,6 +137,7 @@
stop_timer_->Setup(event_loop_->monotonic_now() +
std::chrono::seconds(1));
queue_restart_ = restart;
+ on_change_();
break;
}
case aos::starter::State::WAITING: {
@@ -144,6 +148,7 @@
DoStart();
} else {
status_ = aos::starter::State::STOPPED;
+ on_change_();
}
break;
}
@@ -171,6 +176,7 @@
restart_timer_->Setup(event_loop_->monotonic_now() + std::chrono::seconds(3));
start_timer_->Disable();
stop_timer_->Disable();
+ on_change_();
}
void Application::set_args(
@@ -310,6 +316,7 @@
// Disable force stop timer since the process already died
stop_timer_->Disable();
+ on_change_();
if (terminating_) {
return true;
}
@@ -403,15 +410,21 @@
: config_msg_(event_loop_config),
event_loop_(event_loop_config),
status_sender_(event_loop_.MakeSender<aos::starter::Status>("/aos")),
- status_timer_(event_loop_.AddTimer([this] { SendStatus(); })),
+ status_timer_(event_loop_.AddTimer([this] {
+ SendStatus();
+ status_count_ = 0;
+ })),
cleanup_timer_(event_loop_.AddTimer([this] { event_loop_.Exit(); })),
+ max_status_count_(
+ event_loop_.GetChannel<aos::starter::Status>("/aos")->frequency() -
+ 1),
listener_(&event_loop_,
[this](signalfd_siginfo signal) { OnSignal(signal); }) {
event_loop_.SkipAosLog();
event_loop_.OnRun([this] {
status_timer_->Setup(event_loop_.monotonic_now(),
- std::chrono::milliseconds(500));
+ std::chrono::milliseconds(1000));
});
event_loop_.MakeWatcher("/aos", [this](const aos::starter::StarterRpc &cmd) {
@@ -452,6 +465,15 @@
}
}
+void Starter::MaybeSendStatus() {
+ if (status_count_ < max_status_count_) {
+ SendStatus();
+ ++status_count_;
+ } else {
+ VLOG(1) << "That's enough " << status_count_ << " " << max_status_count_;
+ }
+}
+
void Starter::Cleanup() {
if (exiting_) {
return;
@@ -491,8 +513,9 @@
}
Application *Starter::AddApplication(const aos::Application *application) {
- auto [iter, success] = applications_.try_emplace(application->name()->str(),
- application, &event_loop_);
+ auto [iter, success] =
+ applications_.try_emplace(application->name()->str(), application,
+ &event_loop_, [this]() { MaybeSendStatus(); });
if (success) {
if (application->has_args()) {
iter->second.set_args(*application->args());
diff --git a/aos/starter/starterd_lib.h b/aos/starter/starterd_lib.h
index 2bbfa22..b5888e0 100644
--- a/aos/starter/starterd_lib.h
+++ b/aos/starter/starterd_lib.h
@@ -68,7 +68,7 @@
class Application {
public:
Application(const aos::Application *application,
- aos::ShmEventLoop *event_loop);
+ aos::ShmEventLoop *event_loop, std::function<void()> on_change);
flatbuffers::Offset<aos::starter::ApplicationStatus> PopulateStatus(
flatbuffers::FlatBufferBuilder *builder);
@@ -137,6 +137,8 @@
aos::ShmEventLoop *event_loop_;
aos::TimerHandler *start_timer_, *restart_timer_, *stop_timer_;
+ std::function<void()> on_change_;
+
DISALLOW_COPY_AND_ASSIGN(Application);
};
@@ -179,6 +181,9 @@
void OnSignal(signalfd_siginfo signal);
+ // Sends the Status message if it wouldn't exceed the rate limit.
+ void MaybeSendStatus();
+
void SendStatus();
const std::string config_path_;
@@ -189,6 +194,9 @@
aos::TimerHandler *status_timer_;
aos::TimerHandler *cleanup_timer_;
+ int status_count_ = 0;
+ const int max_status_count_;
+
std::unordered_map<std::string, Application> applications_;
// Set to true on cleanup to block rpc commands and ensure cleanup only