Merge lp:~mvo/software-center/polkit-lp785117 into lp:software-center
- polkit-lp785117
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 3123 |
Proposed branch: | lp:~mvo/software-center/polkit-lp785117 |
Merge into: | lp:software-center |
Diff against target: |
204 lines (+109/-9) (has conflicts) 3 files modified
softwarecenter/backend/installbackend_impl/aptd.py (+55/-5) softwarecenter/paths.py (+9/-1) tests/test_aptd.py (+45/-3) Text conflict in softwarecenter/paths.py |
To merge this branch: | bzr merge lp:~mvo/software-center/polkit-lp785117 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Evan (community) | Approve | ||
Matthew Paul Thomas | Pending | ||
software-store-developers | Pending | ||
Review via email: mp+112292@code.launchpad.net |
Commit message
Description of the change
This branch adds more error handling in the failure case.
Just like now errors like "NotAuthorized" or "NoReply" are ignored as policykit will already have displayed
something to the user. There is a new error message if the agent failed to launch, this can be tested in e.g.
a fvwm session.
Plus unknown errors are also displayed and the dialog asks for a bugreport, this should give us a idea if
there is anything else hidding here that needs attention. Matthew may want to tweak the error dialog texts,
but I think its ok to have them somewhat technically as this is a pretty rare circumstance when no policykit-agent
is available and lots of stuff will break in this case.
Michael Vogt (mvo) wrote : | # |
I updated the code now to use the new apport mechanism for reporting recoverable problems.
Michael Vogt (mvo) wrote : | # |
I updated the code now to use the new apport mechanism for reporting recoverable problems.
On Wed, Aug 22, 2012 at 8:57 AM, Michael Vogt <email address hidden> wrote:
> === modified file 'softwarecenter
> --- softwarecenter/
> +++ softwarecenter/
> @@ -973,13 +979,48 @@
> + return
> + if name in ["org.freedeskt
> + summary = _("Authentication Error")
> + text = _("Is policykit installed and an authentication "
> + "agent running? Error Details:\n%s") % error
> + self.ui.error(None, summary, text)
> + return
Can you clarify the rationale for creating a software-center dialog
and exiting the function here? I would have thought you'd want to have
graphs of the occurrence of the authentication agent not running, as
it may be more often than we suspect and be evidence of a larger
problem. We won't know until we measure though.
> + # show a apport recoverable error dialog to the user as we want
> + # to know about these issues
> + self._call_
> + _("There was a error submitting the transaction"), error)
Grammar nit: an before vowel sounds. So it's "there was an error."
> + # mvo: I don't think we need to send "Package\
> + # apport should figure this out itself
> + data = "DialogBody\
> + 'text': text,
> + 'error': error,
> + }
> + # this will be quick as it just writes the report file and the
> + # helper is spawned by apport asyncronsoly
Correct, but to clarify: the report is written, update-notifier has an
inotify watch on /var/crash and it then calls apport to process unseen
reports.
> + APPORT_
> + p = Popen(
> + [APPORT_
> +
> + (stdout, stderr) = p.communicate(
> + return_code = p.wait()
subprocess.
Lib/subprocess.
So you could just grab it off the pid member. There's no harm in
calling wait() again though, so feel free to leave that.
> === modified file 'tests/
> --- tests/test_aptd.py 2012-06-28 08:51:44 +0000
> +++ tests/test_aptd.py 2012-08-22 07:56:18 +0000
> @@ -121,5 +143,15 @@
> + @patch(
> + def test_recoverabl
> + mock_popen_instance = Mock()
> + mock_popen_
> + mock_popen_
> + mock_popen.
> + self.aptd.
> + mock_popen_
You could expand this to check the arguments to Popen and put a
StringIO on stdin to ensure that you're getting three nuls and the
right key-value pair...
Matthew Paul Thomas (mpt) wrote : | # |
Even if you did convert the custom error to an Apport one, though...
+ text = _("Is policykit installed and an authentication "
+ "agent running? Error Details:\n%s") % error
...A big part of USC's day job is to tell whether or not things are installed. Why is it now asking me whether something is installed? :-) (Even I have trouble with this particular question, because I confuse policykit and policykit-1.) Besides, software-center Depends on policykit-1 and policykit-1-gnome, so being uninstalled is unlikely to be the problem, unless it was removed (together with software-center itself) while USC was open.
Instead I suggest something like "Software can’t be installed or removed because the authentication service is not available. (%s)" % error
- 3032. By Michael Vogt
-
address the easy points of evans review
Michael Vogt (mvo) wrote : | # |
On Wed, Aug 22, 2012 at 11:31:08AM -0000, Matthew Paul Thomas wrote:
> Even if you did convert the custom error to an Apport one, though...
>
> + text = _("Is policykit installed and an authentication "
> + "agent running? Error Details:\n%s") % error
>
> ...A big part of USC's day job is to tell whether or not things are installed. Why is it now asking me whether something is installed? :-) (Even I have trouble with this particular question, because I confuse policykit and policykit-1.) Besides, software-center Depends on policykit-1 and policykit-1-gnome, so being uninstalled is unlikely to be the problem, unless it was removed (together with software-center itself) while USC was open.
Indeed, this part of the text dosn't make a lot of sense, it will be
installed, but it might not be running because its running inside a
environement that does not autostart it or because there is something
wrong with the install.
> Instead I suggest something like "Software can’t be installed or removed because the authentication service is not available. (%s)" % error
Thanks, I updated the text to match what you write.
I will also make this part of what is reported via apport as a
recoverable error so that we can get data on it as Evan suggested.
Cheers,
Michael
- 3033. By Michael Vogt
-
softwarecenter/
backend/ installbackend_ impl/aptd. py: update policykit error text to match the suggestion of mpt (thanks!) - 3034. By Michael Vogt
-
tests/test_aptd.py: improve test (and as a consequence the code) as suggested by Evan
- 3035. By Michael Vogt
-
tests/test_aptd.py: further improve the test
- 3036. By Michael Vogt
-
softwarecenter/
backend/ installbackend_ impl/aptd. py: send unavailable polkit agent also to apport
Michael Vogt (mvo) wrote : | # |
On Wed, Aug 22, 2012 at 11:10:00AM -0000, Evan Dandrea wrote:
> On Wed, Aug 22, 2012 at 8:57 AM, Michael Vogt <email address hidden> wrote:
> > === modified file 'softwarecenter
> > --- softwarecenter/
> > +++ softwarecenter/
> > @@ -973,13 +979,48 @@
> > + return
> > + if name in ["org.freedeskt
> > + summary = _("Authentication Error")
> > + text = _("Is policykit installed and an authentication "
> > + "agent running? Error Details:\n%s") % error
> > + self.ui.error(None, summary, text)
> > + return
>
> Can you clarify the rationale for creating a software-center dialog
> and exiting the function here? I would have thought you'd want to have
> graphs of the occurrence of the authentication agent not running, as
> it may be more often than we suspect and be evidence of a larger
> problem. We won't know until we measure though.
You are right, it should be meassured, I now modified the code to do
that.
What is your opinion on showing the internal dialog still in addition
to fire of the report to apport? The assumption here is that the user
might not have update-notifier runnig to pick the report up
immediately and because in this case we know what the problem is its
nice to show it to the user. Alternatively I could make this
conditional, i.e. if update-notifier is availalbe rely on that and if
not display a internal dialog. WDYT?
> > + # show a apport recoverable error dialog to the user as we want
> > + # to know about these issues
> > + self._call_
> > + _("There was a error submitting the transaction"), error)
>
> Grammar nit: an before vowel sounds. So it's "there was an error."
Fixed.
> > + # mvo: I don't think we need to send "Package\
> > + # apport should figure this out itself
> > + data = "DialogBody\
> > + 'text': text,
> > + 'error': error,
> > + }
> > + # this will be quick as it just writes the report file and the
> > + # helper is spawned by apport asyncronsoly
>
> Correct, but to clarify: the report is written, update-notifier has an
> inotify watch on /var/crash and it then calls apport to process unseen
> reports.
I updated the comment in the code to make this a bit clearer.
> > + APPORT_
> > + p = Popen(
> > + [APPORT_
> > +
> > + (stdout, stderr) = p.communicate(
> > + return_code = p.wait()
>
> subprocess.
> Lib/subprocess.
>
> So you could just grab it off the pid member. There's no harm in
> calling wait() again though, so feel free to leave that.
Good point :) I simply use p.returncode now.
> > === modifie...
- 3037. By Michael Vogt
-
trivial pep8 fixes
On Thu, Aug 23, 2012 at 1:30 PM, Michael Vogt <email address hidden> wrote:
> What is your opinion on showing the internal dialog still in addition
> to fire of the report to apport? The assumption here is that the user
> might not have update-notifier runnig to pick the report up
> immediately and because in this case we know what the problem is its
> nice to show it to the user. Alternatively I could make this
> conditional, i.e. if update-notifier is availalbe rely on that and if
> not display a internal dialog. WDYT?
I think the cases of update-notifier are sufficiently small to not
burden everyone with redundant dialogs. For what it's worth, using
update-notifier for inotify watches will be replaced by upstart
inotify events once James has finished those.
The rest looks good.
Preview Diff
1 | === modified file 'softwarecenter/backend/installbackend_impl/aptd.py' |
2 | --- softwarecenter/backend/installbackend_impl/aptd.py 2012-08-07 13:15:08 +0000 |
3 | +++ softwarecenter/backend/installbackend_impl/aptd.py 2012-08-23 12:29:44 +0000 |
4 | @@ -21,6 +21,12 @@ |
5 | import logging |
6 | import os |
7 | import re |
8 | +import traceback |
9 | + |
10 | +from subprocess import ( |
11 | + Popen, |
12 | + PIPE, |
13 | + ) |
14 | |
15 | from gi.repository import GObject |
16 | |
17 | @@ -29,7 +35,11 @@ |
18 | obfuscate_private_ppa_details, |
19 | utf8, |
20 | ) |
21 | -from softwarecenter.enums import TransactionTypes, PURCHASE_TRANSACTION_ID |
22 | +from softwarecenter.enums import ( |
23 | + TransactionTypes, |
24 | + PURCHASE_TRANSACTION_ID, |
25 | + ) |
26 | +from softwarecenter.paths import APPORT_RECOVERABLE_ERROR |
27 | |
28 | from aptdaemon import client |
29 | from aptdaemon import enums |
30 | @@ -973,13 +983,53 @@ |
31 | |
32 | self.emit("transaction-stopped", result) |
33 | if isinstance(error, dbus.DBusException): |
34 | + # ignore errors that the user knows about already (like |
35 | + # that he entered a wrong password or that he does not |
36 | + # care about (like no-reply) |
37 | name = error.get_dbus_name() |
38 | if name in ["org.freedesktop.PolicyKit.Error.NotAuthorized", |
39 | "org.freedesktop.DBus.Error.NoReply"]: |
40 | - pass |
41 | - else: |
42 | - self._logger.exception("_on_trans_error") |
43 | - #raise error |
44 | + return |
45 | + # we want to give some advice here to the user but also |
46 | + # report this via apport |
47 | + if name in ["org.freedesktop.PolicyKit.Error.Failed"]: |
48 | + summary = _("Authentication Error") |
49 | + text = _("Software can't be installed or removed because " |
50 | + "the authentication service is not available. " |
51 | + "(%s") % error |
52 | + # send to apport for reporting |
53 | + self._call_apport_recoverable_error(text, error) |
54 | + # ... and display as a dialog |
55 | + self.ui.error(None, summary, text) |
56 | + return |
57 | + # show a apport recoverable error dialog to the user as we want |
58 | + # to know about these issues |
59 | + self._call_apport_recoverable_error( |
60 | + _("There was an error submitting the transaction"), error) |
61 | + |
62 | + def _call_apport_recoverable_error(self, text, error): |
63 | + """Call apports recoverable_problem dialog """ |
64 | + |
65 | + # ensure we have a proper expection string in the report |
66 | + if isinstance(error, Exception): |
67 | + error = traceback.format_exc(error) |
68 | + |
69 | + # mvo: I don't think we need to send "Package\0software-center", |
70 | + # apport should figure this out itself |
71 | + data = "DialogBody\0%(text)s\0Traceback\0%(error)s" % { |
72 | + 'text': text, |
73 | + 'error': error, |
74 | + } |
75 | + # This will be quick as it just writes the report file. Then |
76 | + # the report gets picked up asynchronously by a inotify watch |
77 | + # and displayed to the user in a seperate process. |
78 | + p = Popen( |
79 | + [APPORT_RECOVERABLE_ERROR], stdin=PIPE, stdout=PIPE, stderr=PIPE) |
80 | + |
81 | + (stdout, stderr) = p.communicate(input=data) |
82 | + if p.returncode != 0: |
83 | + logging.warn("%s returned '%s' ('%s', '%s')" % ( |
84 | + APPORT_RECOVERABLE_ERROR, p.returncode, stdout, stderr)) |
85 | |
86 | |
87 | if __name__ == "__main__": |
88 | |
89 | === modified file 'softwarecenter/paths.py' |
90 | --- softwarecenter/paths.py 2012-08-22 08:16:30 +0000 |
91 | +++ softwarecenter/paths.py 2012-08-23 12:29:44 +0000 |
92 | @@ -73,7 +73,15 @@ |
93 | # OEM |
94 | OEM_CHANNEL_DESCRIPTOR = "/var/lib/ubuntu-dist-channel" |
95 | |
96 | - |
97 | +<<<<<<< TREE |
98 | + |
99 | +======= |
100 | + |
101 | +# apport |
102 | +APPORT_RECOVERABLE_ERROR = "/usr/share/apport/recoverable_problem" |
103 | + |
104 | + |
105 | +>>>>>>> MERGE-SOURCE |
106 | # ratings&review |
107 | # relative to datadir |
108 | class RNRApps: |
109 | |
110 | === modified file 'tests/test_aptd.py' |
111 | --- tests/test_aptd.py 2012-06-28 08:51:44 +0000 |
112 | +++ tests/test_aptd.py 2012-08-23 12:29:44 +0000 |
113 | @@ -3,18 +3,23 @@ |
114 | |
115 | import logging |
116 | import os |
117 | +import subprocess |
118 | import time |
119 | import unittest |
120 | |
121 | +import dbus |
122 | + |
123 | from tests.utils import ( |
124 | setup_test_env, |
125 | ) |
126 | setup_test_env() |
127 | |
128 | +from softwarecenter.backend.installbackend_impl.aptd import AptdaemonBackend |
129 | from softwarecenter.db.application import Application |
130 | -from softwarecenter.backend.installbackend_impl.aptd import AptdaemonBackend |
131 | +from softwarecenter.paths import APPORT_RECOVERABLE_ERROR |
132 | + |
133 | from defer import inline_callbacks |
134 | -from mock import Mock |
135 | +from mock import Mock, patch |
136 | |
137 | import aptdaemon.loop |
138 | |
139 | @@ -24,6 +29,7 @@ |
140 | |
141 | def setUp(self): |
142 | self.aptd = AptdaemonBackend() |
143 | + self.aptd.ui = Mock() |
144 | # monkey patch |
145 | self.aptd.aptd_client.install_packages = self._mock_aptd_client_install_packages |
146 | self._pkgs_to_install = [] |
147 | @@ -105,6 +111,25 @@ |
148 | addons_remove = ["gimp-plugin-registry"] |
149 | yield self.aptd.apply_changes(pkgname, appname ,iconname, addons_install, addons_remove) |
150 | |
151 | + |
152 | + def test_trans_error_ui_display(self): |
153 | + """ test if the right error ui is displayed for various dbus |
154 | + errors |
155 | + """ |
156 | + error = dbus.DBusException() |
157 | + dbus_name_mock = Mock() |
158 | + with patch.object(self.aptd.ui, "error") as error_ui_mock: |
159 | + for dbus_name, show_error_ui in [ |
160 | + ("org.freedesktop.PolicyKit.Error.NotAuthorized", False), |
161 | + ("org.freedesktop.PolicyKit.Error.Failed", True), |
162 | + ("moo.baa.lalala", True), |
163 | + ]: |
164 | + error_ui_mock.reset() |
165 | + dbus_name_mock.return_value = dbus_name |
166 | + error.get_dbus_name = dbus_name_mock |
167 | + self.aptd._on_trans_error(error) |
168 | + self.assertEqual(error_ui_mock.called, show_error_ui) |
169 | + |
170 | @inline_callbacks |
171 | def _inline_add_repo_call(self): |
172 | deb_line = "deb https://foo" |
173 | @@ -113,7 +138,7 @@ |
174 | iconname = "iconname" |
175 | yield self.aptd.add_repo_add_key_and_install_app( |
176 | deb_line, signing_key_id, app, iconname, None, None) |
177 | - |
178 | + |
179 | def test_add_repo_add_key_and_install_app(self): |
180 | from mock import patch |
181 | with patch.object(self.aptd._logger, "info") as mock: |
182 | @@ -121,5 +146,22 @@ |
183 | self.assertTrue( |
184 | mock.call_args[0][0].startswith("add_repo_add_key")) |
185 | |
186 | + @patch("softwarecenter.backend.installbackend_impl.aptd.Popen") |
187 | + def test_recoverable_error(self, mock_popen): |
188 | + mock_popen_instance = Mock() |
189 | + mock_popen_instance.communicate.return_value = ("stdout", "stderr") |
190 | + mock_popen_instance.returncode = 0 |
191 | + mock_popen.return_value = mock_popen_instance |
192 | + self.aptd._call_apport_recoverable_error("msg", "traceback-error") |
193 | + mock_popen.assert_called_with( |
194 | + [APPORT_RECOVERABLE_ERROR], stdin=subprocess.PIPE, |
195 | + stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
196 | + # check that we really send the right data |
197 | + args, kwargs = mock_popen_instance.communicate.call_args |
198 | + self.assertEqual( |
199 | + kwargs["input"].split("\0"), |
200 | + [ 'DialogBody', 'msg','Traceback', 'traceback-error']) |
201 | + |
202 | + |
203 | if __name__ == "__main__": |
204 | unittest.main() |
I believe that recovering from errors while at the same time reporting them is something that we're going to want to do often and consistently.
Matthew had a work item this cycle to create the interface for an application- triggered recoverable error report: /wiki.ubuntu. com/ErrorTracke r#app-requested
https:/
I've implemented this first as a DBus service: /code.launchpad .net/~ev/ apport/ recoverable- errors/ +merge/ 111840
https:/
There is an ongoing discussion on picking a communication channel with far fewer dependencies than DBus, but whatever the result we will have something implemented for 12.10.
Michael, I would love your input on that merge request in the hope that we can build something that addresses what you're trying to achieve here.