blob: 1381fa31932b6ee592b511b9a345e87e933d3303 [file] [log] [blame]
Tyler Chatowa79419d2020-08-12 20:12:11 -07001#include <chrono>
Philipp Schrader08537492021-01-23 16:17:55 -08002#include <functional>
Tyler Chatowa79419d2020-08-12 20:12:11 -07003#include <iostream>
4#include <unordered_map>
5
Philipp Schrader08537492021-01-23 16:17:55 -08006#include "absl/strings/str_format.h"
Tyler Chatowa79419d2020-08-12 20:12:11 -07007#include "aos/init.h"
8#include "aos/json_to_flatbuffer.h"
9#include "gflags/gflags.h"
10#include "starter_rpc_lib.h"
11
12DEFINE_string(config, "./config.json", "File path of aos configuration");
13
Philipp Schrader08537492021-01-23 16:17:55 -080014namespace {
Tyler Chatowa79419d2020-08-12 20:12:11 -070015
Philipp Schrader08537492021-01-23 16:17:55 -080016static const std::unordered_map<std::string, aos::starter::Command>
17 kCommandConversions{{"start", aos::starter::Command::START},
18 {"stop", aos::starter::Command::STOP},
19 {"restart", aos::starter::Command::RESTART}};
Tyler Chatowa79419d2020-08-12 20:12:11 -070020
Philipp Schrader08537492021-01-23 16:17:55 -080021bool GetStarterStatus(int argc, char **argv, const aos::Configuration *config) {
22 if (argc == 1) {
23 // Print status for all processes.
24 auto status = aos::starter::GetStarterStatus(config);
25 for (const aos::starter::ApplicationStatus *app_status :
26 *status.message().statuses()) {
27 absl::PrintF("%-30s %s\n", app_status->name()->string_view(),
28 aos::starter::EnumNameState(app_status->state()));
29 }
30 } else if (argc == 2) {
31 // Print status for the specified process.
32 const char *application_name = argv[1];
33 auto status = aos::starter::GetStatus(application_name, config);
Tyler Chatowa79419d2020-08-12 20:12:11 -070034 std::cout << aos::FlatbufferToJson(&status.message()) << '\n';
Philipp Schrader08537492021-01-23 16:17:55 -080035 } else {
36 LOG(ERROR) << "The \"status\" command requires zero or one arguments.";
37 return true;
38 }
39 return false;
40}
Tyler Chatowa79419d2020-08-12 20:12:11 -070041
Philipp Schrader08537492021-01-23 16:17:55 -080042bool InteractWithProgram(int argc, char **argv,
43 const aos::Configuration *config) {
44 const char *command_string = argv[0];
45
46 if (argc != 2) {
47 LOG(ERROR) << "The \"" << command_string
48 << "\" command requires an application name as an argument.";
49 return true;
Tyler Chatowa79419d2020-08-12 20:12:11 -070050 }
51
Philipp Schrader08537492021-01-23 16:17:55 -080052 const auto command_search = kCommandConversions.find(command_string);
53 CHECK(command_search != kCommandConversions.end())
54 << "Internal error: \"" << command_string
55 << "\" is not in kCommandConversions.";
Tyler Chatowa79419d2020-08-12 20:12:11 -070056
Philipp Schrader08537492021-01-23 16:17:55 -080057 const aos::starter::Command command = command_search->second;
58 const char *application_name = argv[1];
59
60 if (aos::starter::SendCommandBlocking(command, application_name, config,
Tyler Chatowa79419d2020-08-12 20:12:11 -070061 std::chrono::seconds(3))) {
62 switch (command) {
63 case aos::starter::Command::START:
64 std::cout << "Successfully started " << application_name << '\n';
65 break;
66 case aos::starter::Command::STOP:
67 std::cout << "Successfully stopped " << application_name << '\n';
68 break;
69 case aos::starter::Command::RESTART:
70 std::cout << "Successfully restarted " << application_name << '\n';
71 break;
72 }
73 } else {
Philipp Schrader08537492021-01-23 16:17:55 -080074 std::cout << "Failed to " << command_string << ' ' << application_name
75 << '\n';
Tyler Chatowa79419d2020-08-12 20:12:11 -070076 }
Philipp Schrader08537492021-01-23 16:17:55 -080077 return false;
78}
79
80// This is the set of subcommands we support. Each subcommand accepts argc and
81// argv from its own point of view. So argv[0] is always the name of the
82// subcommand. argv[1] and up are the arguments to the subcommand.
83// The subcommand returns true if there was an error parsing the command line
84// arguments. It returns false when the command line arguments are parsed
85// successfully.
86static const std::unordered_map<
87 std::string, std::function<bool(int argc, char **argv,
88 const aos::Configuration *config)>>
89 kCommands{
90 {"status", GetStarterStatus},
91 {"start", InteractWithProgram},
92 {"stop", InteractWithProgram},
93 {"restart", InteractWithProgram},
94 };
95
96} // namespace
97
98int main(int argc, char **argv) {
99 aos::InitGoogle(&argc, &argv);
100
101 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
102 aos::configuration::ReadConfig(FLAGS_config);
103
104 bool parsing_failed = false;
105
106 if (argc < 2) {
107 parsing_failed = true;
108 } else {
109 const char *command = argv[1];
110 auto it = kCommands.find(command);
111 if (it == kCommands.end()) {
112 parsing_failed = true;
113 } else {
114 parsing_failed = it->second(argc - 1, argv + 1, &config.message());
115 }
116 }
117
118 if (parsing_failed) {
119 LOG(ERROR) << "Parsing failed. Valid commands are:";
120 for (auto entry: kCommands) {
121 LOG(ERROR) << " - " << entry.first;
122 }
123 return 1;
124 }
125
126 return 0;
Tyler Chatowa79419d2020-08-12 20:12:11 -0700127}