• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eclipse-bluechi / bluechi / 15181127791

22 May 2025 07:52AM UTC coverage: 82.57% (+0.3%) from 82.302%
15181127791

push

github

engelmi
Update integration tests for proxy service config feature

Signed-off-by: Michael Engel <mengel@redhat.com>

5661 of 6856 relevant lines covered (82.57%)

1574.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.21
/src/agent/proxy.c
1
/*
2
 * Copyright Contributors to the Eclipse BlueChi project
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
#include "libbluechi/log/log.h"
7

8
#include "agent.h"
9
#include "proxy.h"
10

11

12
static int proxy_service_method_error(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
13
static int proxy_service_method_target_state_changed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
14
static int proxy_service_method_target_new(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
15
static int proxy_service_method_target_removed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
16

17
static const sd_bus_vtable proxy_service_vtable[] = {
18
        SD_BUS_VTABLE_START(0),
19
        SD_BUS_METHOD("Error", "s", "", proxy_service_method_error, 0),
20
        SD_BUS_METHOD("TargetNew", "s", "", proxy_service_method_target_new, 0),
21
        SD_BUS_METHOD("TargetStateChanged", "sss", "", proxy_service_method_target_state_changed, 0),
22
        SD_BUS_METHOD("TargetRemoved", "s", "", proxy_service_method_target_removed, 0),
23
        SD_BUS_VTABLE_END
24
};
25

26
/* This is called by the controller when the service that is the target
27
 * of a proxy changes state.
28
 */
29

30
static void proxy_service_initial_state_reached(ProxyService *proxy, bool success) {
14✔
31
        Agent *agent = proxy->agent;
14✔
32
        int r = 0;
14✔
33

34
        assert(proxy->request_message != NULL);
14✔
35

36
        if (success) {
14✔
37
                bc_log_infof("Replying to %s successfully", proxy->local_service_name);
10✔
38
                proxy->sent_successful_ready = true;
10✔
39
                r = sd_bus_reply_method_return(proxy->request_message, "");
10✔
40
        } else {
41
                bc_log_infof("Replying to %s with failure", proxy->local_service_name);
4✔
42
                r = sd_bus_reply_method_errorf(
4✔
43
                                proxy->request_message,
44
                                BC_BUS_ERROR_ACTIVATION_FAILED,
45
                                "Proxy service failed to start");
46
        }
47

48
        if (r < 0) {
14✔
49
                bc_log_errorf("Failed to send reply to proxy request: %s", strerror(-r));
×
50
        }
51

52
        sd_bus_message_unrefp(&proxy->request_message);
14✔
53
        proxy->request_message = NULL;
14✔
54

55
        if (!proxy->sent_successful_ready) {
14✔
56
                agent_remove_proxy(agent, proxy, true);
4✔
57
        }
58
}
14✔
59

60
static void proxy_service_target_stopped(ProxyService *proxy) {
3✔
61
        Agent *agent = proxy->agent;
3✔
62

63
        bc_log_infof("Proxy for %s stopping due to target stopped", proxy->local_service_name);
3✔
64

65
        assert(proxy->request_message == NULL);
3✔
66
        agent_remove_proxy(agent, proxy, true);
3✔
67
}
3✔
68

69
static int proxy_service_method_target_state_changed(
22✔
70
                sd_bus_message *m, void *userdata, UNUSED sd_bus_error *ret_error) {
71
        _cleanup_proxy_service_ ProxyService *proxy = proxy_service_ref((ProxyService *) userdata);
44✔
72
        Agent *agent = proxy->agent;
22✔
73

74
        if (agent == NULL) {
22✔
75
                return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_FAILED, "Failed to get the proxy agent");
×
76
        }
77

78

79
        const char *active_state_str = NULL;
22✔
80
        const char *substate = NULL;
22✔
81
        const char *reason = NULL;
22✔
82
        int r = sd_bus_message_read(m, "sss", &active_state_str, &substate, &reason);
22✔
83
        if (r < 0) {
22✔
84
                return sd_bus_reply_method_errorf(
×
85
                                m,
86
                                SD_BUS_ERROR_INVALID_ARGS,
87
                                "Invalid argument for: active state, substate, or reason: %s",
88
                                strerror(-r));
89
        }
90

91
        UnitActiveState active_state = active_state_from_string(active_state_str);
22✔
92

93
        bc_log_debugf("Proxy service '%s' got TargetStateChanged from controller: %s %s %s",
22✔
94
                      proxy->local_service_name,
95
                      active_state_str,
96
                      substate,
97
                      reason);
98

99
        if (proxy->request_message) {
22✔
100
                /* We're waiting for the initial start-or-fail to report back
101
                 *
102
                 * There are two main things that can happen here.
103
                 *
104
                 * Either the state eventually changes to any kind of
105
                 * active state. Then we consider the target service
106
                 * to have started, and we report that, and switch to waiting
107
                 * for it to stop. It is possible that we get a virtual
108
                 * active state change because the service was already running,
109
                 * but this is fine here.
110
                 *
111
                 * Alternatively, we get a message that says the state
112
                 * switched to failed, or inactive. This means the service
113
                 * stopped, which we report as a failure to start the target.
114
                 * However, here we have to be careful about virtual inactive
115
                 * events, as we may get a virtual inactive for the current
116
                 * state before then getting a real transition to the new state.
117
                 *
118
                 * In addition, it is possible that we never ever change state, because
119
                 * the service fails to parse, for instance. If so, we hit the (real) removed
120
                 * event before seeing any activation. See below for that.
121
                 */
122

123
                if (active_state == UNIT_ACTIVE) {
10✔
124
                        proxy_service_initial_state_reached(proxy, true);
10✔
125
                } else if ((active_state == UNIT_FAILED || active_state == UNIT_INACTIVE) &&
×
126
                           streq(reason, "real")) {
×
127
                        proxy_service_initial_state_reached(proxy, false);
×
128
                }
129
        } else if (proxy->sent_successful_ready) {
12✔
130
                /* We reached the initial state and are now monitoring for the target to exit */
131
                if ((active_state == UNIT_FAILED || active_state == UNIT_INACTIVE) && streq(reason, "real")) {
12✔
132
                        proxy_service_target_stopped(proxy);
3✔
133
                }
134
        }
135

136
        return sd_bus_reply_method_return(m, "");
22✔
137
}
138

139
static int proxy_service_method_target_new(sd_bus_message *m, void *userdata, UNUSED sd_bus_error *ret_error) {
10✔
140
        _cleanup_proxy_service_ ProxyService *proxy = proxy_service_ref((ProxyService *) userdata);
20✔
141
        Agent *agent = proxy->agent;
10✔
142
        if (agent == NULL) {
10✔
143
                return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_FAILED, "Internal error");
×
144
        }
145

146
        const char *reason = NULL;
10✔
147
        int r = sd_bus_message_read(m, "s", &reason);
10✔
148
        if (r < 0) {
10✔
149
                return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Invalid arguments");
×
150
        }
151

152
        bc_log_debugf("Proxy service '%s' got TargetNew from controller: %s", proxy->local_service_name, reason);
10✔
153

154
        return sd_bus_reply_method_return(m, "");
10✔
155
}
156

157
static int proxy_service_method_target_removed(sd_bus_message *m, void *userdata, UNUSED sd_bus_error *ret_error) {
2✔
158
        _cleanup_proxy_service_ ProxyService *proxy = proxy_service_ref((ProxyService *) userdata);
4✔
159
        Agent *agent = proxy->agent;
2✔
160
        if (agent == NULL) {
2✔
161
                return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_FAILED, "Failed to get the proxy agent");
×
162
        }
163

164
        const char *reason = NULL;
2✔
165
        int r = sd_bus_message_read(m, "s", &reason);
2✔
166
        if (r < 0) {
2✔
167
                return sd_bus_reply_method_errorf(
×
168
                                m,
169
                                SD_BUS_ERROR_INVALID_ARGS,
170
                                "Invalid argument for the reason: %s",
171
                                strerror(-r));
172
        }
173

174
        bc_log_debugf("Proxy service '%s' got TargetRemoved from controller: %s",
2✔
175
                      proxy->local_service_name,
176
                      reason);
177

178
        /* See above in state_changed for details */
179

180
        if (proxy->request_message != NULL && streq(reason, "real")) {
2✔
181
                proxy_service_initial_state_reached(proxy, false);
×
182
        }
183

184
        return sd_bus_reply_method_return(m, "");
2✔
185
}
186

187
/* This is called by the controller when there was an error setting up the monitor.
188
 * Note, this is only sent once, and if it is sent, expect no other messages.
189
 */
190

191
static int proxy_service_method_error(sd_bus_message *m, void *userdata, UNUSED sd_bus_error *ret_error) {
4✔
192
        _cleanup_proxy_service_ ProxyService *proxy = proxy_service_ref((ProxyService *) userdata);
8✔
193
        Agent *agent = proxy->agent;
4✔
194

195
        if (agent == NULL) {
4✔
196
                return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_FAILED, "Failed to get the proxy agent");
×
197
        }
198

199
        const char *message = NULL;
4✔
200
        int r = sd_bus_message_read(m, "s", &message);
4✔
201
        if (r < 0) {
4✔
202
                message = "Got no message";
×
203
        }
204

205
        bc_log_errorf("Got proxy start error: %s", message);
4✔
206

207
        proxy_service_initial_state_reached(proxy, false);
4✔
208

209
        return sd_bus_reply_method_return(m, "");
4✔
210
}
211

212
ProxyService *proxy_service_new(
14✔
213
                Agent *agent,
214
                const char *local_service_name,
215
                const char *node,
216
                const char *unit,
217
                sd_bus_message *request_message) {
218
        static uint32_t next_id = 0;
14✔
219

220
        _cleanup_proxy_service_ ProxyService *proxy = malloc0(sizeof(ProxyService));
14✔
221
        if (proxy == NULL) {
14✔
222
                return NULL;
223
        }
224

225
        proxy->ref_count = 1;
14✔
226
        proxy->id = ++next_id;
14✔
227
        proxy->agent = agent;
14✔
228
        proxy->request_message = sd_bus_message_ref(request_message);
14✔
229
        LIST_INIT(proxy_services, proxy);
14✔
230

231
        proxy->node_name = strdup(node);
14✔
232
        if (proxy->node_name == NULL) {
14✔
233
                return NULL;
234
        }
235
        proxy->unit_name = strdup(unit);
14✔
236
        if (proxy->unit_name == NULL) {
14✔
237
                return NULL;
238
        }
239
        proxy->local_service_name = strdup(local_service_name);
14✔
240
        if (proxy->local_service_name == NULL) {
14✔
241
                return NULL;
242
        }
243

244
        int r = asprintf(&proxy->object_path, "%s/%u", INTERNAL_PROXY_OBJECT_PATH_PREFIX, proxy->id);
14✔
245
        if (r < 0) {
14✔
246
                return NULL;
247
        }
248

249
        return steal_pointer(&proxy);
250
}
251

252
ProxyService *proxy_service_ref(ProxyService *proxy) {
52✔
253
        proxy->ref_count++;
52✔
254
        return proxy;
52✔
255
}
256

257
void proxy_service_unref(ProxyService *proxy) {
66✔
258
        proxy->ref_count--;
66✔
259
        if (proxy->ref_count != 0) {
66✔
260
                return;
261
        }
262

263
        /* Should have been removed from list by now */
264
        assert(proxy->proxy_services_next == NULL);
14✔
265
        assert(proxy->proxy_services_prev == NULL);
14✔
266

267
        sd_bus_message_unrefp(&proxy->request_message);
14✔
268
        sd_bus_slot_unrefp(&proxy->export_slot);
14✔
269

270
        free_and_null(proxy->node_name);
14✔
271
        free_and_null(proxy->unit_name);
14✔
272
        free_and_null(proxy->local_service_name);
14✔
273
        free_and_null(proxy->object_path);
14✔
274
        free(proxy);
14✔
275
}
276

277
bool proxy_service_export(ProxyService *proxy) {
14✔
278
        int r = sd_bus_add_object_vtable(
28✔
279
                        proxy->agent->peer_dbus,
14✔
280
                        &proxy->export_slot,
281
                        proxy->object_path,
14✔
282
                        INTERNAL_PROXY_INTERFACE,
283
                        proxy_service_vtable,
284
                        proxy);
285
        if (r < 0) {
14✔
286
                bc_log_errorf("Failed to add service proxy vtable: %s", strerror(-r));
×
287
                return false;
×
288
        }
289
        return true;
290
}
291

292
void proxy_service_unexport(ProxyService *proxy) {
14✔
293
        sd_bus_slot_unrefp(&proxy->export_slot);
14✔
294
        proxy->export_slot = NULL;
14✔
295
}
14✔
296

297
int proxy_service_emit_proxy_new(ProxyService *proxy) {
14✔
298
        Agent *agent = proxy->agent;
14✔
299

300
        if (!agent_is_connected(agent)) {
14✔
301
                return -ENOTCONN;
302
        }
303

304
        bc_log_infof("Registering new proxy for %s (on %s)", proxy->unit_name, proxy->node_name);
14✔
305
        int res = sd_bus_emit_signal(
14✔
306
                        agent->peer_dbus,
307
                        INTERNAL_AGENT_OBJECT_PATH,
308
                        INTERNAL_AGENT_INTERFACE,
309
                        "ProxyNew",
310
                        "sso",
311
                        proxy->node_name,
312
                        proxy->unit_name,
313
                        proxy->object_path);
314
        if (res >= 0) {
14✔
315
                proxy->sent_new_proxy = true;
14✔
316
        }
317
        return res;
318
}
319

320
int proxy_service_emit_proxy_removed(ProxyService *proxy) {
12✔
321
        Agent *agent = proxy->agent;
12✔
322

323
        /* No need to tell the controller if we didn't announce this */
324
        if (!proxy->sent_new_proxy) {
12✔
325
                return 0;
326
        }
327

328
        if (!agent_is_connected(agent)) {
12✔
329
                return -ENOTCONN;
330
        }
331

332
        bc_log_infof("Unregistering proxy for %s (on %s)", proxy->unit_name, proxy->node_name);
12✔
333
        return sd_bus_emit_signal(
12✔
334
                        proxy->agent->peer_dbus,
12✔
335
                        INTERNAL_AGENT_OBJECT_PATH,
336
                        INTERNAL_AGENT_INTERFACE,
337
                        "ProxyRemoved",
338
                        "ss",
339
                        proxy->node_name,
340
                        proxy->unit_name);
341
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc