1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "rpc/rpc.hpp"
4
5#include "ServiceManager.hpp"
6#include "common/ConfigurationManager.hpp"
7#include "proto/services.pb.h"
8#include "units/inherited.hpp"
9#include "units/template.hpp"
10#include "units/unit.hpp"
11
12#include <chrono>
13#include <cstdlib>
14#include <vector>
15
16static RpcUnitStatus GetUnitStatus(const IUnit *unit)
17{
18 RpcUnitStatusEnum statusEnum;
19 const auto status = unit->GetStatus();
20 switch (status.status)
21 {
22 case UnitStatus::UnitStarting: statusEnum = RpcUnitStatusEnum_Starting; break;
23 case UnitStatus::UnitStarted: statusEnum = RpcUnitStatusEnum_Started; break;
24 case UnitStatus::UnitFailed: statusEnum = RpcUnitStatusEnum_Failed; break;
25 case UnitStatus::UnitStopping: statusEnum = RpcUnitStatusEnum_Stopping; break;
26 case UnitStatus::UnitStopped: statusEnum = RpcUnitStatusEnum_Stopped; break;
27 }
28 RpcUnitStatus rpcStatus{
29 .isActive = status.active,
30 .status = statusEnum,
31 .statusMessage = strdup(string: status.message.c_str()),
32 .timestamp = std::chrono::system_clock::to_time_t(t: status.timestamp),
33 };
34
35 return rpcStatus;
36};
37
38rpc_result_code_t ServiceManagerServer::get_units(rpc_context_t *ctx, GetUnitsRequest *req, GetUnitsResponse *resp)
39{
40 (void) ctx;
41 (void) req;
42
43 const auto units = ConfigurationManager->GetAllUnits();
44 int nUnits = 0;
45
46 std::map<std::string, std::string> inheritedUnits; // child id -> base_id
47 for (const auto &[id, unit] : units)
48 {
49 if (unit->GetType() == UnitType::Inherited)
50 {
51 const auto inheritedUnit = std::dynamic_pointer_cast<const InheritedUnit>(r: unit);
52 if (inheritedUnit)
53 inheritedUnits[inheritedUnit->GetChildId()] = id;
54 }
55 else
56 {
57 nUnits++;
58 }
59 }
60
61 resp->units_count = nUnits;
62 resp->units = static_cast<RpcUnit *>(malloc(size: nUnits * sizeof(RpcUnit)));
63 if (!resp->units)
64 return RPC_RESULT_SERVER_INTERNAL_ERROR;
65
66 int i = 0;
67 for (const auto &[id, unit] : units)
68 {
69 if (unit->GetType() == UnitType::Inherited)
70 continue; // skip inherited units in the main list
71
72 resp->units[i].type = static_cast<RpcUnitType>(unit->GetType());
73 resp->units[i].description = strdup(string: unit->GetDescription().c_str());
74 resp->units[i].name = strdup(string: unit->id.c_str());
75 resp->units[i].status = GetUnitStatus(unit: unit.get());
76
77 std::vector<std::string> overrideChain;
78 {
79 bool isInherited = true;
80 std::string baseId = id;
81 while (isInherited)
82 {
83 isInherited = false;
84 auto it = inheritedUnits.find(x: baseId);
85 if (it != inheritedUnits.end() && it->second != baseId)
86 {
87 isInherited = true;
88 overrideChain.push_back(x: it->second);
89 baseId = it->second;
90 continue;
91 }
92 }
93 }
94
95 resp->units[i].overridden_units_count = overrideChain.size();
96 resp->units[i].overridden_units = static_cast<RpcOverriddenUnit *>(malloc(size: (1 + overrideChain.size()) * sizeof(RpcOverriddenUnit)));
97 if (!resp->units[i].overridden_units)
98 return RPC_RESULT_SERVER_INTERNAL_ERROR;
99 for (size_t j = 0; j < overrideChain.size(); j++)
100 {
101 resp->units[i].overridden_units[j].base_unit_id = strdup(string: overrideChain[j].c_str());
102 }
103
104 i++;
105 }
106
107 return RPC_RESULT_OK;
108}
109
110rpc_result_code_t ServiceManagerServer::get_templates(rpc_context_t *ctx, GetTemplatesRequest *req, GetTemplatesResponse *resp)
111{
112 (void) ctx;
113 (void) req;
114
115 const auto templates = ConfigurationManager->GetAllTemplates();
116
117 resp->templates_count = templates.size();
118 resp->templates = static_cast<RpcUnitTemplate *>(malloc(size: templates.size() * sizeof(RpcUnitTemplate)));
119 if (!resp->templates)
120 return RPC_RESULT_SERVER_INTERNAL_ERROR;
121
122 int i = 0;
123 for (const auto &[id, template_] : templates)
124 {
125 resp->templates[i].base_id = strdup(string: template_->id.c_str());
126 resp->templates[i].description = strdup(string: template_->table["description"].value_or(default_value: "<unknown>"));
127 {
128 // parameters
129 const auto &params = template_->GetParameters();
130 resp->templates[i].parameters_count = params.size();
131 resp->templates[i].parameters = static_cast<char **>(malloc(size: params.size() * sizeof(char *)));
132 if (!resp->templates[i].parameters)
133 return RPC_RESULT_SERVER_INTERNAL_ERROR;
134 for (size_t j = 0; j < params.size(); j++)
135 resp->templates[i].parameters[j] = strdup(string: params[j].c_str());
136 }
137 {
138 const auto &predefined_args = template_->predefined_args;
139 resp->templates[i].predefined_arguments_count = predefined_args.size();
140 resp->templates[i].predefined_arguments = static_cast<KeyValuePair *>(malloc(size: predefined_args.size() * sizeof(KeyValuePair)));
141 if (!resp->templates[i].predefined_arguments)
142 return RPC_RESULT_SERVER_INTERNAL_ERROR;
143 int j = 0;
144 for (const auto &[key, value] : predefined_args)
145 {
146 resp->templates[i].predefined_arguments[j].name = strdup(string: key.c_str());
147 resp->templates[i].predefined_arguments[j].value = strdup(string: value.c_str());
148 j++;
149 }
150 }
151
152 i++;
153 }
154
155 return RPC_RESULT_OK;
156}
157
158rpc_result_code_t ServiceManagerServer::start_unit(rpc_context_t *ctx, StartUnitRequest *req, StartUnitResponse *resp)
159{
160 (void) ctx;
161 resp->success = ServiceManager->StartUnit(id: req->unit_id);
162 return RPC_RESULT_OK;
163}
164
165rpc_result_code_t ServiceManagerServer::stop_unit(rpc_context_t *ctx, StopUnitRequest *req, StopUnitResponse *resp)
166{
167 (void) ctx;
168 resp->success = ServiceManager->StopUnit(id: req->unit_id);
169 return RPC_RESULT_OK;
170}
171
172rpc_result_code_t ServiceManagerServer::instantiate_unit(rpc_context_t *ctx, InstantiateUnitRequest *req, InstantiateUnitResponse *resp)
173{
174 (void) ctx;
175 ArgumentMap args;
176 for (size_t i = 0; i < req->parameters_count; i++)
177 {
178 const auto &param = req->parameters[i];
179 args[param.name] = param.value;
180 }
181
182 const auto unit = ConfigurationManager->InstantiateUnit(template_id: req->template_id, parameters: args);
183 if (!unit)
184 return RPC_RESULT_SERVER_INTERNAL_ERROR;
185
186 resp->unit_id = strdup(string: unit->id.c_str());
187 return RPC_RESULT_OK;
188}
189
190rpc_result_code_t ServiceManagerServer::get_unit_overrides(rpc_context_t *ctx, GetUnitOverridesRequest *req, GetUnitOverridesResponse *resp)
191{
192 (void) ctx;
193 (void) req;
194
195 const auto overrides = ConfigurationManager->GetTemplateOverrides();
196
197 resp->overrides_count = overrides.size();
198 resp->overrides = static_cast<RpcUnitOverride *>(malloc(size: overrides.size() * sizeof(RpcUnitOverride)));
199 if (!resp->overrides)
200 return RPC_RESULT_SERVER_INTERNAL_ERROR;
201
202 int i = 0;
203 for (const auto &[pair, override] : overrides)
204 {
205 const auto &[id, args] = pair;
206 resp->overrides[i].base_unit_id = strdup(string: id.c_str());
207 resp->overrides[i].overrides_count = args.size();
208 resp->overrides[i].overrides = static_cast<KeyValuePair *>(malloc(size: args.size() * sizeof(KeyValuePair)));
209 if (!resp->overrides[i].overrides)
210 return RPC_RESULT_SERVER_INTERNAL_ERROR;
211 int j = 0;
212 for (const auto &[key, value] : args)
213 {
214 resp->overrides[i].overrides[j].name = strdup(string: key.c_str());
215 resp->overrides[i].overrides[j].value = strdup(string: value.c_str());
216 j++;
217 }
218 resp->overrides[i].overridden_unit_id = strdup(string: override.c_str());
219 i++;
220 }
221
222 return RPC_RESULT_OK;
223}
224