Merge lp:~ted/ubuntu-app-launch/reset-units into lp:ubuntu-app-launch

Proposed by Ted Gould
Status: Superseded
Proposed branch: lp:~ted/ubuntu-app-launch/reset-units
Merge into: lp:ubuntu-app-launch
Prerequisite: lp:~ted/ubuntu-app-launch/install-root
Diff against target: 226 lines (+109/-11)
4 files modified
libubuntu-app-launch/jobs-systemd.cpp (+61/-6)
libubuntu-app-launch/jobs-systemd.h (+2/-0)
tests/jobs-systemd.cpp (+4/-1)
tests/systemd-mock.h (+42/-4)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/reset-units
Reviewer Review Type Date Requested Status
Indicator Applet Developers Pending
Review via email: mp+316291@code.launchpad.net

This proposal has been superseded by a proposal from 2017-02-03.

Commit message

Reset failed units so they can be tried again

To post a comment you must log in.
406. By Ted Gould

Merging future trunk

407. By Ted Gould

Add a test that catches the error

408. By Ted Gould

Check to ensure we get the reset on a failure

409. By Ted Gould

Add comment to describe the function

410. By Ted Gould

Attaching bug

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'libubuntu-app-launch/jobs-systemd.cpp'
2--- libubuntu-app-launch/jobs-systemd.cpp 2017-02-02 22:54:33 +0000
3+++ libubuntu-app-launch/jobs-systemd.cpp 2017-02-02 22:54:34 +0000
4@@ -306,7 +306,7 @@
5 auto unsub = [&](guint& handle) {
6 if (handle != 0)
7 {
8- g_dbus_connection_signal_unsubscribe(dbus_.get(), handle);
9+ g_dbus_connection_signal_unsubscribe(userbus_.get(), handle);
10 handle = 0;
11 }
12 };
13@@ -425,12 +425,24 @@
14 }
15 auto uris = findEnv("APP_URIS", env);
16
17+ g_debug("Exec line: %s", exec.c_str());
18+ g_debug("App URLS: %s", uris.c_str());
19+
20 auto execarray = desktop_exec_parse(exec.c_str(), uris.c_str());
21
22- std::vector<std::string> retval = {execarray->data, execarray->data + execarray->len};
23+ std::vector<std::string> retval;
24+ for (unsigned int i = 0; i < execarray->len; i++)
25+ {
26+ auto cstr = g_array_index(execarray, gchar*, i);
27+ if (cstr != nullptr)
28+ {
29+ retval.emplace_back(cstr);
30+ }
31+ }
32
33- g_array_set_clear_func(execarray, g_free);
34- g_array_free(execarray, TRUE);
35+ /* This seems to work better than array_free(), I can't figure out why */
36+ auto strv = (gchar**)g_array_free(execarray, FALSE);
37+ g_strfreev(strv);
38
39 if (retval.empty())
40 {
41@@ -786,7 +798,7 @@
42 auto retval = std::make_shared<instance::SystemD>(appId, job, instance, urls, registry);
43 auto chelper = new StartCHelper{};
44 chelper->ptr = retval;
45- chelper->bus = manager->userbus_;
46+ chelper->bus = registry->impl->_dbus;
47
48 tracepoint(ubuntu_app_launch, handshake_wait, appIdStr.c_str());
49 starting_handshake_wait(handshake);
50@@ -1269,7 +1281,7 @@
51 auto data = new FailedData{reg};
52
53 handle_appFailed = g_dbus_connection_signal_subscribe(
54- reg->impl->_dbus.get(), /* bus */
55+ userbus_.get(), /* bus */
56 SYSTEMD_DBUS_ADDRESS, /* sender */
57 "org.freedesktop.DBus.Properties", /* interface */
58 "PropertiesChanged", /* signal */
59@@ -1330,6 +1342,9 @@
60 }
61 g_variant_dict_clear(&dict);
62
63+ /* Reset the failure bit on the unit */
64+ manager->resetUnit(unitinfo);
65+
66 /* Oh, we might want to do something now */
67 auto reason{Registry::FailureType::CRASH};
68 if (g_strcmp0(value, "exit-code") == 0)
69@@ -1356,6 +1371,46 @@
70 return sig_appFailed;
71 }
72
73+void SystemD::resetUnit(const UnitInfo& info) const
74+{
75+ auto registry = registry_.lock();
76+ auto unitname = unitName(info);
77+ auto bus = userbus_;
78+ auto cancel = registry->impl->thread.getCancellable();
79+
80+ registry->impl->thread.executeOnThread([bus, unitname, cancel] {
81+ g_dbus_connection_call(bus.get(), /* user bus */
82+ SYSTEMD_DBUS_ADDRESS, /* bus name */
83+ SYSTEMD_DBUS_PATH_MANAGER, /* path */
84+ SYSTEMD_DBUS_IFACE_MANAGER, /* interface */
85+ "ResetFailedUnit", /* method */
86+ g_variant_new("(s)", /* params */
87+ unitname.c_str()), /* param: specify unit */
88+ nullptr, /* ret type */
89+ G_DBUS_CALL_FLAGS_NONE, /* flags */
90+ -1, /* timeout */
91+ cancel.get(), /* cancellable */
92+ [](GObject* obj, GAsyncResult* res, gpointer user_data) {
93+ GError* error{nullptr};
94+ GVariant* callt = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
95+
96+ if (error != nullptr)
97+ {
98+ if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
99+ {
100+ g_warning("Unable to reset failed unit: %s", error->message);
101+ }
102+ g_error_free(error);
103+ return;
104+ }
105+
106+ g_clear_pointer(&callt, g_variant_unref);
107+ g_debug("Reset Failed Unit");
108+ },
109+ nullptr);
110+ });
111+}
112+
113 } // namespace manager
114 } // namespace jobs
115 } // namespace app_launch
116
117=== modified file 'libubuntu-app-launch/jobs-systemd.h'
118--- libubuntu-app-launch/jobs-systemd.h 2017-02-02 22:54:33 +0000
119+++ libubuntu-app-launch/jobs-systemd.h 2017-02-02 22:54:34 +0000
120@@ -128,6 +128,8 @@
121
122 static std::vector<std::string> parseExec(std::list<std::pair<std::string, std::string>>& env);
123 static void application_start_cb(GObject* obj, GAsyncResult* res, gpointer user_data);
124+
125+ void resetUnit(const UnitInfo& info) const;
126 };
127
128 } // namespace manager
129
130=== modified file 'tests/jobs-systemd.cpp'
131--- tests/jobs-systemd.cpp 2017-02-02 22:54:33 +0000
132+++ tests/jobs-systemd.cpp 2017-02-02 22:54:34 +0000
133@@ -238,7 +238,7 @@
134 std::function<std::list<std::pair<std::string, std::string>>()> getenvfunc =
135 [&]() -> std::list<std::pair<std::string, std::string>> {
136 gotenv = true;
137- return {};
138+ return {{"APP_EXEC", "sh"}};
139 };
140
141 auto inst = manager->launch(multipleAppID(), defaultJobName(), "123", {},
142@@ -265,6 +265,9 @@
143 units.begin()->environment.end(),
144 units.begin()->environment.find(std::string{"DBUS_SESSION_BUS_ADDRESS="} + getenv("DBUS_SESSION_BUS_ADDRESS")));
145
146+ /* Ensure the exec is correct */
147+ EXPECT_EQ("/bin/sh", units.begin()->execpath);
148+
149 /* Try an entirely custom variable */
150 systemd->managerClear();
151 units.clear();
152
153=== modified file 'tests/systemd-mock.h'
154--- tests/systemd-mock.h 2017-02-02 22:54:33 +0000
155+++ tests/systemd-mock.h 2017-02-02 22:54:34 +0000
156@@ -326,6 +326,8 @@
157 {
158 std::string name;
159 std::set<std::string> environment;
160+ std::string execpath;
161+ std::list<std::string> execline;
162 };
163
164 std::list<TransientUnit> unitCalls()
165@@ -366,15 +368,16 @@
166 unit.name = name;
167
168 auto paramarray = g_variant_get_child_value(call.params, 2);
169- gchar* key;
170+ gchar* ckey;
171 GVariant* var;
172 GVariantIter iter;
173 g_variant_iter_init(&iter, paramarray);
174- while (g_variant_iter_loop(&iter, "(sv)", &key, &var))
175+ while (g_variant_iter_loop(&iter, "(sv)", &ckey, &var))
176 {
177- g_debug("Looking at parameter: %s", key);
178+ g_debug("Looking at parameter: %s", ckey);
179+ std::string key{ckey};
180
181- if (std::string{key} == "Environment")
182+ if (key == "Environment")
183 {
184 GVariantIter array;
185 gchar* envvar;
186@@ -385,6 +388,41 @@
187 unit.environment.emplace(envvar);
188 }
189 }
190+ else if (key == "ExecStart")
191+ {
192+ /* a(sasb) */
193+ if (g_variant_n_children(var) > 1)
194+ {
195+ g_warning("'ExecStart' has more than one entry, only processing the first");
196+ }
197+
198+ auto tuple = g_variant_get_child_value(var, 0);
199+
200+ const gchar* cpath = nullptr;
201+ g_variant_get_child(tuple, 0, "&s", &cpath);
202+
203+ if (cpath != nullptr)
204+ {
205+ unit.execpath = cpath;
206+ }
207+ else
208+ {
209+ g_warning("'ExecStart[0][0]' isn't a string?");
210+ }
211+
212+ auto vexecarray = g_variant_get_child_value(tuple, 1);
213+ GVariantIter execarray;
214+ g_variant_iter_init(&execarray, vexecarray);
215+ const gchar* execentry;
216+
217+ while (g_variant_iter_loop(&execarray, "&s", &execentry))
218+ {
219+ unit.execline.emplace_back(execentry);
220+ }
221+
222+ g_clear_pointer(&vexecarray, g_variant_unref);
223+ g_clear_pointer(&tuple, g_variant_unref);
224+ }
225 }
226 g_variant_unref(paramarray);
227

Subscribers

People subscribed via source and target branches