Merge ~nteodosio/software-properties:xenial-ua into software-properties:ubuntu/xenial
- Git
- lp:~nteodosio/software-properties
- xenial-ua
- Merge into ubuntu/xenial
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | a57fef40be0414b68c795d62b1a6cac70eb16a75 | ||||
Proposed branch: | ~nteodosio/software-properties:xenial-ua | ||||
Merge into: | software-properties:ubuntu/xenial | ||||
Diff against target: |
1919 lines (+1719/-4) 14 files modified
data/gtkbuilder/dialog-ua-attach.ui (+232/-0) data/gtkbuilder/dialog-ua-detach.ui (+64/-0) data/gtkbuilder/dialog-ua-fips-enable.ui (+82/-0) data/gtkbuilder/main.ui (+530/-2) data/ubuntu-pro-logo.svg (+24/-0) debian/control (+3/-1) debian/software-properties-gtk.install (+1/-0) softwareproperties/SoftwareProperties.py (+2/-1) softwareproperties/gtk/DialogUaAttach.py (+201/-0) softwareproperties/gtk/DialogUaDetach.py (+71/-0) softwareproperties/gtk/DialogUaFipsEnable.py (+52/-0) softwareproperties/gtk/SoftwarePropertiesGtk.py (+69/-0) softwareproperties/gtk/UbuntuProPage.py (+293/-0) softwareproperties/gtk/utils.py (+95/-0) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Sebastien Bacher | Approve | ||
Review via email: mp+448388@code.launchpad.net |
Commit message
Description of the change
This is a backport of the Ubuntu Pro tab to Xenial's software-
Nathan Teodosio (nteodosio) wrote : | # |
Nathan Teodosio (nteodosio) wrote : | # |
I think I fixed the SVG problem by manually tweaking the <rect> <circle> and <path> parameters in it: https:/
Once design approves it, I think we are good to go.
Sebastien Bacher (seb128) wrote (last edit ): | # |
Thanks, since it uses distro_info it also needs to Depends on python3-
Trying to start on fresh xenial install it errors out on 'uaclient' not existing, it should also have a versioned depends on 'ubuntu-
After installing those software-properties still errors out
Traceback (most recent call last):
File "/usr/bin/
app = SoftwarePropert
File "/usr/lib/
self.
File "/usr/lib/
status = get_ua_status()
File "/usr/lib/
status = json.loads(
File "/usr/lib/
s._
TypeError: the JSON object must be str, not 'bytes'
I've tested by building a deb of the current xenial package and that patch on top
Nathan Teodosio (nteodosio) wrote : | # |
I was able to reproduce the error in a new Xenial virtual machine, though my old one was still fine with it... ¯\_(ツ)_/¯
Thanks for the review, I addressed your comments.
Nathan Teodosio (nteodosio) wrote : | # |
Wait, it seems that if I build and install the package it doesn't find the SVG. Let me check that.
Sebastien Bacher (seb128) wrote : | # |
Now I get
Traceback (most recent call last):
File "/usr/bin/
app = SoftwarePropert
File "/usr/lib/
self.
File "/usr/lib/
status = get_ua_status()
File "/usr/lib/
status = json.loads(
AttributeError: 'str' object has no attribute 'decode'
Nathan Teodosio (nteodosio) wrote : | # |
There is something odd going on here... Your two error messages are saying that now status_json is bytes, now string.
I remember having problems with the part
--->
result = subprocess.run(
)
<---
never returning and working around it. I wonder if it could be related.
I'll try to reproduce the issue on my end but if all else fails maybe a try except for type(status_json) will have to do it.
Sebastien Bacher (seb128) wrote : | # |
weird, now it returns a str indeed, maybe one of the ubuntu-
Nathan Teodosio (nteodosio) wrote : | # |
There was actually nothing odd, it's just that once it reads from ua
call it is one type and when it reads from status.json it is another. I
guess I don't function alright at evening! :P
Sebastien Bacher (seb128) wrote : | # |
It works now but any idea why we need the .decode there where it seems it's not in the focal or master versions? Did the python default behavior changed in newer series? if so maybe we should add a code comment explaining?
Nathan Teodosio (nteodosio) wrote : | # |
Yes, json.loads accepts since Python 3.6 a bytes value[1]. Xenial is on 3.5.
Sebastien Bacher (seb128) wrote : | # |
Thanks, it's working without issue now!
I've updated the po/POTFILES.in to list the new files for translations and merged/uploaded
Note that the livepatch checkbox stay inactive because update-notifier version in xenial doesn't have livepatch integration atm, might be one to work on later if there is demand for it
Preview Diff
1 | diff --git a/data/gtkbuilder/dialog-ua-attach.ui b/data/gtkbuilder/dialog-ua-attach.ui |
2 | new file mode 100644 |
3 | index 0000000..b1563f1 |
4 | --- /dev/null |
5 | +++ b/data/gtkbuilder/dialog-ua-attach.ui |
6 | @@ -0,0 +1,232 @@ |
7 | +<?xml version="1.0" encoding="UTF-8"?> |
8 | +<interface> |
9 | + <requires lib="gtk+" version="3.16"/> |
10 | + <object class="GtkDialog" id="dialog_ua_attach"> |
11 | + <property name="can-focus">False</property> |
12 | + <property name="border-width">18</property> |
13 | + <property name="title" translatable="yes">Enable Ubuntu Pro</property> |
14 | + <property name="resizable">False</property> |
15 | + <property name="modal">True</property> |
16 | + <property name="type-hint">dialog</property> |
17 | + <property name="skip-taskbar-hint">True</property> |
18 | + <!-- interface-requires gtk+ 3.0 --> |
19 | + <child internal-child="vbox"> |
20 | + <object class="GtkBox"> |
21 | + <property name="visible">True</property> |
22 | + <property name="can-focus">False</property> |
23 | + <property name="no-show-all">True</property> |
24 | + <property name="orientation">vertical</property> |
25 | + <child> |
26 | + <object class="GtkLabel"> |
27 | + <property name="visible">True</property> |
28 | + <property name="can-focus">True</property> |
29 | + <property name="label" translatable="yes">To upgrade to Ubuntu Pro, use your existing free personal, or company Ubuntu One account, or provide a token. <a href="https://ubuntu.com/login">Register a new account</a>.</property> |
30 | + <property name="use-markup">True</property> |
31 | + <property name="wrap">True</property> |
32 | + <property name="max-width-chars">130</property> |
33 | + </object> |
34 | + </child> |
35 | + <child> |
36 | + <object class="GtkBox" id="radio_net_control_box"> |
37 | + <property name="visible">True</property> |
38 | + <property name="orientation">vertical</property> |
39 | + <child> |
40 | + <object class="GtkRadioButton" id="magic_radio"> |
41 | + <property name="label" translatable="yes">Enter code on ubuntu.com/pro/attach</property> |
42 | + <property name="visible">True</property> |
43 | + <property name="can-focus">True</property> |
44 | + <property name="receives-default">False</property> |
45 | + <property name="margin-top">30</property> |
46 | + <property name="xalign">0</property> |
47 | + <property name="group">magic_radio</property> |
48 | + <signal name="toggled" handler="on_radio_toggled" swapped="no"/> |
49 | + <signal name="clicked" handler="on_magic_radio_clicked" swapped="no"/> |
50 | + </object> |
51 | + </child> |
52 | + <child> |
53 | + <object class="GtkBox"> |
54 | + <property name="visible">True</property> |
55 | + <property name="can-focus">False</property> |
56 | + <property name="orientation">horizontal</property> |
57 | + <child> |
58 | + <object class="GtkBox" id="pin_label_box"> |
59 | + <property name="visible">True</property> |
60 | + <property name="margin-left">20</property> |
61 | + <property name="margin-top">12</property> |
62 | + <property name="margin-bottom">8</property> |
63 | + <property name="can-focus">False</property> |
64 | + <child> |
65 | + <object class="GtkLabel" id="pin_label"> |
66 | + <property name="label"> </property> |
67 | + <property name="visible">True</property> |
68 | + <property name="selectable">True</property> |
69 | + <property name="can-focus">False</property> |
70 | + <property name="halign">start</property> |
71 | + <property name="margin-left">6</property> |
72 | + <property name="margin-right">6</property> |
73 | + <property name="margin-top">4</property> |
74 | + <property name="margin-bottom">4</property> |
75 | + <attributes> |
76 | + <attribute name="scale" value="2"/> |
77 | + </attributes> |
78 | + </object> |
79 | + </child> |
80 | + </object> |
81 | + </child> |
82 | + <child> |
83 | + <object class="GtkFixed"> |
84 | + <property name="visible">True</property> |
85 | + <property name="valign">center</property> |
86 | + <property name="margin">3</property> |
87 | + <property name="margin-left">9</property> |
88 | + <child> |
89 | + <object class="GtkSpinner" id="pin_spinner"> |
90 | + <property name="visible">True</property> |
91 | + <property name="valign">center</property> |
92 | + </object> |
93 | + </child> |
94 | + <child> |
95 | + <object class="GtkImage" id="pin_status_icon"> |
96 | + <property name="visible">False</property> |
97 | + <property name="valign">center</property> |
98 | + </object> |
99 | + </child> |
100 | + </object> |
101 | + </child> |
102 | + <child> |
103 | + <object class="GtkLabel" id="pin_status"> |
104 | + <property name="margin">3</property> |
105 | + <property name="visible">True</property> |
106 | + <property name="valign">center</property> |
107 | + <property name="use-markup">True</property> |
108 | + </object> |
109 | + </child> |
110 | + </object> |
111 | + </child> |
112 | + <child> |
113 | + <object class="GtkRadioButton" id="token_radio"> |
114 | + <property name="label" translatable="yes">Or add token manually</property> |
115 | + <property name="visible">True</property> |
116 | + <property name="can-focus">True</property> |
117 | + <property name="receives-default">False</property> |
118 | + <property name="margin-top">6</property> |
119 | + <property name="xalign">0</property> |
120 | + <property name="group">magic_radio</property> |
121 | + <signal name="toggled" handler="on_radio_toggled" swapped="no"/> |
122 | + </object> |
123 | + </child> |
124 | + <child> |
125 | + <object class="GtkBox"> |
126 | + <property name="visible">True</property> |
127 | + <property name="can-focus">False</property> |
128 | + <property name="no-show-all">True</property> |
129 | + <child> |
130 | + <object class="GtkEntry" id="token_field"> |
131 | + <property name="visible">True</property> |
132 | + <property name="sensitive">False</property> |
133 | + <property name="can-focus">True</property> |
134 | + <property name="margin-left">20</property> |
135 | + <property name="margin-top">12</property> |
136 | + <property name="margin-bottom">12</property> |
137 | + <property name="margin-right">4</property> |
138 | + <property name="width-chars">35</property> |
139 | + <property name="placeholder-text" translatable="yes">Token</property> |
140 | + <property name="halign">start</property> |
141 | + <signal name="activate" handler="on_token_entry_activate" swapped="no"/> |
142 | + <signal name="changed" handler="on_token_typing" swapped="no"/> |
143 | + </object> |
144 | + </child> |
145 | + <child> |
146 | + <object class="GtkFixed"> |
147 | + <property name="visible">True</property> |
148 | + <property name="valign">center</property> |
149 | + <property name="margin">3</property> |
150 | + <child> |
151 | + <object class="GtkSpinner" id="token_spinner"> |
152 | + <property name="visible">True</property> |
153 | + <property name="valign">center</property> |
154 | + </object> |
155 | + </child> |
156 | + <child> |
157 | + <object class="GtkImage" id="token_status_icon"> |
158 | + <property name="visible">False</property> |
159 | + <property name="valign">center</property> |
160 | + </object> |
161 | + </child> |
162 | + </object> |
163 | + </child> |
164 | + <child> |
165 | + <object class="GtkLabel" id="token_status"> |
166 | + <property name="margin">3</property> |
167 | + <property name="visible">True</property> |
168 | + <property name="valign">center</property> |
169 | + <property name="use-markup">True</property> |
170 | + </object> |
171 | + </child> |
172 | + </object> |
173 | + </child> |
174 | + <child> |
175 | + <object class="GtkLabel"> |
176 | + <property name="visible">True</property> |
177 | + <property name="halign">start</property> |
178 | + <property name="margin-left">20</property> |
179 | + <property name="use-markup">True</property> |
180 | + <property name="label" translatable="yes">From your admin, or from <a href="https://ubuntu.com/pro">ubuntu.com/pro</a></property> |
181 | + </object> |
182 | + </child> |
183 | + </object> |
184 | + </child> |
185 | + <child> |
186 | + <object class="GtkBox" id="no_connection"> |
187 | + <property name="visible">False</property> |
188 | + <property name="margin-left">5</property> |
189 | + <property name="margin-top">18</property> |
190 | + <property name="margin-bottom">18</property> |
191 | + <child> |
192 | + <object class="GtkImage"> |
193 | + <property name="visible">True</property> |
194 | + <property name="margin-right">5</property> |
195 | + <property name="stock">gtk-dialog-warning</property> |
196 | + </object> |
197 | + </child> |
198 | + <child> |
199 | + <object class="GtkLabel"> |
200 | + <property name="visible">True</property> |
201 | + <property name="wrap">True</property> |
202 | + <property name="label" translatable="yes">Unable to connect to Ubuntu Pro servers. Check your internet connection.</property> |
203 | + </object> |
204 | + </child> |
205 | + </object> |
206 | + </child> |
207 | + <child> |
208 | + <object class="GtkBox"> |
209 | + <property name="visible">True</property> |
210 | + <property name="orientation">horizontal</property> |
211 | + <property name="halign">end</property> |
212 | + <child> |
213 | + <object class="GtkButton" id="cancel"> |
214 | + <property name="visible">True</property> |
215 | + <property name="margin-right">10</property> |
216 | + <property name="label" translatable="yes">Cancel</property> |
217 | + <signal name="clicked" handler="on_cancel_clicked" swapped="no"/> |
218 | + </object> |
219 | + </child> |
220 | + <child> |
221 | + <object class="GtkBox" id="confirm_net_control_box"> |
222 | + <property name="visible">True</property> |
223 | + <child> |
224 | + <object class="GtkButton" id="confirm"> |
225 | + <property name="visible">True</property> |
226 | + <property name="label" translatable="yes">Confirm</property> |
227 | + <property name="sensitive">False</property> |
228 | + <signal name="clicked" handler="on_confirm_clicked" swapped="no"/> |
229 | + </object> |
230 | + </child> |
231 | + </object> |
232 | + </child> |
233 | + </object> |
234 | + </child> |
235 | + </object> |
236 | + </child> |
237 | + </object> |
238 | +</interface> |
239 | diff --git a/data/gtkbuilder/dialog-ua-detach.ui b/data/gtkbuilder/dialog-ua-detach.ui |
240 | new file mode 100644 |
241 | index 0000000..dec72c8 |
242 | --- /dev/null |
243 | +++ b/data/gtkbuilder/dialog-ua-detach.ui |
244 | @@ -0,0 +1,64 @@ |
245 | +<?xml version="1.0"?> |
246 | +<interface> |
247 | + <object class="GtkDialog" id="dialog_ua_detach"> |
248 | + <property name="border_width">18</property> |
249 | + <property name="title" translatable="yes">Disable Ubuntu Pro</property> |
250 | + <property name="resizable">False</property> |
251 | + <property name="modal">True</property> |
252 | + <property name="type_hint">dialog</property> |
253 | + <property name="skip_taskbar_hint">True</property> |
254 | + <child internal-child="vbox"> |
255 | + <object class="GtkBox"> |
256 | + <property name="orientation">vertical</property> |
257 | + <property name="spacing">18</property> |
258 | + <child> |
259 | + <object class="GtkBox"> |
260 | + <property name="visible">True</property> |
261 | + <property name="orientation">vertical</property> |
262 | + <property name="spacing">18</property> |
263 | + <child> |
264 | + <object class="GtkLabel"> |
265 | + <property name="visible">True</property> |
266 | + <property name="label" translatable="yes">Disabling Ubuntu Pro will detach your subscription from this machine. Do you want to proceed?</property> |
267 | + <property name="use_markup">True</property> |
268 | + <property name="xalign">0</property> |
269 | + </object> |
270 | + </child> |
271 | + <child> |
272 | + <object class="GtkLabel" id="label_detach_error"> |
273 | + <property name="visible">True</property> |
274 | + <property name="xalign">0</property> |
275 | + <attributes> |
276 | + <attribute name="foreground" value="red"/> |
277 | + <attribute name="scale" value="0.9"/> |
278 | + </attributes> |
279 | + </object> |
280 | + </child> |
281 | + </object> |
282 | + </child> |
283 | + </object> |
284 | + </child> |
285 | + <child internal-child="action_area"> |
286 | + <object class="GtkHButtonBox"> |
287 | + <property name="visible">True</property> |
288 | + <property name="layout_style">end</property> |
289 | + <child> |
290 | + <object class="GtkButton"> |
291 | + <property name="visible">True</property> |
292 | + <property name="label" translatable="yes">No, go _back</property> |
293 | + <property name="use_underline">True</property> |
294 | + <signal name="clicked" handler="on_cancel_clicked"/> |
295 | + </object> |
296 | + </child> |
297 | + <child> |
298 | + <object class="GtkButton" id="button_detach"> |
299 | + <property name="visible">True</property> |
300 | + <property name="label" translatable="yes">_Disable Ubuntu Pro</property> |
301 | + <property name="use_underline">True</property> |
302 | + <signal name="clicked" handler="on_detach_clicked"/> |
303 | + </object> |
304 | + </child> |
305 | + </object> |
306 | + </child> |
307 | + </object> |
308 | +</interface> |
309 | diff --git a/data/gtkbuilder/dialog-ua-fips-enable.ui b/data/gtkbuilder/dialog-ua-fips-enable.ui |
310 | new file mode 100644 |
311 | index 0000000..5595121 |
312 | --- /dev/null |
313 | +++ b/data/gtkbuilder/dialog-ua-fips-enable.ui |
314 | @@ -0,0 +1,82 @@ |
315 | +<?xml version="1.0"?> |
316 | +<interface> |
317 | + <object class="GtkDialog" id="dialog_ua_fips_enable"> |
318 | + <property name="border_width">18</property> |
319 | + <property name="title" translatable="yes">Enable FIPS</property> |
320 | + <property name="resizable">False</property> |
321 | + <property name="modal">True</property> |
322 | + <property name="type_hint">dialog</property> |
323 | + <property name="skip_taskbar_hint">True</property> |
324 | + <child internal-child="vbox"> |
325 | + <object class="GtkBox"> |
326 | + <property name="orientation">vertical</property> |
327 | + <property name="spacing">18</property> |
328 | + <child> |
329 | + <object class="GtkBox"> |
330 | + <property name="visible">True</property> |
331 | + <property name="orientation">vertical</property> |
332 | + <property name="spacing">18</property> |
333 | + <child> |
334 | + <object class="GtkLabel"> |
335 | + <property name="visible">True</property> |
336 | + <property name="label" translatable="yes">Enabling FIPS cannot be reversed and Livepatch will be permanently disabled. Choose your preferred FIPS option.</property> |
337 | + <property name="xalign">0</property> |
338 | + </object> |
339 | + </child> |
340 | + <child> |
341 | + <object class="GtkRadioButton" id="radio_fips_with_updates"> |
342 | + <property name="visible">True</property> |
343 | + <child> |
344 | + <object class="GtkLabel"> |
345 | + <property name="visible">True</property> |
346 | + <property name="label" translatable="yes"><b>FIPS with updates</b> |
347 | +Installs FIPS 140-2 validated packages and allows for regular security updates.</property> |
348 | + <property name="use_markup">True</property> |
349 | + <property name="xalign">0</property> |
350 | + </object> |
351 | + </child> |
352 | + </object> |
353 | + </child> |
354 | + <child> |
355 | + <object class="GtkRadioButton"> |
356 | + <property name="visible">True</property> |
357 | + <property name="group">radio_fips_with_updates</property> |
358 | + <child> |
359 | + <object class="GtkLabel"> |
360 | + <property name="visible">True</property> |
361 | + <property name="label" translatable="yes"><b>FIPS without updates</b> |
362 | +Installs FIPS 140-2 validated packages. These will not be updated until the next recertification.</property> |
363 | + <property name="use_markup">True</property> |
364 | + <property name="xalign">0</property> |
365 | + </object> |
366 | + </child> |
367 | + </object> |
368 | + </child> |
369 | + </object> |
370 | + </child> |
371 | + </object> |
372 | + </child> |
373 | + <child internal-child="action_area"> |
374 | + <object class="GtkHButtonBox"> |
375 | + <property name="visible">True</property> |
376 | + <property name="layout_style">end</property> |
377 | + <child> |
378 | + <object class="GtkButton"> |
379 | + <property name="visible">True</property> |
380 | + <property name="label" translatable="yes">Cance_l</property> |
381 | + <property name="use_underline">True</property> |
382 | + <signal name="clicked" handler="on_cancel_clicked"/> |
383 | + </object> |
384 | + </child> |
385 | + <child> |
386 | + <object class="GtkButton"> |
387 | + <property name="visible">True</property> |
388 | + <property name="label" translatable="yes">_Continue</property> |
389 | + <property name="use_underline">True</property> |
390 | + <signal name="clicked" handler="on_continue_clicked"/> |
391 | + </object> |
392 | + </child> |
393 | + </object> |
394 | + </child> |
395 | + </object> |
396 | +</interface> |
397 | diff --git a/data/gtkbuilder/main.ui b/data/gtkbuilder/main.ui |
398 | index ed4abc1..9afcc22 100644 |
399 | --- a/data/gtkbuilder/main.ui |
400 | +++ b/data/gtkbuilder/main.ui |
401 | @@ -547,7 +547,18 @@ |
402 | <packing> |
403 | <property name="expand">False</property> |
404 | <property name="fill">True</property> |
405 | - <property name="position">0</property> |
406 | + </packing> |
407 | + </child> |
408 | + <child> |
409 | + <object class="GtkLabel"> |
410 | + <property name="visible">True</property> |
411 | + <property name="can_focus">False</property> |
412 | + <property name="label" translatable="yes">Snap package updates are checked routinely and installed automatically.</property> |
413 | + <property name="xalign">0</property> |
414 | + </object> |
415 | + <packing> |
416 | + <property name="expand">False</property> |
417 | + <property name="fill">False</property> |
418 | </packing> |
419 | </child> |
420 | <child> |
421 | @@ -562,6 +573,98 @@ |
422 | <property name="can_focus">False</property> |
423 | <property name="spacing">6</property> |
424 | <child> |
425 | + <object class="GtkHBox"> |
426 | + <property name="visible">True</property> |
427 | + <property name="can_focus">False</property> |
428 | + <property name="spacing">6</property> |
429 | + <child> |
430 | + <object class="GtkLabel" id="label_esm_heading"> |
431 | + <property name="visible">True</property> |
432 | + <property name="can_focus">False</property> |
433 | + <property name="xalign">1</property> |
434 | + <property name="label" translatable="yes">For other packages, this system has:</property> |
435 | + </object> |
436 | + <packing> |
437 | + <property name="expand">False</property> |
438 | + <property name="fill">False</property> |
439 | + <property name="position">0</property> |
440 | + </packing> |
441 | + </child> |
442 | + <child> |
443 | + <object class="GtkHBox"> |
444 | + <property name="visible">True</property> |
445 | + <property name="can_focus">False</property> |
446 | + <property name="spacing">6</property> |
447 | + <child> |
448 | + <object class="GtkLabel" id="label_esm_status"> |
449 | + <property name="visible">True</property> |
450 | + <property name="can_focus">False</property> |
451 | + <property name="xalign">0</property> |
452 | + </object> |
453 | + <packing> |
454 | + <property name="expand">False</property> |
455 | + <property name="fill">True</property> |
456 | + </packing> |
457 | + </child> |
458 | + <child> |
459 | + <object class="GtkLabel" id="label_esm_subscribe"> |
460 | + <property name="visible">True</property> |
461 | + <property name="can_focus">False</property> |
462 | + <property name="xalign">1</property> |
463 | + </object> |
464 | + <packing> |
465 | + <property name="expand">True</property> |
466 | + <property name="fill">True</property> |
467 | + </packing> |
468 | + </child> |
469 | + </object> |
470 | + <packing> |
471 | + <property name="expand">True</property> |
472 | + <property name="fill">True</property> |
473 | + <property name="position">1</property> |
474 | + </packing> |
475 | + </child> |
476 | + </object> |
477 | + <packing> |
478 | + <property name="expand">False</property> |
479 | + <property name="fill">False</property> |
480 | + </packing> |
481 | + </child> |
482 | + <child> |
483 | + <object class="GtkHBox"> |
484 | + <property name="visible">True</property> |
485 | + <property name="can_focus">False</property> |
486 | + <property name="spacing">6</property> |
487 | + <child> |
488 | + <object class="GtkLabel" id="label_eol_heading"> |
489 | + <property name="visible">True</property> |
490 | + <property name="can_focus">False</property> |
491 | + </object> |
492 | + <packing> |
493 | + <property name="expand">False</property> |
494 | + <property name="fill">False</property> |
495 | + <property name="position">0</property> |
496 | + </packing> |
497 | + </child> |
498 | + <child> |
499 | + <object class="GtkLabel" id="label_eol"> |
500 | + <property name="visible">True</property> |
501 | + <property name="can_focus">False</property> |
502 | + <property name="xalign">0</property> |
503 | + </object> |
504 | + <packing> |
505 | + <property name="expand">True</property> |
506 | + <property name="fill">True</property> |
507 | + <property name="position">1</property> |
508 | + </packing> |
509 | + </child> |
510 | + </object> |
511 | + <packing> |
512 | + <property name="expand">False</property> |
513 | + <property name="fill">False</property> |
514 | + </packing> |
515 | + </child> |
516 | + <child> |
517 | <object class="GtkHBox" id="hbox_check_for_updates"> |
518 | <property name="visible">True</property> |
519 | <property name="can_focus">False</property> |
520 | @@ -1087,7 +1190,7 @@ |
521 | <object class="GtkLabel" id="label_updates1"> |
522 | <property name="visible">True</property> |
523 | <property name="can_focus">False</property> |
524 | - <property name="label" translatable="yes">Proposed updates are only for testing updates and providing development feedback. Enabling this may introduce instability.</property> |
525 | + <property name="label" translatable="yes">Use proposed updates if you’re willing to report bugs on any problems that occur.</property> |
526 | <property name="use_markup">True</property> |
527 | <property name="wrap">True</property> |
528 | <property name="max-width-chars">110</property> |
529 | @@ -1116,6 +1219,426 @@ |
530 | <property name="tab_fill">False</property> |
531 | </packing> |
532 | </child> |
533 | + <child> |
534 | + <object class="GtkStack" id="stack_ua_main"> |
535 | + <property name="visible">True</property> |
536 | + <child> |
537 | + <object class="GtkBox" id="box_ua_options"> |
538 | + <property name="visible">True</property> |
539 | + <property name="border_width">12</property> |
540 | + <property name="orientation">vertical</property> |
541 | + <property name="spacing">12</property> |
542 | + <child> |
543 | + <object class="GtkLabel"> |
544 | + <property name="visible">True</property> |
545 | + <property name="label" translatable="yes"><b>Subscription</b></property> |
546 | + <property name="use_markup">True</property> |
547 | + <property name="wrap">True</property> |
548 | + <property name="max_width_chars">1</property> |
549 | + <property name="xalign">0</property> |
550 | + </object> |
551 | + </child> |
552 | + <child> |
553 | + <object class="GtkFrame"> |
554 | + <property name="visible">True</property> |
555 | + <child> |
556 | + <object class="GtkBox"> |
557 | + <property name="visible">True</property> |
558 | + <property name="spacing">36</property> |
559 | + <property name="margin">18</property> |
560 | + <child> |
561 | + <object class="GtkImage" id="image_ubuntu_pro_logo"> |
562 | + <property name="visible">True</property> |
563 | + </object> |
564 | + </child> |
565 | + <child> |
566 | + <object class="GtkStack" id="stack_ua_attach"> |
567 | + <property name="visible">True</property> |
568 | + <child> |
569 | + <object class="GtkBox" id="box_ua_unattached"> |
570 | + <property name="visible">True</property> |
571 | + <property name="spacing">24</property> |
572 | + <child> |
573 | + <object class="GtkButton" id="button_ua_attach"> |
574 | + <property name="visible">True</property> |
575 | + <property name="valign">center</property> |
576 | + <property name="label" translatable="yes">_Enable Ubuntu Pro</property> |
577 | + <property name="use_underline">True</property> |
578 | + </object> |
579 | + </child> |
580 | + <child> |
581 | + <object class="GtkLabel"> |
582 | + <property name="visible">True</property> |
583 | + <property name="label" translatable="yes"><b>This machine is not covered by an Ubuntu Pro subscription.</b> |
584 | +Receive security updates for over 25,000 Ubuntu packages, free for up to 5 machines. <a href="https://ubuntu.com/pro">Learn more</a>.</property> |
585 | + <property name="use_markup">True</property> |
586 | + <property name="wrap">True</property> |
587 | + <property name="max-width-chars">90</property> |
588 | + <property name="xalign">0</property> |
589 | + </object> |
590 | + </child> |
591 | + </object> |
592 | + </child> |
593 | + <child> |
594 | + <object class="GtkBox" id="box_ua_attached"> |
595 | + <property name="visible">True</property> |
596 | + <property name="spacing">24</property> |
597 | + <child> |
598 | + <object class="GtkButton" id="button_ua_detach"> |
599 | + <property name="visible">True</property> |
600 | + <property name="valign">center</property> |
601 | + <property name="label" translatable="yes">_Disable Ubuntu Pro</property> |
602 | + <property name="use_underline">True</property> |
603 | + </object> |
604 | + </child> |
605 | + <child> |
606 | + <object class="GtkBox"> |
607 | + <property name="visible">True</property> |
608 | + <property name="spacing">6</property> |
609 | + <child> |
610 | + <object class="GtkImage"> |
611 | + <property name="visible">True</property> |
612 | + <property name="icon-name">emblem-default</property> |
613 | + </object> |
614 | + </child> |
615 | + <child> |
616 | + <object class="GtkLabel"> |
617 | + <property name="visible">True</property> |
618 | + <property name="use_markup">True</property> |
619 | + <property name="label" translatable="yes"><span foreground="green">Ubuntu Pro support is enabled</span></property> |
620 | + <property name="xalign">0</property> |
621 | + </object> |
622 | + </child> |
623 | + </object> |
624 | + </child> |
625 | + </object> |
626 | + </child> |
627 | + </object> |
628 | + </child> |
629 | + </object> |
630 | + </child> |
631 | + </object> |
632 | + </child> |
633 | + <child> |
634 | + <object class="GtkLabel"> |
635 | + <property name="visible">True</property> |
636 | + <property name="can_focus">False</property> |
637 | + <property name="label" translatable="yes"><b>Security</b></property> |
638 | + <property name="use_markup">True</property> |
639 | + <property name="wrap">True</property> |
640 | + <property name="max_width_chars">1</property> |
641 | + <property name="xalign">0</property> |
642 | + </object> |
643 | + </child> |
644 | + <child> |
645 | + <object class="GtkGrid"> |
646 | + <property name="visible">True</property> |
647 | + <property name="row_spacing">12</property> |
648 | + <property name="column_spacing">12</property> |
649 | + <child> |
650 | + <object class="GtkSwitch" id="switch_ua_esm_infra"> |
651 | + <property name="visible">True</property> |
652 | + <property name="halign">start</property> |
653 | + <property name="valign">center</property> |
654 | + </object> |
655 | + <packing> |
656 | + <property name="left_attach">0</property> |
657 | + <property name="top_attach">0</property> |
658 | + </packing> |
659 | + </child> |
660 | + <child> |
661 | + <object class="GtkLabel" id="label_ua_esm_infra"> |
662 | + <property name="visible">True</property> |
663 | + <property name="use_markup">True</property> |
664 | + <property name="valign">center</property> |
665 | + <property name="xalign">0</property> |
666 | + </object> |
667 | + <packing> |
668 | + <property name="left_attach">1</property> |
669 | + <property name="top_attach">0</property> |
670 | + </packing> |
671 | + </child> |
672 | + <child> |
673 | + <object class="GtkLabel" id="label_ua_esm_infra_error"> |
674 | + <property name="visible">False</property> |
675 | + <property name="label" translatable="yes">Could not enable ESM Infra. Please try again.</property> |
676 | + <property name="valign">center</property> |
677 | + <property name="xalign">0</property> |
678 | + <attributes> |
679 | + <attribute name="foreground" value="red"/> |
680 | + <attribute name="scale" value="0.9"/> |
681 | + </attributes> |
682 | + </object> |
683 | + <packing> |
684 | + <property name="left_attach">1</property> |
685 | + <property name="top_attach">1</property> |
686 | + </packing> |
687 | + </child> |
688 | + <child> |
689 | + <object class="GtkSwitch" id="switch_ua_esm_apps"> |
690 | + <property name="visible">True</property> |
691 | + <property name="halign">start</property> |
692 | + <property name="valign">center</property> |
693 | + </object> |
694 | + <packing> |
695 | + <property name="left_attach">0</property> |
696 | + <property name="top_attach">2</property> |
697 | + </packing> |
698 | + </child> |
699 | + <child> |
700 | + <object class="GtkLabel" id="label_ua_esm_apps"> |
701 | + <property name="visible">True</property> |
702 | + <property name="use_markup">True</property> |
703 | + <property name="xalign">0</property> |
704 | + </object> |
705 | + <packing> |
706 | + <property name="left_attach">1</property> |
707 | + <property name="top_attach">2</property> |
708 | + </packing> |
709 | + </child> |
710 | + <child> |
711 | + <object class="GtkLabel" id="label_ua_esm_apps_error"> |
712 | + <property name="visible">False</property> |
713 | + <property name="label" translatable="yes">Could not enable ESM Apps. Please try again.</property> |
714 | + <property name="xalign">0</property> |
715 | + <attributes> |
716 | + <attribute name="foreground" value="red"/> |
717 | + <attribute name="scale" value="0.9"/> |
718 | + </attributes> |
719 | + </object> |
720 | + <packing> |
721 | + <property name="left_attach">1</property> |
722 | + <property name="top_attach">3</property> |
723 | + </packing> |
724 | + </child> |
725 | + <child> |
726 | + <object class="GtkSwitch" id="switch_ua_livepatch"> |
727 | + <property name="visible">True</property> |
728 | + <property name="halign">start</property> |
729 | + <property name="valign">center</property> |
730 | + </object> |
731 | + <packing> |
732 | + <property name="left_attach">0</property> |
733 | + <property name="top_attach">4</property> |
734 | + </packing> |
735 | + </child> |
736 | + <child> |
737 | + <object class="GtkLabel" id="label_ua_livepatch"> |
738 | + <property name="visible">True</property> |
739 | + <property name="label" translatable="yes"><b>Kernel Livepatch</b> helps keep your system secure by applying security updates that don't require a restart.</property> |
740 | + <property name="use_markup">True</property> |
741 | + <property name="xalign">0</property> |
742 | + </object> |
743 | + <packing> |
744 | + <property name="left_attach">1</property> |
745 | + <property name="top_attach">4</property> |
746 | + </packing> |
747 | + </child> |
748 | + <child> |
749 | + <object class="GtkLabel" id="label_ua_livepatch_error"> |
750 | + <property name="visible">False</property> |
751 | + <property name="label" translatable="yes">Could not enable Livepatch. Please try again.</property> |
752 | + <property name="xalign">0</property> |
753 | + <attributes> |
754 | + <attribute name="foreground" value="red"/> |
755 | + <attribute name="scale" value="0.9"/> |
756 | + </attributes> |
757 | + </object> |
758 | + <packing> |
759 | + <property name="left_attach">1</property> |
760 | + <property name="top_attach">5</property> |
761 | + </packing> |
762 | + </child> |
763 | + <child> |
764 | + <object class="GtkCheckButton" id="checkbutton_livepatch_topbar"> |
765 | + <property name="visible">True</property> |
766 | + <property name="label" translatable="yes">Show Livepatch status in the top bar</property> |
767 | + <property name="sensitive">False</property> |
768 | + <property name="halign">start</property> |
769 | + <property name="draw_indicator">True</property> |
770 | + </object> |
771 | + <packing> |
772 | + <property name="left_attach">1</property> |
773 | + <property name="top_attach">6</property> |
774 | + </packing> |
775 | + </child> |
776 | + </object> |
777 | + </child> |
778 | + <child> |
779 | + <object class="GtkFrame"> |
780 | + <property name="visible">True</property> |
781 | + <child> |
782 | + <object class="GtkExpander" id="expander_compliance_and_hardening"> |
783 | + <property name="visible">True</property> |
784 | + <property name="margin">18</property> |
785 | + <child type="label"> |
786 | + <object class="GtkBox"> |
787 | + <property name="visible">True</property> |
788 | + <property name="orientation">vertical</property> |
789 | + <property name="spacing">12</property> |
790 | + <child> |
791 | + <object class="GtkLabel"> |
792 | + <property name="visible">True</property> |
793 | + <property name="label" translatable="yes"><b>Compliance &amp; Hardening</b></property> |
794 | + <property name="use_markup">True</property> |
795 | + <property name="xalign">0</property> |
796 | + </object> |
797 | + </child> |
798 | + <child> |
799 | + <object class="GtkLabel"> |
800 | + <property name="visible">True</property> |
801 | + <property name="label" translatable="yes">Only recommended to assist with FedRAMP, HIPAA, and other compliance and hardening requirements. Includes FIPS 140-2 certified modules, DISA-STIG, CIS and Common Criteria.</property> |
802 | + <property name="wrap">True</property> |
803 | + <property name="xalign">0</property> |
804 | + <property name="max-width-chars">90</property> |
805 | + </object> |
806 | + </child> |
807 | + </object> |
808 | + </child> |
809 | + <child> |
810 | + <object class="GtkGrid"> |
811 | + <property name="visible">True</property> |
812 | + <property name="orientation">vertical</property> |
813 | + <property name="row_spacing">12</property> |
814 | + <property name="column_spacing">12</property> |
815 | + <property name="margin_top">12</property> |
816 | + <child> |
817 | + <object class="GtkButton" id="button_ua_fips"> |
818 | + <property name="visible">True</property> |
819 | + <property name="width_request">160</property> |
820 | + <child> |
821 | + <object class="GtkLabel"> |
822 | + <property name="visible">True</property> |
823 | + <property name="label" translatable="yes">Enable _FIPS</property> |
824 | + <property name="use_underline">True</property> |
825 | + </object> |
826 | + </child> |
827 | + </object> |
828 | + <packing> |
829 | + <property name="left_attach">0</property> |
830 | + <property name="top_attach">0</property> |
831 | + </packing> |
832 | + </child> |
833 | + <child> |
834 | + <object class="GtkLabel" id="label_ua_fips_status"> |
835 | + <property name="visible">True</property> |
836 | + <property name="label" translatable="yes"><b>FIPS 140-2</b></property> |
837 | + <property name="use_markup">True</property> |
838 | + <property name="xalign">0</property> |
839 | + </object> |
840 | + <packing> |
841 | + <property name="left_attach">1</property> |
842 | + <property name="top_attach">0</property> |
843 | + </packing> |
844 | + </child> |
845 | + <child> |
846 | + <object class="GtkLabel" id="label_ua_fips_description"> |
847 | + <property name="visible">True</property> |
848 | + <property name="label" translatable="yes">A US and Canada government cryptographic module certification of compliance with the FIPS 140-2 data protection standard. <a href="https://ubuntu.com/security/certifications/docs/fips">FIPS documentation</a></property> |
849 | + <property name="use_markup">True</property> |
850 | + <property name="wrap">True</property> |
851 | + <property name="xalign">0</property> |
852 | + <property name="max-width-chars">75</property> |
853 | + </object> |
854 | + <packing> |
855 | + <property name="left_attach">1</property> |
856 | + <property name="top_attach">1</property> |
857 | + </packing> |
858 | + </child> |
859 | + <child> |
860 | + <object class="GtkButton" id="button_ua_usg"> |
861 | + <property name="visible">True</property> |
862 | + <property name="width_request">160</property> |
863 | + <child> |
864 | + <object class="GtkLabel" id="label_ua_usg_button"> |
865 | + <property name="visible">True</property> |
866 | + <property name="label" translatable="yes">Enable _USG</property> |
867 | + <property name="use_underline">True</property> |
868 | + </object> |
869 | + </child> |
870 | + </object> |
871 | + <packing> |
872 | + <property name="left_attach">0</property> |
873 | + <property name="top_attach">2</property> |
874 | + </packing> |
875 | + </child> |
876 | + <child> |
877 | + <object class="GtkLabel" id="label_ua_usg_status"> |
878 | + <property name="visible">True</property> |
879 | + <property name="label" translatable="yes"><b>Ubuntu Security Guide (USG)</b></property> |
880 | + <property name="use_markup">True</property> |
881 | + <property name="xalign">0</property> |
882 | + </object> |
883 | + <packing> |
884 | + <property name="left_attach">1</property> |
885 | + <property name="top_attach">2</property> |
886 | + </packing> |
887 | + </child> |
888 | + <child> |
889 | + <object class="GtkLabel" id="label_ua_usg_description"> |
890 | + <property name="visible">True</property> |
891 | + <property name="label" translatable="yes">Automates hardening and auditing with CIS benchmark and DISA-STIG profiles while allowing for environment-specific customizations. <a href="https://ubuntu.com/security/certifications/docs/usg">USG documentation</a></property> |
892 | + <property name="use_markup">True</property> |
893 | + <property name="wrap">True</property> |
894 | + <property name="xalign">0</property> |
895 | + <property name="max-width-chars">75</property> |
896 | + </object> |
897 | + <packing> |
898 | + <property name="left_attach">1</property> |
899 | + <property name="top_attach">3</property> |
900 | + </packing> |
901 | + </child> |
902 | + </object> |
903 | + </child> |
904 | + </object> |
905 | + </child> |
906 | + </object> |
907 | + </child> |
908 | + </object> |
909 | + <packing> |
910 | + <property name="position">6</property> |
911 | + </packing> |
912 | + </child> |
913 | + <child> |
914 | + <object class="GtkBox" id="box_ua_fips_setup"> |
915 | + <property name="visible">True</property> |
916 | + <child> |
917 | + <object class="GtkBox"> |
918 | + <property name="visible">True</property> |
919 | + <property name="orientation">vertical</property> |
920 | + <property name="spacing">18</property> |
921 | + <property name="expand">True</property> |
922 | + <property name="halign">center</property> |
923 | + <property name="valign">center</property> |
924 | + <child> |
925 | + <object class="GtkSpinner"> |
926 | + <property name="visible">True</property> |
927 | + <property name="active">True</property> |
928 | + </object> |
929 | + </child> |
930 | + <child> |
931 | + <object class="GtkLabel"> |
932 | + <property name="visible">True</property> |
933 | + <property name="label" translatable="yes">Setting up FIPS</property> |
934 | + </object> |
935 | + </child> |
936 | + </object> |
937 | + </child> |
938 | + </object> |
939 | + </child> |
940 | + </object> |
941 | + </child> |
942 | + <child type="tab"> |
943 | + <object class="GtkLabel"> |
944 | + <property name="visible">True</property> |
945 | + <property name="can_focus">False</property> |
946 | + <property name="label">Ubuntu Pro</property> |
947 | + </object> |
948 | + <packing> |
949 | + <property name="position">6</property> |
950 | + <property name="tab_fill">False</property> |
951 | + </packing> |
952 | + </child> |
953 | </object> |
954 | <packing> |
955 | <property name="expand">True</property> |
956 | @@ -1177,9 +1700,14 @@ |
957 | </child> |
958 | </object> |
959 | </child> |
960 | + <child type="titlebar"> |
961 | + <placeholder/> |
962 | + </child> |
963 | </object> |
964 | <object class="GtkSizeGroup" id="sizegroup1"> |
965 | <widgets> |
966 | + <widget name="label_esm_heading"/> |
967 | + <widget name="label_eol_heading"/> |
968 | <widget name="label3"/> |
969 | <widget name="label4"/> |
970 | <widget name="label5"/> |
971 | diff --git a/data/ubuntu-pro-logo.svg b/data/ubuntu-pro-logo.svg |
972 | new file mode 100644 |
973 | index 0000000..71a4efe |
974 | --- /dev/null |
975 | +++ b/data/ubuntu-pro-logo.svg |
976 | @@ -0,0 +1,24 @@ |
977 | +<?xml version="1.0" encoding="UTF-8"?> |
978 | +<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1579.82 400"> |
979 | + <g> |
980 | + <path d="m381.87,354.01c-11.69,0-21.64-1.78-29.85-5.33-8.22-3.56-14.86-8.47-19.94-14.74-5.08-6.26-8.77-13.59-11.05-21.98-2.29-8.38-3.43-17.4-3.43-27.06v-110.77h17.28v108.49c0,9.65,1.14,18,3.43,25.03,2.29,7.03,5.46,12.83,9.53,17.4,4.06,4.57,8.97,7.96,14.74,10.16,5.76,2.2,12.2,3.3,19.31,3.3s13.55-1.1,19.31-3.3c5.76-2.2,10.67-5.59,14.74-10.16s7.24-10.37,9.53-17.4c2.29-7.03,3.43-15.37,3.43-25.03v-108.49h17.28v110.77c0,9.65-1.14,18.67-3.43,27.06-2.29,8.38-5.97,15.71-11.05,21.98-5.08,6.27-11.73,11.18-19.94,14.74-8.22,3.56-18.17,5.33-29.85,5.33Z"/> |
981 | + <path d="m500.62,226.73c2.88-2.2,7.5-4.53,13.85-6.99,6.35-2.45,13.85-3.68,22.48-3.68,9.48,0,17.91,1.7,25.28,5.08,7.37,3.39,13.59,8.13,18.67,14.23,5.08,6.1,8.93,13.34,11.56,21.72,2.62,8.38,3.94,17.57,3.94,27.57,0,10.67-1.57,20.24-4.7,28.71-3.13,8.47-7.54,15.67-13.21,21.59-5.68,5.93-12.45,10.46-20.32,13.59-7.88,3.13-16.64,4.7-26.3,4.7-11.69,0-21.34-.76-28.96-2.29-7.62-1.52-13.89-3.13-18.8-4.83v-190.04l16.51-3.05v73.68Zm0,107.98c2.54.85,6.31,1.65,11.31,2.41,4.99.76,11.56,1.14,19.69,1.14,14.23,0,25.66-4.61,34.3-13.85,8.64-9.23,12.96-22.49,12.96-39.76,0-7.28-.76-14.18-2.29-20.71-1.52-6.52-3.98-12.19-7.37-17.02-3.39-4.83-7.84-8.68-13.34-11.56-5.51-2.88-12.32-4.32-20.45-4.32-3.9,0-7.62.38-11.18,1.14-3.56.76-6.86,1.74-9.91,2.92-3.05,1.19-5.72,2.46-8,3.81-2.29,1.36-4.19,2.63-5.72,3.81v91.97Z"/> |
982 | + <path d="m726.96,345.63c-4.91,1.36-11.52,2.88-19.82,4.57-8.3,1.69-18.46,2.54-30.49,2.54-9.82,0-18.04-1.44-24.64-4.32-6.61-2.88-11.94-6.94-16.01-12.2-4.06-5.25-6.99-11.6-8.76-19.05-1.78-7.45-2.67-15.67-2.67-24.64v-73.68h16.51v68.34c0,9.32.67,17.19,2.03,23.63,1.35,6.44,3.56,11.65,6.61,15.62,3.05,3.98,6.99,6.86,11.81,8.64,4.83,1.78,10.71,2.67,17.66,2.67,7.79,0,14.56-.42,20.33-1.27,5.76-.85,9.4-1.61,10.92-2.29v-115.34h16.51v126.78Z"/> |
983 | + <path d="m763.39,223.43c4.91-1.35,11.52-2.88,19.82-4.57,8.3-1.69,18.46-2.54,30.49-2.54,9.99,0,18.33,1.44,25.03,4.32,6.69,2.88,12.02,6.99,16.01,12.32,3.98,5.33,6.81,11.73,8.51,19.18,1.69,7.46,2.54,15.67,2.54,24.64v73.42h-16.51v-68.09c0-9.31-.63-17.19-1.91-23.63-1.27-6.44-3.39-11.69-6.35-15.75-2.96-4.07-6.86-6.99-11.69-8.77-4.83-1.78-10.88-2.67-18.17-2.67-7.79,0-14.53.42-20.2,1.27-5.68.85-9.36,1.61-11.05,2.29v115.34h-16.51v-126.78Z"/> |
984 | + <path d="m916.61,218.85h52.34v13.97h-52.34v69.87c0,7.46.63,13.51,1.9,18.17,1.27,4.66,3.09,8.26,5.46,10.8,2.37,2.54,5.25,4.24,8.64,5.08,3.38.85,7.11,1.27,11.18,1.27,6.94,0,12.53-.8,16.77-2.41,4.23-1.61,7.53-3.09,9.91-4.45l4.06,13.72c-2.37,1.52-6.52,3.26-12.45,5.21-5.93,1.95-12.37,2.92-19.31,2.92-8.13,0-14.95-1.06-20.45-3.18-5.51-2.12-9.91-5.34-13.21-9.65-3.3-4.32-5.63-9.69-6.99-16.13-1.36-6.43-2.03-14.06-2.03-22.87v-120.93l16.52-3.05v41.67Z"/> |
985 | + <path d="m1094.4,345.63c-4.91,1.36-11.52,2.88-19.82,4.57-8.3,1.69-18.46,2.54-30.49,2.54-9.82,0-18.04-1.44-24.64-4.32-6.61-2.88-11.94-6.94-16.01-12.2-4.06-5.25-6.99-11.6-8.76-19.05-1.78-7.45-2.67-15.67-2.67-24.64v-73.68h16.51v68.34c0,9.32.67,17.19,2.03,23.63,1.35,6.44,3.56,11.65,6.61,15.62,3.05,3.98,6.99,6.86,11.81,8.64,4.83,1.78,10.71,2.67,17.66,2.67,7.79,0,14.56-.42,20.32-1.27,5.76-.85,9.4-1.61,10.93-2.29v-115.34h16.51v126.78Z"/> |
986 | + <path d="m1241.5,172.61c24.9,0,43.44,4.74,55.64,14.23,12.2,9.49,18.29,22.95,18.29,40.4,0,10-1.78,18.51-5.34,25.53-3.56,7.03-8.64,12.7-15.24,17.02-6.61,4.32-14.7,7.46-24.26,9.4-9.57,1.95-20.37,2.92-32.39,2.92h-23.88v68.09h-17.28v-172.76c6.1-1.69,13.25-2.92,21.47-3.68,8.21-.76,15.88-1.14,22.99-1.14Zm.76,14.99c-6.44,0-11.9.21-16.39.63-4.49.42-8.35.81-11.56,1.14v77.74h21.85c9.31,0,17.74-.55,25.28-1.65,7.54-1.1,13.97-3.13,19.31-6.1,5.34-2.96,9.44-7.07,12.32-12.32,2.88-5.25,4.32-11.94,4.32-20.07s-1.57-14.23-4.7-19.31c-3.14-5.08-7.29-9.1-12.45-12.07-5.17-2.96-11.05-5.04-17.66-6.22-6.61-1.18-13.38-1.78-20.32-1.78Z"/> |
987 | + <path d="m1385.07,216.31c5.42,0,10.54.42,15.37,1.27,4.83.85,8.17,1.7,10.04,2.54l-3.3,14.23c-1.36-.67-4.11-1.4-8.26-2.16-4.15-.76-9.62-1.14-16.39-1.14-7.12,0-12.83.51-17.15,1.52-4.32,1.02-7.16,1.87-8.51,2.54v115.09h-16.51v-125.25c4.23-1.86,10.08-3.77,17.53-5.72,7.45-1.95,16.51-2.92,27.18-2.92Z"/> |
988 | + <path d="m1538.85,284.65c0,10.33-1.48,19.73-4.45,28.2-2.96,8.47-7.11,15.67-12.45,21.6-5.34,5.93-11.65,10.54-18.93,13.85-7.29,3.3-15.33,4.95-24.14,4.95s-16.86-1.65-24.13-4.95c-7.29-3.3-13.59-7.92-18.93-13.85-5.34-5.93-9.49-13.12-12.45-21.6-2.97-8.47-4.45-17.87-4.45-28.2s1.48-19.73,4.45-28.2c2.96-8.47,7.11-15.71,12.45-21.72,5.33-6.01,11.64-10.67,18.93-13.97,7.28-3.3,15.33-4.95,24.13-4.95s16.85,1.65,24.14,4.95c7.28,3.3,13.59,7.96,18.93,13.97,5.34,6.01,9.48,13.25,12.45,21.72,2.96,8.47,4.45,17.87,4.45,28.2Zm-17.53,0c0-16.43-3.81-29.51-11.43-39.25-7.62-9.74-17.96-14.61-31-14.61s-23.37,4.87-31,14.61c-7.62,9.74-11.43,22.83-11.43,39.25s3.81,29.47,11.43,39.13c7.62,9.65,17.95,14.48,31,14.48s23.38-4.83,31-14.48,11.43-22.69,11.43-39.13Z"/> |
989 | + </g> |
990 | + <g> |
991 | + <rect fill="#e95420" x="0" y="0" width="254.06" height="400"/> |
992 | + <rect fill="#e95420" x="30.25" y="169.38" width="193.57" height="193.57"/> |
993 | + <circle fill="white" cx="58.09" cy="255.92" r="26.3"/> |
994 | + <circle fill="white" cx="167.63" cy="198.25" r="26.3"/> |
995 | + <path fill="white" d="m117.41,323.61c-18.95-4.06-34.78-16.16-43.68-33.32-7.01,3.19-14.9,4.16-22.49,2.76,10.77,26.45,33.61,45.66,61.65,51.67,6.15,1.32,12.42,1.96,18.68,1.92-4.83-6.35-7.52-14.01-7.7-21.99-2.17-.24-4.33-.59-6.45-1.05Z"/> |
996 | + <circle fill="white" cx="161.71" cy="323.76" r="26.3"/> |
997 | + <path fill="white" d="m198.31,314.1c8.18-10.31,13.94-22.5,16.71-35.45,4.84-22.59.32-46.29-12.4-65.51-3.03,7.14-8.17,13.17-14.79,17.32,7.1,13.38,9.26,28.82,6.08,43.67-1.56,7.27-4.31,14.12-8.18,20.38,6.19,5.08,10.56,11.91,12.59,19.6Z"/> |
998 | + <path fill="white" d="m56.06,218.2c.67-.04,1.34-.05,2-.05,2.66,0,5.31.28,7.94.85,4.29.92,8.32,2.54,12.01,4.84,11.84-17.03,30.95-27.25,51.65-27.63.11-1.99.38-3.97.79-5.92,1.21-5.63,3.67-10.9,7.19-15.41-33.08-2.62-65.22,14.45-81.59,43.33Z"/> |
999 | + </g> |
1000 | +</svg> |
1001 | diff --git a/debian/control b/debian/control |
1002 | index 20d0e4b..f00e135 100644 |
1003 | --- a/debian/control |
1004 | +++ b/debian/control |
1005 | @@ -31,7 +31,9 @@ Package: python3-software-properties |
1006 | Section: python |
1007 | Architecture: all |
1008 | Depends: ${python3:Depends}, ${misc:Depends}, python3, python3-apt (>= |
1009 | - 0.6.20ubuntu16), python3-pycurl, lsb-release, iso-codes |
1010 | + 0.6.20ubuntu16), python3-pycurl, lsb-release, iso-codes, python3-distro-info |
1011 | + (>= 0.14ubuntu0.3), ubuntu-advantage-tools (>=27.11~), |
1012 | + ubuntu-advantage-desktop-daemon |
1013 | Recommends: unattended-upgrades |
1014 | Description: manage the repositories that you install software from |
1015 | This software provides an abstraction of the used apt repositories. |
1016 | diff --git a/debian/software-properties-gtk.install b/debian/software-properties-gtk.install |
1017 | index 07ce9a2..cb8c737 100644 |
1018 | --- a/debian/software-properties-gtk.install |
1019 | +++ b/debian/software-properties-gtk.install |
1020 | @@ -6,4 +6,5 @@ debian/tmp/usr/share/icons |
1021 | debian/tmp/usr/share/applications/software-properties-gtk.desktop |
1022 | debian/tmp/usr/share/applications/software-properties-gnome.desktop |
1023 | debian/tmp/usr/share/applications/software-properties-drivers.desktop |
1024 | +debian/tmp/usr/share/software-properties/ubuntu-pro-logo.svg |
1025 | #debian/tmp/usr/share/gnome/help/software-properties |
1026 | diff --git a/softwareproperties/SoftwareProperties.py b/softwareproperties/SoftwareProperties.py |
1027 | index 5f4e3f3..0caa598 100644 |
1028 | --- a/softwareproperties/SoftwareProperties.py |
1029 | +++ b/softwareproperties/SoftwareProperties.py |
1030 | @@ -132,7 +132,8 @@ class SoftwareProperties(object): |
1031 | " wait for all running threads (PPA key fetchers) to exit " |
1032 | for t in threading.enumerate(): |
1033 | if t.ident != threading.current_thread().ident: |
1034 | - t.join() |
1035 | + if not t.daemon: |
1036 | + t.join() |
1037 | |
1038 | def backup_apt_conf(self): |
1039 | """Backup all apt configuration options""" |
1040 | diff --git a/softwareproperties/gtk/DialogUaAttach.py b/softwareproperties/gtk/DialogUaAttach.py |
1041 | new file mode 100644 |
1042 | index 0000000..6fcfc92 |
1043 | --- /dev/null |
1044 | +++ b/softwareproperties/gtk/DialogUaAttach.py |
1045 | @@ -0,0 +1,201 @@ |
1046 | +# |
1047 | +# Copyright (c) 2021 Canonical Ltd. |
1048 | +# |
1049 | +# This program is free software; you can redistribute it and/or |
1050 | +# modify it under the terms of the GNU General Public License as |
1051 | +# published by the Free Software Foundation; either version 2 of the |
1052 | +# License, or (at your option) any later version. |
1053 | +# |
1054 | +# This program is distributed in the hope that it will be useful, |
1055 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1056 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1057 | +# GNU General Public License for more details. |
1058 | +# |
1059 | +# You should have received a copy of the GNU General Public License |
1060 | +# along with this program; if not, write to the Free Software |
1061 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
1062 | +# USA |
1063 | + |
1064 | +import os |
1065 | +from gettext import gettext as _ |
1066 | +import gi |
1067 | +gi.require_version("Gtk", "3.0") |
1068 | +from gi.repository import Gtk,GLib,Gio |
1069 | +from softwareproperties.gtk.utils import setup_ui |
1070 | +from uaclient.api.u.pro.attach.magic.initiate.v1 import initiate |
1071 | +from uaclient.api.u.pro.attach.magic.wait.v1 import MagicAttachWaitOptions, wait |
1072 | +from uaclient.exceptions import MagicAttachTokenError |
1073 | +import threading |
1074 | + |
1075 | +class DialogUaAttach: |
1076 | + def __init__(self, parent, datadir, ua_object): |
1077 | + """setup up the gtk dialog""" |
1078 | + setup_ui(self, os.path.join(datadir, "gtkbuilder", "dialog-ua-attach.ui"), domain="software-properties") |
1079 | + |
1080 | + self.ua_object = ua_object |
1081 | + self.dialog = self.dialog_ua_attach |
1082 | + self.dialog.set_transient_for(parent) |
1083 | + |
1084 | + self.contract_token = None |
1085 | + self.attaching = False |
1086 | + self.poll = None |
1087 | + self.pin = "" |
1088 | + |
1089 | + self.net_monitor = Gio.network_monitor_get_default() |
1090 | + self.net_monitor.connect("network-changed", self.net_status_changed, 0) |
1091 | + self.net_status_changed( |
1092 | + self.net_monitor, self.net_monitor.get_network_available(), 1 |
1093 | + ) |
1094 | + |
1095 | + def run(self): |
1096 | + self.dialog.run() |
1097 | + self.dialog.hide() |
1098 | + |
1099 | + def update_state(self, case = None): |
1100 | + """ |
1101 | + fail : called by the attachment callback, and it failed. |
1102 | + success: called by the attachment callback, and it succeeded. |
1103 | + expired: called by the token polling when the token expires. |
1104 | + """ |
1105 | + if self.token_radio.get_active(): |
1106 | + self.confirm.set_sensitive(self.token_field.get_text() != "" and |
1107 | + not self.attaching) |
1108 | + icon = self.token_status_icon |
1109 | + spinner = self.token_spinner |
1110 | + status = self.token_status |
1111 | + else: |
1112 | + self.pin_label.set_text(self.pin) |
1113 | + self.confirm.set_sensitive(self.contract_token != None and |
1114 | + not self.attaching) |
1115 | + icon = self.pin_status_icon |
1116 | + spinner = self.pin_spinner |
1117 | + status = self.pin_status |
1118 | + |
1119 | + if self.attaching: |
1120 | + spinner.start() |
1121 | + else: |
1122 | + spinner.stop() |
1123 | + |
1124 | + def lock_radio_buttons(boolean): |
1125 | + self.token_radio.set_sensitive(not boolean) |
1126 | + self.magic_radio.set_sensitive(not boolean) |
1127 | + |
1128 | + lock_radio_buttons(self.attaching) |
1129 | + self.token_field.set_sensitive(not self.attaching |
1130 | + and self.token_radio.get_active()) |
1131 | + |
1132 | + # Unconditionally hide the "other radio section" icon/status. |
1133 | + # Show icon/status of the "current radio section" only if case is set. |
1134 | + self.token_status_icon.set_visible(False) |
1135 | + self.token_status.set_visible(False) |
1136 | + self.pin_status_icon.set_visible(False) |
1137 | + self.pin_status.set_visible(False) |
1138 | + if (case != None): |
1139 | + icon.set_visible(True) |
1140 | + status.set_visible(True) |
1141 | + |
1142 | + if (case == "fail"): |
1143 | + status.set_markup('<span foreground="red">%s</span>' % _('Invalid token')) |
1144 | + icon.set_from_icon_name('emblem-unreadable', 1) |
1145 | + elif (case == "success"): |
1146 | + self.finish() |
1147 | + elif (case == "pin_validated"): |
1148 | + status.set_markup('<span foreground="green">%s</span>' % _('Valid token')) |
1149 | + icon.set_from_icon_name('emblem-default', 1) |
1150 | + lock_radio_buttons(True) |
1151 | + elif (case == "expired"): |
1152 | + status.set_markup(_('Code expired')) |
1153 | + icon.set_from_icon_name('gtk-dialog-warning', 1) |
1154 | + |
1155 | + def attach(self): |
1156 | + if self.attaching: |
1157 | + return |
1158 | + |
1159 | + if self.token_radio.get_active(): |
1160 | + token = self.token_field.get_text() |
1161 | + else: |
1162 | + token = self.contract_token |
1163 | + |
1164 | + self.attaching = True |
1165 | + def on_reply(): |
1166 | + self.attaching = False |
1167 | + self.update_state("success") |
1168 | + def on_error(error): |
1169 | + self.attaching = False |
1170 | + if self.magic_radio.get_active(): |
1171 | + self.contract_token = None |
1172 | + self.update_state("fail") |
1173 | + self.ua_object.Attach(token, reply_handler=on_reply, error_handler=on_error, dbus_interface='com.canonical.UbuntuAdvantage.Manager', timeout=600) |
1174 | + self.update_state() |
1175 | + |
1176 | + def on_token_typing(self, entry): |
1177 | + self.confirm.set_sensitive(self.token_field.get_text() != '') |
1178 | + |
1179 | + def on_token_entry_activate(self, entry): |
1180 | + token = self.token_field.get_text() |
1181 | + if token != '': |
1182 | + self.attach() |
1183 | + |
1184 | + def on_confirm_clicked(self, button): |
1185 | + self.attach() |
1186 | + |
1187 | + def on_cancel_clicked(self, button): |
1188 | + self.dialog.response(Gtk.ResponseType.CANCEL) |
1189 | + |
1190 | + def poll_for_magic_token(self): |
1191 | + options = MagicAttachWaitOptions(magic_token=self.req_id) |
1192 | + try: |
1193 | + response = wait(options) |
1194 | + self.contract_token = response.contract_token |
1195 | + GLib.idle_add(self.update_state, 'pin_validated') |
1196 | + except MagicAttachTokenError: |
1197 | + GLib.idle_add(self.update_state, 'expired') |
1198 | + except Exception as e: |
1199 | + print("Error getting the Ubuntu Pro token: ", e, flush = True) |
1200 | + finally: |
1201 | + self.poll = None |
1202 | + |
1203 | + def start_magic_attach(self): |
1204 | + # Already polling, don't bother the server with a new request. |
1205 | + if self.poll != None or self.contract_token != None: |
1206 | + return |
1207 | + |
1208 | + self.contract_token = None |
1209 | + |
1210 | + # Request a magic attachment and parse relevants fields from response. |
1211 | + # userCode: The pin the user has to type in <ubuntu.com/pro/attach>; |
1212 | + # token: Identifies the request (used for polling for it). |
1213 | + try: |
1214 | + response = initiate() |
1215 | + self.pin = response.user_code |
1216 | + self.req_id = response.token |
1217 | + except Exception as e: |
1218 | + print("Error retrieving magic token: ", e) |
1219 | + return |
1220 | + self.update_state() |
1221 | + self.poll = threading.Thread(target=self.poll_for_magic_token, daemon=True) |
1222 | + self.poll.start() |
1223 | + |
1224 | + def on_radio_toggled(self, button): |
1225 | + self.update_state() |
1226 | + |
1227 | + def on_magic_radio_clicked(self, button): |
1228 | + self.start_magic_attach() |
1229 | + |
1230 | + # Do not control the radio buttons and confirm button widgets directly, |
1231 | + # since those former are controlled by update_state and this function must |
1232 | + # be logically independent of it. Control the net_control_box'es instead. |
1233 | + def net_status_changed(self, monitor, available, first_run): |
1234 | + self.no_connection.set_visible(not available) |
1235 | + self.radio_net_control_box.set_sensitive(available) |
1236 | + self.confirm_net_control_box.set_sensitive(available) |
1237 | + if available: |
1238 | + if self.pin == "": |
1239 | + self.start_magic_attach() |
1240 | + elif self.poll == None: |
1241 | + # wait() timed out without internet; Restart polling. |
1242 | + self.poll = threading.Thread(target=self.poll_for_magic_token, daemon=True) |
1243 | + self.poll.start() |
1244 | + |
1245 | + def finish(self): |
1246 | + self.dialog.response(Gtk.ResponseType.OK) |
1247 | diff --git a/softwareproperties/gtk/DialogUaDetach.py b/softwareproperties/gtk/DialogUaDetach.py |
1248 | new file mode 100644 |
1249 | index 0000000..1e247df |
1250 | --- /dev/null |
1251 | +++ b/softwareproperties/gtk/DialogUaDetach.py |
1252 | @@ -0,0 +1,71 @@ |
1253 | +# |
1254 | +# Copyright (c) 2022 Canonical Ltd. |
1255 | +# |
1256 | +# This program is free software; you can redistribute it and/or |
1257 | +# modify it under the terms of the GNU General Public License as |
1258 | +# published by the Free Software Foundation; either version 2 of the |
1259 | +# License, or (at your option) any later version. |
1260 | +# |
1261 | +# This program is distributed in the hope that it will be useful, |
1262 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1263 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1264 | +# GNU General Public License for more details. |
1265 | +# |
1266 | +# You should have received a copy of the GNU General Public License |
1267 | +# along with this program; if not, write to the Free Software |
1268 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
1269 | +# USA |
1270 | + |
1271 | +import os |
1272 | +from gettext import gettext as _ |
1273 | +import gi |
1274 | +gi.require_version("Gtk", "3.0") |
1275 | +from gi.repository import Gtk |
1276 | + |
1277 | +from softwareproperties.gtk.utils import ( |
1278 | + setup_ui, |
1279 | +) |
1280 | + |
1281 | +class DialogUaDetach: |
1282 | + def __init__(self, parent, datadir, ua_object): |
1283 | + """setup up the gtk dialog""" |
1284 | + setup_ui(self, os.path.join(datadir, "gtkbuilder", "dialog-ua-detach.ui"), domain="software-properties") |
1285 | + |
1286 | + self.ua_object = ua_object |
1287 | + self.dialog = self.dialog_ua_detach |
1288 | + self.dialog.set_transient_for(parent) |
1289 | + |
1290 | + self.detaching = False |
1291 | + |
1292 | + def run(self): |
1293 | + self.dialog.run() |
1294 | + self.dialog.hide() |
1295 | + |
1296 | + def update_state(self): |
1297 | + self.button_detach.set_sensitive(not self.detaching) |
1298 | + |
1299 | + def detach(self): |
1300 | + if self.detaching: |
1301 | + return |
1302 | + |
1303 | + self.detaching = True |
1304 | + self.label_detach_error.set_text('') |
1305 | + def on_reply(): |
1306 | + self.dialog.response(Gtk.ResponseType.OK) |
1307 | + def on_error(error): |
1308 | + # FIXME |
1309 | + print(error) |
1310 | + self.label_detach_error.set_text(_('Failed to detach. Please try again')) |
1311 | + self.detaching = False |
1312 | + self.update_state() |
1313 | + self.ua_object.Detach(reply_handler=on_reply, error_handler=on_error, dbus_interface='com.canonical.UbuntuAdvantage.Manager', timeout=600) |
1314 | + self.update_state() |
1315 | + |
1316 | + def on_token_entry_changed(self, entry): |
1317 | + self.update_state() |
1318 | + |
1319 | + def on_detach_clicked(self, button): |
1320 | + self.detach() |
1321 | + |
1322 | + def on_cancel_clicked(self, button): |
1323 | + self.dialog.response(Gtk.ResponseType.CANCEL) |
1324 | diff --git a/softwareproperties/gtk/DialogUaFipsEnable.py b/softwareproperties/gtk/DialogUaFipsEnable.py |
1325 | new file mode 100644 |
1326 | index 0000000..1ca507d |
1327 | --- /dev/null |
1328 | +++ b/softwareproperties/gtk/DialogUaFipsEnable.py |
1329 | @@ -0,0 +1,52 @@ |
1330 | +# |
1331 | +# Copyright (c) 2022 Canonical Ltd. |
1332 | +# |
1333 | +# This program is free software; you can redistribute it and/or |
1334 | +# modify it under the terms of the GNU General Public License as |
1335 | +# published by the Free Software Foundation; either version 2 of the |
1336 | +# License, or (at your option) any later version. |
1337 | +# |
1338 | +# This program is distributed in the hope that it will be useful, |
1339 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1340 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1341 | +# GNU General Public License for more details. |
1342 | +# |
1343 | +# You should have received a copy of the GNU General Public License |
1344 | +# along with this program; if not, write to the Free Software |
1345 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
1346 | +# USA |
1347 | + |
1348 | +import os |
1349 | +import gi |
1350 | +gi.require_version("Gtk", "3.0") |
1351 | +from gi.repository import Gtk |
1352 | + |
1353 | +from softwareproperties.gtk.utils import ( |
1354 | + setup_ui, |
1355 | +) |
1356 | + |
1357 | +class DialogUaFipsEnable: |
1358 | + def __init__(self, parent, datadir, ua_object): |
1359 | + """setup up the gtk dialog""" |
1360 | + setup_ui(self, os.path.join(datadir, "gtkbuilder", "dialog-ua-fips-enable.ui"), domain="software-properties") |
1361 | + |
1362 | + self.ua_object = ua_object |
1363 | + self.dialog = self.dialog_ua_fips_enable |
1364 | + self.dialog.set_transient_for(parent) |
1365 | + |
1366 | + def run(self): |
1367 | + result = self.dialog.run() |
1368 | + self.dialog.hide() |
1369 | + if result == Gtk.ResponseType.OK: |
1370 | + if self.radio_fips_with_updates.get_active(): |
1371 | + return 'fips-updates' |
1372 | + else: |
1373 | + return 'fips' |
1374 | + else: |
1375 | + return None |
1376 | + |
1377 | + def on_continue_clicked(self, button): |
1378 | + self.dialog.response(Gtk.ResponseType.OK) |
1379 | + |
1380 | + def on_cancel_clicked(self, button): |
1381 | + self.dialog.response(Gtk.ResponseType.CANCEL) |
1382 | diff --git a/softwareproperties/gtk/SoftwarePropertiesGtk.py b/softwareproperties/gtk/SoftwarePropertiesGtk.py |
1383 | index 033c6b8..6257e93 100644 |
1384 | --- a/softwareproperties/gtk/SoftwarePropertiesGtk.py |
1385 | +++ b/softwareproperties/gtk/SoftwarePropertiesGtk.py |
1386 | @@ -26,6 +26,7 @@ from __future__ import absolute_import, print_function |
1387 | |
1388 | import apt |
1389 | import apt_pkg |
1390 | +import datetime |
1391 | import dbus |
1392 | from gettext import gettext as _ |
1393 | import gettext |
1394 | @@ -36,7 +37,10 @@ from aptdaemon.errors import NotAuthorizedError, TransactionFailed |
1395 | import logging |
1396 | import threading |
1397 | import sys |
1398 | +import time |
1399 | |
1400 | +import gi |
1401 | +gi.require_version("Gdk", "3.0") |
1402 | from gi.repository import GObject, Gdk, Gtk, Gio, GLib |
1403 | |
1404 | from .SimpleGtkbuilderApp import SimpleGtkbuilderApp |
1405 | @@ -45,12 +49,20 @@ from .DialogMirror import DialogMirror |
1406 | from .DialogEdit import DialogEdit |
1407 | from .DialogCacheOutdated import DialogCacheOutdated |
1408 | from .DialogAddSourcesList import DialogAddSourcesList |
1409 | +from .UbuntuProPage import UbuntuProPage |
1410 | |
1411 | import softwareproperties |
1412 | import softwareproperties.distro |
1413 | from softwareproperties.SoftwareProperties import SoftwareProperties |
1414 | import softwareproperties.SoftwareProperties |
1415 | |
1416 | +from softwareproperties.gtk.utils import ( |
1417 | + get_ua_status, |
1418 | + get_ua_service_status, |
1419 | + current_distro, |
1420 | + is_current_distro_lts, |
1421 | +) |
1422 | + |
1423 | from UbuntuDrivers import detect |
1424 | |
1425 | if GLib.pyglib_version < (3, 9, 1): |
1426 | @@ -179,6 +191,8 @@ class SoftwarePropertiesGtk(SoftwareProperties, SimpleGtkbuilderApp): |
1427 | self.show_distro() |
1428 | # Setup and show the Additonal Drivers tab |
1429 | self.init_drivers() |
1430 | + # Setup and show the Ubuntu Pro tab |
1431 | + self.init_ubuntu_pro() |
1432 | |
1433 | # Connect to switch-page before setting initial tab. Otherwise the |
1434 | # first switch goes unnoticed. |
1435 | @@ -349,6 +363,57 @@ class SoftwarePropertiesGtk(SoftwareProperties, SimpleGtkbuilderApp): |
1436 | self.vbox_updates.add(checkbox) |
1437 | checkbox.show() |
1438 | |
1439 | + status = get_ua_status() |
1440 | + if not is_current_distro_lts(): |
1441 | + esm_available = False |
1442 | + esm_enabled = False |
1443 | + else: |
1444 | + (infra_available, infra_status) = get_ua_service_status("esm-infra", status=status) |
1445 | + (apps_available, apps_status) = get_ua_service_status("esm-apps", status=status) |
1446 | + esm_available = bool(infra_available or apps_available) |
1447 | + esm_enabled = "enabled" in (infra_status, apps_status) |
1448 | + distro = current_distro() |
1449 | + if esm_enabled: |
1450 | + eol_text = _("Extended Security Maintenance") |
1451 | + # EOL date should probably be UA contract expiry. |
1452 | + # This is probably sooner than ESM EOL for the distro and |
1453 | + # gives software properties dialogs a chance to interact about |
1454 | + # renewals if needed. |
1455 | + try: |
1456 | + # Ignore timezone to simplify formatting python < 3.7 |
1457 | + # 3.7 has datetime.fromisoformat() |
1458 | + dt, _sep, _tz = status.get("expires", "").partition("+") |
1459 | + eol_date = datetime.datetime.strptime( |
1460 | + dt, "%Y-%m-%dT%H:%M:%S" |
1461 | + ).date() |
1462 | + except ValueError: |
1463 | + print("Unable to determine UA contract expiry") |
1464 | + eol_date = distro.eol |
1465 | + else: |
1466 | + eol_text = _("Basic Security Maintenance") |
1467 | + eol_date = distro.eol |
1468 | + self.label_esm_status.set_markup(eol_text) |
1469 | + esm_url = "https://ubuntu.com/esm" # Non-EOL LTS generic ESM |
1470 | + today = datetime.datetime.now().date() |
1471 | + if today >= eol_date: |
1472 | + if esm_available: |
1473 | + # EOL LTS uses release-specific ESM ubuntu.com/XX-YY |
1474 | + distro_ver = distro.version.replace(' LTS', '') |
1475 | + esm_url = "https://ubuntu.com/%s" % distro_ver.replace(".", "-") |
1476 | + eol_expiry_text = _("Ended %s - extend or upgrade now") % eol_date.strftime("%x") |
1477 | + elif today >= eol_date - datetime.timedelta(days=60): |
1478 | + eol_expiry_text = _("Ends %s - extend or upgrade soon") % eol_date.strftime("%x") |
1479 | + else: |
1480 | + eol_expiry_text = _("Active until %s") % eol_date.strftime("%x") |
1481 | + self.label_eol.set_label(eol_expiry_text) |
1482 | + self.label_esm_subscribe.set_markup( |
1483 | + "<a href=\"%s\">%s</a>" % (esm_url, _("Extend…")) |
1484 | + ) |
1485 | + self.label_esm_subscribe.set_visible( |
1486 | + esm_available and not esm_enabled |
1487 | + ) |
1488 | + eol_expiry_text = _("Ended %s") % eol_date.strftime("%x") |
1489 | + |
1490 | # setup the server chooser |
1491 | cell = Gtk.CellRendererText() |
1492 | self.combobox_server.pack_start(cell, True) |
1493 | @@ -1009,6 +1074,7 @@ class SoftwarePropertiesGtk(SoftwareProperties, SimpleGtkbuilderApp): |
1494 | def on_delete_event(self, widget, args): |
1495 | """Close the window if requested""" |
1496 | self.on_close_button(widget) |
1497 | + return False |
1498 | |
1499 | def on_close_button(self, widget): |
1500 | """Show a dialog that a reload of the channel information is required |
1501 | @@ -1426,3 +1492,6 @@ class SoftwarePropertiesGtk(SoftwareProperties, SimpleGtkbuilderApp): |
1502 | % {'count': self.nonfree_drivers}) |
1503 | else: |
1504 | self.label_driver_action.set_label(_("No proprietary drivers are in use.")) |
1505 | + |
1506 | + def init_ubuntu_pro(self): |
1507 | + self.ubuntu_pro_page = UbuntuProPage(self) |
1508 | diff --git a/softwareproperties/gtk/UbuntuProPage.py b/softwareproperties/gtk/UbuntuProPage.py |
1509 | new file mode 100644 |
1510 | index 0000000..40f6761 |
1511 | --- /dev/null |
1512 | +++ b/softwareproperties/gtk/UbuntuProPage.py |
1513 | @@ -0,0 +1,293 @@ |
1514 | +# |
1515 | +# Copyright (c) 2021 Canonical Ltd. |
1516 | +# |
1517 | +# This program is free software; you can redistribute it and/or |
1518 | +# modify it under the terms of the GNU General Public License as |
1519 | +# published by the Free Software Foundation; either version 2 of the |
1520 | +# License, or (at your option) any later version. |
1521 | +# |
1522 | +# This program is distributed in the hope that it will be useful, |
1523 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1524 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1525 | +# GNU General Public License for more details. |
1526 | +# |
1527 | +# You should have received a copy of the GNU General Public License |
1528 | +# along with this program; if not, write to the Free Software |
1529 | +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
1530 | +# USA |
1531 | + |
1532 | +import dbus |
1533 | +import os |
1534 | +from gettext import gettext as _ |
1535 | +import gi |
1536 | +gi.require_version("Gtk", "3.0") |
1537 | +from gi.repository import GdkPixbuf, Gio, Gtk |
1538 | +from softwareproperties.gtk.utils import current_distro |
1539 | + |
1540 | +from .DialogUaAttach import DialogUaAttach |
1541 | +from .DialogUaDetach import DialogUaDetach |
1542 | +from .DialogUaFipsEnable import DialogUaFipsEnable |
1543 | + |
1544 | +class UaService: |
1545 | + def __init__(self, bus_object, name, entitled, status): |
1546 | + self.bus_object = bus_object |
1547 | + self.name = name |
1548 | + self.entitled = entitled |
1549 | + self.status = status |
1550 | + self.request_in_progress = False |
1551 | + |
1552 | +class UbuntuProPage(object): |
1553 | + |
1554 | + def __init__(self, parent): |
1555 | + self._parent = parent |
1556 | + |
1557 | + self.stack_ua_attach = parent.stack_ua_attach |
1558 | + self.box_ua_attached = parent.box_ua_attached |
1559 | + self.box_ua_unattached = parent.box_ua_unattached |
1560 | + self.stack_ua_main = parent.stack_ua_main |
1561 | + self.box_ua_options = parent.box_ua_options |
1562 | + self.box_ua_fips_setup = parent.box_ua_fips_setup |
1563 | + self.switch_ua_esm_infra = parent.switch_ua_esm_infra |
1564 | + self.label_ua_esm_infra = parent.label_ua_esm_infra |
1565 | + self.label_ua_esm_infra_error = parent.label_ua_esm_infra_error |
1566 | + self.label_ua_esm_infra_error_messages = { |
1567 | + "enable": _("Could not enable ESM Infra. Please try again."), |
1568 | + "disable": _("Could not disable ESM Infra. Please try again."), |
1569 | + } |
1570 | + self.switch_ua_esm_apps = parent.switch_ua_esm_apps |
1571 | + self.label_ua_esm_apps = parent.label_ua_esm_apps |
1572 | + self.label_ua_esm_apps_error = parent.label_ua_esm_apps_error |
1573 | + self.label_ua_esm_apps_error_messages = { |
1574 | + "enable": _("Could not enable ESM Apps. Please try again."), |
1575 | + "disable": _("Could not disable ESM Apps. Please try again."), |
1576 | + } |
1577 | + self.switch_ua_livepatch = parent.switch_ua_livepatch |
1578 | + self.checkbutton_livepatch_topbar = parent.checkbutton_livepatch_topbar |
1579 | + self.label_ua_livepatch = parent.label_ua_livepatch |
1580 | + self.label_ua_livepatch_error = parent.label_ua_livepatch_error |
1581 | + self.label_ua_livepatch_error_messages = { |
1582 | + "enable": _("Could not enable Livepatch. Please try again."), |
1583 | + "disable": _("Could not disable Livepatch. Please try again."), |
1584 | + } |
1585 | + self.button_ua_fips = parent.button_ua_fips |
1586 | + self.label_ua_fips_status = parent.label_ua_fips_status |
1587 | + self.label_ua_fips_description = parent.label_ua_fips_description |
1588 | + self.button_ua_usg = parent.button_ua_usg |
1589 | + self.label_ua_usg_button = parent.label_ua_usg_button |
1590 | + self.label_ua_usg_status = parent.label_ua_usg_status |
1591 | + self.label_ua_usg_description = parent.label_ua_usg_description |
1592 | + |
1593 | + ubuntu_pro_logo = GdkPixbuf.Pixbuf.new_from_file_at_scale(os.path.join(parent.datadir, 'ubuntu-pro-logo.svg'), -1, 50, True) |
1594 | + parent.image_ubuntu_pro_logo.set_from_pixbuf(ubuntu_pro_logo) |
1595 | + |
1596 | + parent.button_ua_attach.connect('clicked', self.on_button_ua_attach_clicked) |
1597 | + parent.button_ua_detach.connect('clicked', self.on_button_ua_detach_clicked) |
1598 | + self.on_ua_esm_infra_changed_handler = self.switch_ua_esm_infra.connect('notify::active', self.on_ua_esm_infra_changed) |
1599 | + self.on_ua_esm_apps_changed_handler = self.switch_ua_esm_apps.connect('notify::active', self.on_ua_esm_apps_changed) |
1600 | + self.on_ua_livepatch_changed_handler = self.switch_ua_livepatch.connect('notify::active', self.on_ua_livepatch_changed) |
1601 | + parent.button_ua_fips.connect('clicked', self.on_button_ua_fips_clicked) |
1602 | + parent.button_ua_usg.connect('clicked', self.on_button_ua_usg_clicked) |
1603 | + parent.expander_compliance_and_hardening.connect('notify::expanded', self.on_compliance_and_hardening_expand_changed) |
1604 | + |
1605 | + # Set date dependent labels |
1606 | + distro = current_distro() |
1607 | + if distro.eol_esm is not None: |
1608 | + eol_year = distro.eol_esm.year |
1609 | + self.label_ua_esm_infra.set_markup(_('<b>ESM Infra</b> provides security updates for over 2,300 Ubuntu Main packages until %d.') % eol_year) |
1610 | + self.label_ua_esm_apps.set_markup(_('<b>ESM Apps</b>; provides security updates for over 23,000 Ubuntu Universe packages until %d.') % eol_year) |
1611 | + else: |
1612 | + self.label_ua_esm_infra.set_markup(_('<b>ESM Infra</b> provides security updates for over 2,300 Ubuntu Main packages.')) |
1613 | + self.label_ua_esm_apps.set_markup(_('<b>ESM Apps</b>; provides security updates for over 23,000 Ubuntu Universe packages.')) |
1614 | + |
1615 | + self.update_notifier_settings = None |
1616 | + source = Gio.SettingsSchemaSource.get_default() |
1617 | + if source is not None: |
1618 | + schema = source.lookup('com.ubuntu.update-notifier', True) |
1619 | + if schema is not None: |
1620 | + settings = Gio.Settings.new('com.ubuntu.update-notifier') |
1621 | + if schema.has_key('show-livepatch-status-icon'): |
1622 | + self.update_notifier_settings = settings |
1623 | + |
1624 | + if self.update_notifier_settings is not None: |
1625 | + self.on_checkbutton_livepatch_topbar_toggled_handler = self.checkbutton_livepatch_topbar.connect('toggled', self.on_checkbutton_livepatch_topbar_toggled) |
1626 | + self.on_update_notifier_settings_changed_handler = self.update_notifier_settings.connect('changed::show-livepatch-status-icon', self.on_update_notifier_settings_changed) |
1627 | + self.on_update_notifier_settings_changed(self.update_notifier_settings, 'show-livepatch-status-icon') |
1628 | + |
1629 | + bus = dbus.SystemBus() |
1630 | + self.ua_object = bus.get_object('com.canonical.UbuntuAdvantage', '/com/canonical/UbuntuAdvantage/Manager') |
1631 | + |
1632 | + # Monitor services |
1633 | + self.attached = False |
1634 | + self.services = {} |
1635 | + def on_interfaces_added(path, interfaces_and_properties): |
1636 | + if path == '/com/canonical/UbuntuAdvantage/Manager': |
1637 | + self.attached = interfaces_and_properties['com.canonical.UbuntuAdvantage.Manager']['Attached'] |
1638 | + elif path.startswith('/com/canonical/UbuntuAdvantage/Services/'): |
1639 | + properties = interfaces_and_properties.get('com.canonical.UbuntuAdvantage.Service') |
1640 | + bus_object = bus.get_object('com.canonical.UbuntuAdvantage', path) |
1641 | + self.services[path] = UaService(bus_object, properties['Name'], properties['Entitled'], properties['Status']) |
1642 | + self.update_status() |
1643 | + def on_interfaces_removed(path, interfaces): |
1644 | + if 'com.canonical.UbuntuAdvantage.Service' in interfaces: |
1645 | + self.services.pop(path) |
1646 | + self.update_status() |
1647 | + def on_properties_changed(interface, changed_properties, invalidated_properties, path): |
1648 | + def get_property(properties, name, default): |
1649 | + value = properties.get(name) |
1650 | + if value is None: |
1651 | + value = default |
1652 | + return value |
1653 | + if path == '/com/canonical/UbuntuAdvantage/Manager' and interface == 'com.canonical.UbuntuAdvantage.Manager': |
1654 | + self.attached = get_property(changed_properties, 'Attached', self.attached) |
1655 | + elif path.startswith('/com/canonical/UbuntuAdvantage/Services/') and interface == 'com.canonical.UbuntuAdvantage.Service': |
1656 | + service = self.services[path] |
1657 | + service.entitled = get_property(changed_properties, 'Entitled', service.entitled) |
1658 | + service.status = get_property(changed_properties, 'Status', service.status) |
1659 | + self.update_status() |
1660 | + object_manager_object = bus.get_object('com.canonical.UbuntuAdvantage', '/') |
1661 | + object_manager_object.connect_to_signal('InterfacesAdded', on_interfaces_added, dbus_interface='org.freedesktop.DBus.ObjectManager') |
1662 | + object_manager_object.connect_to_signal('InterfacesRemoved', on_interfaces_removed, dbus_interface='org.freedesktop.DBus.ObjectManager') |
1663 | + bus.add_signal_receiver(on_properties_changed, bus_name='com.canonical.UbuntuAdvantage', signal_name='PropertiesChanged', dbus_interface='org.freedesktop.DBus.Properties', path_keyword='path') |
1664 | + objects = object_manager_object.GetManagedObjects(dbus_interface='org.freedesktop.DBus.ObjectManager') |
1665 | + for path in objects: |
1666 | + on_interfaces_added(path, objects[path]) |
1667 | + |
1668 | + def get_service(self, name): |
1669 | + for service in self.services.values(): |
1670 | + if service.name == name: |
1671 | + return service |
1672 | + return None |
1673 | + |
1674 | + def update_status(self): |
1675 | + if self.attached: |
1676 | + self.stack_ua_attach.set_visible_child(self.box_ua_attached) |
1677 | + else: |
1678 | + self.stack_ua_attach.set_visible_child(self.box_ua_unattached) |
1679 | + |
1680 | + def entitled_to_service(service): |
1681 | + return service is not None and service.entitled == 'yes' |
1682 | + def service_request_in_progress(service): |
1683 | + return service is not None and service.request_in_progress |
1684 | + def service_is_enabled(service): |
1685 | + return service is not None and service.status == 'enabled' |
1686 | + |
1687 | + def update_switch(switch, service, handler): |
1688 | + if service is not None and service.request_in_progress: |
1689 | + return |
1690 | + switch.handler_block(handler) |
1691 | + switch.set_active(service_is_enabled(service)) |
1692 | + switch.handler_unblock(handler) |
1693 | + |
1694 | + esm_infra_service = self.get_service('esm-infra') |
1695 | + for widget in [self.switch_ua_esm_infra, self.label_ua_esm_infra, self.label_ua_esm_infra_error]: |
1696 | + widget.set_sensitive(entitled_to_service(esm_infra_service) and not service_request_in_progress(esm_infra_service)) |
1697 | + update_switch(self.switch_ua_esm_infra, esm_infra_service, self.on_ua_esm_infra_changed_handler) |
1698 | + |
1699 | + esm_apps_service = self.get_service('esm-apps') |
1700 | + for widget in [self.switch_ua_esm_apps, self.label_ua_esm_apps, self.label_ua_esm_apps_error]: |
1701 | + widget.set_sensitive(entitled_to_service(esm_apps_service) and not service_request_in_progress(esm_apps_service)) |
1702 | + update_switch(self.switch_ua_esm_apps, esm_apps_service, self.on_ua_esm_apps_changed_handler) |
1703 | + |
1704 | + livepatch_service = self.get_service('livepatch') |
1705 | + for widget in [self.switch_ua_livepatch, self.label_ua_livepatch, self.label_ua_livepatch_error]: |
1706 | + widget.set_sensitive(entitled_to_service(livepatch_service) and not service_request_in_progress(livepatch_service)) |
1707 | + update_switch(self.switch_ua_livepatch, livepatch_service, self.on_ua_livepatch_changed_handler) |
1708 | + self.checkbutton_livepatch_topbar.set_sensitive(self.update_notifier_settings is not None and self.switch_ua_livepatch.get_active()) |
1709 | + |
1710 | + fips_service = self.get_service('fips') |
1711 | + fips_updates_service = self.get_service('fips-updates') |
1712 | + fips_in_progress = service_request_in_progress(fips_service) or service_request_in_progress(fips_updates_service) |
1713 | + self.button_ua_fips.set_sensitive(entitled_to_service(fips_service) and not fips_in_progress) |
1714 | + if fips_in_progress: |
1715 | + self.stack_ua_main.set_visible_child(self.box_ua_fips_setup) |
1716 | + else: |
1717 | + self.stack_ua_main.set_visible_child(self.box_ua_options) |
1718 | + |
1719 | + usg_service = self.get_service('usg') |
1720 | + if not service_request_in_progress(usg_service): |
1721 | + if service_is_enabled(usg_service): |
1722 | + self.label_ua_usg_button.set_label(_('Disable _USG')) |
1723 | + else: |
1724 | + self.label_ua_usg_button.set_label(_('Enable _USG')) |
1725 | + self.button_ua_usg.set_sensitive(entitled_to_service(usg_service) and not service_request_in_progress(usg_service)) |
1726 | + |
1727 | + def on_button_ua_attach_clicked(self, button): |
1728 | + dialog = DialogUaAttach(self._parent.window_main, self._parent.datadir, self.ua_object) |
1729 | + dialog.run() |
1730 | + |
1731 | + def on_button_ua_detach_clicked(self, button): |
1732 | + dialog = DialogUaDetach(self._parent.window_main, self._parent.datadir, self.ua_object) |
1733 | + dialog.run() |
1734 | + |
1735 | + def set_service_enabled(self, service_name, enabled, error_label, error_label_messages): |
1736 | + if error_label is not None: |
1737 | + error_label.set_visible(False) |
1738 | + service = self.get_service(service_name) |
1739 | + if service is None: |
1740 | + return |
1741 | + def on_reply(): |
1742 | + service.request_in_progress = False |
1743 | + self.update_status() |
1744 | + def on_error(error): |
1745 | + print(error) |
1746 | + if error_label is not None: |
1747 | + error_label.set_visible(True) |
1748 | + if enabled: |
1749 | + error_label.set_label(error_label_messages["enable"]) |
1750 | + else: |
1751 | + error_label.set_label(error_label_messages["disable"]) |
1752 | + service.request_in_progress = False |
1753 | + self.update_status() |
1754 | + if enabled: |
1755 | + service.bus_object.Enable(reply_handler=on_reply, error_handler=on_error, dbus_interface='com.canonical.UbuntuAdvantage.Service', timeout=600) |
1756 | + else: |
1757 | + service.bus_object.Disable(reply_handler=on_reply, error_handler=on_error, dbus_interface='com.canonical.UbuntuAdvantage.Service', timeout=600) |
1758 | + service.request_in_progress = True |
1759 | + self.update_status() |
1760 | + |
1761 | + def on_ua_esm_infra_changed(self, switch, param): |
1762 | + self.set_service_enabled('esm-infra', self.switch_ua_esm_infra.get_active(), self.label_ua_esm_infra_error, self.label_ua_esm_infra_error_messages) |
1763 | + |
1764 | + def on_ua_esm_apps_changed(self, switch, param): |
1765 | + self.set_service_enabled('esm-apps', self.switch_ua_esm_apps.get_active(), self.label_ua_esm_apps_error, self.label_ua_esm_apps_error_messages) |
1766 | + |
1767 | + def on_ua_livepatch_changed(self, switch, param): |
1768 | + self.set_service_enabled('livepatch', self.switch_ua_livepatch.get_active(), self.label_ua_livepatch_error, self.label_ua_livepatch_error_messages) |
1769 | + |
1770 | + def on_checkbutton_livepatch_topbar_toggled(self, button): |
1771 | + self.update_notifier_settings.handler_block(self.on_update_notifier_settings_changed_handler) |
1772 | + self.update_notifier_settings.set_boolean('show-livepatch-status-icon', self.checkbutton_livepatch_topbar.get_active()) |
1773 | + self.update_notifier_settings.handler_unblock(self.on_update_notifier_settings_changed_handler) |
1774 | + |
1775 | + def on_update_notifier_settings_changed(self, settings, key): |
1776 | + self.checkbutton_livepatch_topbar.handler_block(self.on_checkbutton_livepatch_topbar_toggled_handler) |
1777 | + self.checkbutton_livepatch_topbar.set_active(self.update_notifier_settings.get_boolean('show-livepatch-status-icon')) |
1778 | + self.checkbutton_livepatch_topbar.handler_unblock(self.on_checkbutton_livepatch_topbar_toggled_handler) |
1779 | + |
1780 | + def on_button_ua_fips_clicked(self, button): |
1781 | + dialog = DialogUaFipsEnable(self._parent.window_main, self._parent.datadir, self.ua_object) |
1782 | + service_name = dialog.run() |
1783 | + if service_name is None: |
1784 | + return |
1785 | + |
1786 | + dialog = Gtk.MessageDialog(parent=self._parent.window_main, |
1787 | + flags=Gtk.DialogFlags.MODAL, |
1788 | + type=Gtk.MessageType.QUESTION, |
1789 | + message_format=None) |
1790 | + dialog.add_button(_('No, go back'), Gtk.ResponseType.CANCEL) |
1791 | + dialog.add_button(_('Enable FIPS'), Gtk.ResponseType.OK) |
1792 | + dialog.set_markup(_('Enabling FIPS could take a few minutes. This action cannot be reversed. Are you sure you want to enable FIPS?')) |
1793 | + result = dialog.run() |
1794 | + dialog.destroy() |
1795 | + if result != Gtk.ResponseType.OK: |
1796 | + return |
1797 | + |
1798 | + self.set_service_enabled(service_name, True, None, None) |
1799 | + |
1800 | + def on_button_ua_usg_clicked(self, button): |
1801 | + service = self.get_service('usg') |
1802 | + is_enabled = service is not None and service.status == 'enabled' |
1803 | + self.set_service_enabled('usg', not is_enabled, None, None) |
1804 | + |
1805 | + def on_compliance_and_hardening_expand_changed(self, widget, param): |
1806 | + self._parent.window_main.resize(1, 1) |
1807 | diff --git a/softwareproperties/gtk/utils.py b/softwareproperties/gtk/utils.py |
1808 | index 9554fea..fd7357d 100644 |
1809 | --- a/softwareproperties/gtk/utils.py |
1810 | +++ b/softwareproperties/gtk/utils.py |
1811 | @@ -19,9 +19,17 @@ |
1812 | from __future__ import print_function |
1813 | |
1814 | from gi.repository import Gtk |
1815 | +import aptsources.distro |
1816 | +import distro_info |
1817 | +import json |
1818 | +import os |
1819 | +import subprocess |
1820 | + |
1821 | import logging |
1822 | LOG=logging.getLogger(__name__) |
1823 | |
1824 | +UA_STATUS_JSON = "/var/lib/ubuntu-advantage/status.json" |
1825 | + |
1826 | def setup_ui(self, path, domain): |
1827 | # setup ui |
1828 | self.builder = Gtk.Builder() |
1829 | @@ -34,3 +42,90 @@ def setup_ui(self, path, domain): |
1830 | setattr(self, name, o) |
1831 | else: |
1832 | logging.debug("can not get name for object '%s'" % o) |
1833 | +def is_current_distro_lts(): |
1834 | + distro = aptsources.distro.get_distro() |
1835 | + di = distro_info.UbuntuDistroInfo() |
1836 | + return di.is_lts(distro.codename) |
1837 | + |
1838 | +def current_distro(): |
1839 | + distro = aptsources.distro.get_distro() |
1840 | + di = distro_info.UbuntuDistroInfo() |
1841 | + releases = di.get_all(result="object") |
1842 | + for release in releases: |
1843 | + if release.series == distro.codename: |
1844 | + return release |
1845 | + |
1846 | + |
1847 | +def get_ua_status(): |
1848 | + """Return a dict of all UA status information or empty dict on error.""" |
1849 | + # status.json will exist on any attached system. It will also be created |
1850 | + # by the systemd timer ua-timer which will update UA_STATUS_JSON every 12 |
1851 | + # hours to reflect current status of UA subscription services. |
1852 | + # Invoking `ua status` with subp will result in a network call to |
1853 | + # contracts.canonical.com which could raise Timeouts on network limited |
1854 | + # machines. So, prefer the status.json file when possible. |
1855 | + status_json = "" |
1856 | + if os.path.exists(UA_STATUS_JSON): |
1857 | + with open(UA_STATUS_JSON) as stream: |
1858 | + status_json = stream.read() |
1859 | + else: |
1860 | + try: |
1861 | + # Success writes UA_STATUS_JSON |
1862 | + result = subprocess.run( |
1863 | + ['ua', 'status', '--format=json'], stdout=subprocess.PIPE |
1864 | + ) |
1865 | + except Exception as e: |
1866 | + print("Failed to run `ua status`:\n%s" % e) |
1867 | + return {} |
1868 | + if result.returncode != 0: |
1869 | + print( |
1870 | + "Ubuntu Advantage client returned code %d" % result.returncode |
1871 | + ) |
1872 | + return {} |
1873 | + # result.stdout is type bytes, but json.loads only accepts str in <3.6. |
1874 | + status_json = result.stdout.decode('utf-8') |
1875 | + if not status_json: |
1876 | + print( |
1877 | + "Warning: no Ubuntu Advantage status found." |
1878 | + " Is ubuntu-advantage-tools installed?" |
1879 | + ) |
1880 | + return {} |
1881 | + try: |
1882 | + status = json.loads(status_json) |
1883 | + except json.JSONDecodeError as e: |
1884 | + print("Failed to parse ubuntu advantage client JSON:\n%s" % e) |
1885 | + return {} |
1886 | + if status.get("_schema_version", "0.1") != "0.1": |
1887 | + print( |
1888 | + "UA status schema version change: %s" % status["_schema_version"] |
1889 | + ) |
1890 | + return status |
1891 | + |
1892 | + |
1893 | +def get_ua_service_status(service_name='esm-infra', status=None): |
1894 | + """Get service availability and status for a specific UA service. |
1895 | + |
1896 | + Return a tuple (available, service_status). |
1897 | + :boolean available: set True when either: |
1898 | + - attached contract is entitled to the service |
1899 | + - unattached machine reports service "availability" as "yes" |
1900 | + :str service_status: will be one of the following: |
1901 | + - "disabled" when the service is available and applicable but not |
1902 | + active |
1903 | + - "enabled" when the service is available and active |
1904 | + - "n/a" when the service is not applicable to the environment or not |
1905 | + entitled for the attached contract |
1906 | + """ |
1907 | + if not status: |
1908 | + status = get_ua_status() |
1909 | + # Assume unattached on empty status dict |
1910 | + available = False |
1911 | + service_status = "n/a" |
1912 | + for service in status.get("services", []): |
1913 | + if service.get("name") != service_name: |
1914 | + continue |
1915 | + if "available" in service: |
1916 | + available = bool("yes" == service["available"]) |
1917 | + if "status" in service: |
1918 | + service_status = service["status"] # enabled, disabled or n/a |
1919 | + return (available, service_status) |
There is still a problem to solve: Ubuntu Pro SVG logo is black: https:/ /people. canonical. com/~npt/ update- manager/ pro-logo- on-xenial. png.