Merge ~pieq/bugit/+git/qabro:fix-1832181-additional-info into bugit:master

Proposed by Pierre Equoy
Status: Merged
Approved by: Pierre Equoy
Approved revision: f212b3c8fc9b3050c973cac4d5ae3f5f189a93f1
Merged at revision: ee43b9e85b21ec5407f1b9f03345baff8c4e997f
Proposed branch: ~pieq/bugit/+git/qabro:fix-1832181-additional-info
Merge into: bugit:master
Diff against target: 255 lines (+115/-31)
6 files modified
qabro/__init__.py (+4/-3)
qabro/__version__.py (+1/-1)
qabro/bug_assistant.py (+34/-17)
qabro/ui.py (+1/-1)
qabro/utils.py (+67/-0)
snap/snapcraft.yaml (+8/-9)
Reviewer Review Type Date Requested Status
Jonathan Cave (community) Approve
Review via email: mp+368694@code.launchpad.net

This proposal supersedes a proposal from 2019-06-12.

Description of the change

Check related bug for more information.

Tested by building a snap and running it on:

- Desktop 18.04
- OEM Desktop 18.04
- Ubuntu Core 16

making sure:

- the manifest field is retrieved when using OEM images
- all the GPUs are shown when the device has more than one

Note: this branch includes the changes made in https://code.launchpad.net/~pieq/qabro/+git/qabro/+ref/move-to-base18

To post a comment you must log in.
Revision history for this message
Jonathan Cave (jocave) wrote :

Looks reasonable to me. If you interested in another implementation of a snapd socket class that take a look at the one in checkbox-support: https://git.launchpad.net/checkbox-support/tree/checkbox_support/snap_utils/snapd.py

review: Approve
Revision history for this message
Pierre Equoy (pieq) wrote :

Thanks joc! I'll keep an eye on your implementation that looks more robust. If I need more complex use cases in the future I may switch to using it instead.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/qabro/__init__.py b/qabro/__init__.py
2index 815374c..9c72446 100644
3--- a/qabro/__init__.py
4+++ b/qabro/__init__.py
5@@ -6,6 +6,7 @@ import sys
6
7 from qabro.bug_assistant import BugAssistant, BugReport
8 from qabro.ui import ReportScreen
9+from qabro.utils import snapdsocket
10
11
12 logger = logging.getLogger(__name__)
13@@ -20,10 +21,10 @@ def main():
14 sys.exit(("Cannot determine snap name. "
15 "Please install this tool using the snap command."))
16
17- output = subprocess.check_output(['snap', 'list', snap_name],
18- universal_newlines=True)
19+ ss = snapdsocket()
20+ qabro_snap_info = [e for e in ss.get_snaps() if e['name'] == 'qabro'][0]
21
22- if 'devmode' not in output:
23+ if not qabro_snap_info['devmode']:
24 sys.exit("This tool requires --devmode option to run properly.")
25
26 logfile = os.path.join(os.getenv('SNAP_USER_COMMON', '/tmp'), 'qabro.log')
27diff --git a/qabro/__version__.py b/qabro/__version__.py
28index 992265c..29033e1 100644
29--- a/qabro/__version__.py
30+++ b/qabro/__version__.py
31@@ -1,5 +1,5 @@
32 __title__ = 'qabro'
33-__version__ = '0.10.1'
34+__version__ = '0.11dev'
35 __description__ = 'Tool to generate a Launchpad bug report and attach useful logs (using sosreport and the like).'
36 __author__ = 'Pierre Equoy'
37 __author_email__ = 'pierre.equoy@canonical.com'
38diff --git a/qabro/bug_assistant.py b/qabro/bug_assistant.py
39index 209eb12..12f6df4 100644
40--- a/qabro/bug_assistant.py
41+++ b/qabro/bug_assistant.py
42@@ -1,8 +1,6 @@
43 import getpass
44-import json
45 import os
46 import re
47-import shutil
48 import subprocess
49 import sys
50 import tarfile
51@@ -11,6 +9,8 @@ from collections import Counter
52 from launchpadlib.launchpad import Launchpad
53 from launchpadlib.uris import LPNET_WEB_ROOT, STAGING_WEB_ROOT, QASTAGING_WEB_ROOT
54
55+from qabro.utils import snapdsocket
56+
57
58 class BugReport:
59 """Bug report.
60@@ -247,8 +247,21 @@ class AttachmentAssistant:
61 print("No $PATH defined. Cannot run sosreport!")
62
63 def attach_snaplist(self):
64- output = subprocess.check_output(['snap', 'list'])
65- self.attachments['snap_list.log'] = output
66+ print("Retrieving list of installed snaps...")
67+ sckt = snapdsocket()
68+ snaps = sckt.get_snaps()
69+ fmt = "{:<32}{:<16}{:<16}{:<16}{:<16}{:<16}"
70+ out = fmt.format("Name", "Version", "Revision",
71+ "Channel", "Devmode", "Confinement") + "\n"
72+ for snap in snaps:
73+ if snap["devmode"]:
74+ devmode = "yes"
75+ else:
76+ devmode = "no"
77+ out += fmt.format(snap["name"], snap["version"], snap["revision"],
78+ snap.get("tracking-channel", "-"), devmode,
79+ snap["confinement"]) + "\n"
80+ self.attachments["snap_list.log"] = out.encode()
81
82 def attach_last_checkbox_session(self):
83 """Archive the most recent Plainbox session available and add it to
84@@ -264,10 +277,10 @@ class AttachmentAssistant:
85 if os.path.exists(classic_path):
86 rootpath = classic_path
87 else:
88- out = subprocess.check_output(["snap", "list"]).decode('utf-8')
89- snap_name_list = [e for e in out.split() if 'checkbox' in e]
90- if snap_name_list:
91- snap_name = snap_name_list[0]
92+ ss = snapdsocket()
93+ snap_list = [e for e in ss.get_snaps() if 'checkbox' in e['name']]
94+ if snap_list:
95+ snap_name = snap_list[0]["name"]
96 sp = "/home/$USER/snap/{}/current/plainbox/sessions"
97 snap_path = os.path.expandvars(sp.format(snap_name))
98 if os.path.exists(snap_path):
99@@ -326,13 +339,16 @@ class AttachmentAssistant:
100 standard_info['Image'] = subprocess.check_output(
101 ['tail', '-n', '1', buildstamp]).decode(sys.stdout.encoding).strip()
102
103- if shutil.which("ubuntu-report"):
104- print("Retrieving Manifest information...")
105- report = subprocess.check_output(["ubuntu-report", "show"])
106- reportjson = json.loads(report)
107- manifest = reportjson.get("OEM").get("DCD")
108- if manifest:
109- standard_info["Manifest"] = manifest
110+ # This file hosts the OEM Manifest information we need
111+ # See: https://forum.snapcraft.io/t/read-access-to-a-file-in-var-lib-on-the-host/11766
112+ udc = '/var/lib/snapd/hostfs/var/lib/ubuntu_dist_channel'
113+ manifest = ''
114+ if os.path.isfile(udc):
115+ with open(udc) as f:
116+ dcd = f.read()
117+ manifest = re.search("^([^\s#]+)$", dcd, re.MULTILINE)[0]
118+ if manifest:
119+ standard_info["Manifest"] = manifest
120
121 p = os.getenv('PATH')
122
123@@ -351,11 +367,12 @@ class AttachmentAssistant:
124
125 standard_info['CPU'] = AttachmentAssistant.get_cpu_info()
126
127- lspci_output = (subprocess.check_output(['lspci'])
128+ lspci_output = (subprocess.check_output(['lspci', '-nn'])
129 .decode(sys.stdout.encoding)
130 .splitlines())
131+ # '03' is the PCI class for display controllers
132 standard_info['GPU'] = '\n'.join([line for line in lspci_output
133- if 'VGA' in line])
134+ if '[03' in line])
135
136 standard_info["kernel-version"] = (subprocess.check_output(["uname", "-r"])
137 .decode(sys.stdout.encoding)
138diff --git a/qabro/ui.py b/qabro/ui.py
139index 26f6bba..9303cc9 100644
140--- a/qabro/ui.py
141+++ b/qabro/ui.py
142@@ -56,7 +56,7 @@ class ReportScreen:
143 # Adding standard info (CPU, BIOS, GPU, etc.) to the description
144 std_info = AttachmentAssistant.get_standard_info()
145 std_info_str = '\n'.join(['{}: {}'.format(elt, std_info[elt]) for elt in std_info])
146- self.default_description += "[Additional information]\n" + std_info_str
147+ self.default_description += "[Additional information]\nSKU: \n" + std_info_str
148
149 self._title = urwid.LineBox(urwid.Edit(), 'Bug Title')
150 self._description = urwid.LineBox(urwid.Edit(edit_text=self.default_description,
151diff --git a/qabro/utils.py b/qabro/utils.py
152new file mode 100644
153index 0000000..af790eb
154--- /dev/null
155+++ b/qabro/utils.py
156@@ -0,0 +1,67 @@
157+#!/usr/bin/env python3
158+import socket, json, pprint
159+
160+class snapdsocket:
161+ def __init__(self, sock=None):
162+ if sock is None:
163+ self.sock = socket.socket(socket.AF_UNIX)
164+ else:
165+ self.sock = sock
166+ self.sock.settimeout(0.3)
167+
168+ def _connect(self):
169+ self.sock.connect("/run/snapd.socket")
170+
171+ def _send(self, msg):
172+ if type(msg) != "bytes":
173+ msg = msg.encode()
174+ self.sock.send(msg)
175+
176+ def _recv(self):
177+ chunks = []
178+ while True:
179+ try:
180+ chunk = self.sock.recv(2048)
181+ chunks.append(chunk.decode())
182+ except socket.timeout:
183+ break
184+ return ''.join(chunks)
185+
186+ def _close(self):
187+ self.sock.close()
188+
189+ def _get_json_response(self, response):
190+ begin = response.find('{')
191+ end = response.rfind('}') + 1
192+ return json.loads(response[begin:end])
193+
194+ def request(self, msg):
195+ self.__init__()
196+ self._connect()
197+ self._send(msg)
198+ raw_resp = self._recv()
199+ self._close()
200+ json_resp = self._get_json_response(raw_resp)
201+ return json_resp
202+
203+ def get_interfaces(self):
204+ req = "GET /v2/interfaces HTTP/1.1\r\nHost: localhost\r\n\r\n"
205+ json_resp = self.request(req)
206+ return json_resp['result']
207+
208+ def get_snaps(self):
209+ req = "GET /v2/snaps HTTP/1.1\r\nHost: localhost\r\n\r\n"
210+ json_resp = self.request(req)
211+ return json_resp['result']
212+
213+ def get_snap_names(self):
214+ req = "GET /v2/snaps HTTP/1.1\r\nHost: localhost\r\n\r\n"
215+ json_resp = self.request(req)
216+ snap_names = []
217+ for s in json_resp["result"]:
218+ snap_names.append(s["name"])
219+ return snap_names
220+
221+if __name__ == "__main__":
222+ sn = snapdsocket()
223+ pprint.pprint(sn.get_snaps())
224diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
225index 0a2ec6c..2c9982d 100644
226--- a/snap/snapcraft.yaml
227+++ b/snap/snapcraft.yaml
228@@ -4,6 +4,7 @@ adopt-info: qabro
229
230 grade: stable # must be 'stable' to release into candidate/stable channels
231 confinement: strict # use 'strict' once you have the right plugs and slots
232+base: core18
233
234 apps:
235 qabro:
236@@ -112,12 +113,10 @@ parts:
237 '*': patches/
238 prime: [-*]
239
240-# https://forum.snapcraft.io/t/snap-layouts/7207
241-passthrough:
242- layout:
243- /etc/sos.conf:
244- bind-file: $SNAP/etc/sos.conf
245- /var/lib/usbutils/usb.ids:
246- bind-file: $SNAP/var/lib/usbutils/usb.ids
247- /usr/share/alsa:
248- bind: $SNAP/usr/share/alsa
249+layout:
250+ /etc/sos.conf:
251+ bind-file: $SNAP/etc/sos.conf
252+ /var/lib/usbutils/usb.ids:
253+ bind-file: $SNAP/var/lib/usbutils/usb.ids
254+ /usr/share/alsa:
255+ bind: $SNAP/usr/share/alsa

Subscribers

People subscribed via source and target branches

to all changes: