Merge lp:~rodsmith/hwcert-tools/show-hw into lp:~hardware-certification/hwcert-tools/reporting-tools

Proposed by Rod Smith
Status: Merged
Approved by: Jeff Lane 
Approved revision: 157
Merged at revision: 170
Proposed branch: lp:~rodsmith/hwcert-tools/show-hw
Merge into: lp:~hardware-certification/hwcert-tools/reporting-tools
Diff against target: 183 lines (+179/-0)
1 file modified
certification_reports/show_hw.py (+179/-0)
To merge this branch: bzr merge lp:~rodsmith/hwcert-tools/show-hw
Reviewer Review Type Date Requested Status
Jeff Lane  Approve
Review via email: mp+242385@code.launchpad.net

This proposal supersedes a proposal from 2014-10-28.

Description of the change

Added new show_hw script, which pulls down dmidecode data from C3. This script is a bit hacky, but is adequate for my immediate needs. Requesting merge in case it might be useful to others in the future, either as-is or as a base for further refinement.

Resubmission: Addressed Jeff's comment.

To post a comment you must log in.
Revision history for this message
Jeff Lane  (bladernr) wrote : Posted in a previous version of this proposal

Other than one minor nitpick that really is a semantics issue, I'm fine iwth this. If you don't want to change the shebang line, that's fine too, just say so and I'll approve.

review: Needs Information
Revision history for this message
Jeff Lane  (bladernr) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'certification_reports/show_hw.py'
--- certification_reports/show_hw.py 1970-01-01 00:00:00 +0000
+++ certification_reports/show_hw.py 2014-11-20 17:04:44 +0000
@@ -0,0 +1,179 @@
1#!/usr/bin/python2
2#
3# Script to extract dmidecode data from C3. Unfortunately, security issues
4# require using both a C3 API key AND SSO credentials. The former are entered
5# on the command line and the script prompts for the latter. Results are
6# stored in a sequence of files, called dmidecode.#.{CID}.txt, where "#"
7# is the sequence number in which the dmidecode data was retrieved and
8# "{CID}" is the machine's CID number. Note that multiple dmidecode files
9# may be retrieved for some computers; I believe this depends on how many
10# were stored in C3.
11#
12# This script uses code provided to me by Daniel Manrique and written by
13# somebody else, whose name I don't recall.
14#
15# This script cannot retrieve dmidecode data by CID value, and some machines
16# which have stored data are NOT being retrieved. This is clearly a bug.
17#
18# The "maximum number of files to be retrieved" value is approximate; the
19# script may return one or two more or less than this.
20#
21# Required parameters:
22# - C3 username
23# - C3 API key (obtained from https://certification.canonical.com/me/)
24# - Maximum number of files to be retrieved (a run during development
25# produced 7759 files, so specifying at least 10000 is advisable,
26# unless you want just a few)
27#
28# By Rod Smith, 2014-10-23
29
30from api_utils import APIQuery, QueryError
31from argparse import ArgumentParser
32
33import os
34import sys
35import getpass
36import mechanize
37
38C3_URL = "https://certification.canonical.com"
39
40api = APIQuery(C3_URL)
41
42
43def get_browser():
44 """
45 Return a mechanize.Browser configured appropriately.
46 """
47 browser = mechanize.Browser()
48 browser.set_handle_robots(False)
49 return browser
50
51
52def prompt_for_credentials():
53 """
54 Return username and password collected from stdin.
55 """
56 print >> sys.stderr, "\rUbuntu SSO username (Canonical e-mail): ",
57 username = raw_input()
58 password = getpass.getpass()
59 return username, password
60
61
62def prompt_for_code():
63 """
64 Return code collected from stdin.
65 """
66 print >> sys.stderr, "\r2-factor authentication code: ",
67 return raw_input()
68
69
70def get_session_cookie(browser=get_browser()):
71 """
72 Fetch initial url, login with the supplied credentials, and return the
73 session id for the authenticated session.
74 """
75 bad_creds = False
76 bad_code = False
77
78 print >> sys.stderr, "Authenticating with Ubuntu SSO..."
79 browser.open("https://certification.canonical.com/openid/login")
80 while True:
81 # There are four possibilities
82 # 1- I'm already authenticated, so bapireak out and fetch the
83 # delicious cookie.
84 if "currently logged in " in browser.response().read():
85 break
86 # 2- I'm in an openid "Continue" page. I can tell because
87 # I have a "Continue" button.
88 browser.select_form(nr=0)
89 try:
90 browser.form.find_control(predicate=lambda c: 'value' in
91 getattr(c, 'attrs', '') and
92 c.attrs['value'] == 'Continue')
93 browser.submit()
94 except mechanize.ControlNotFoundError:
95 #3- I'm in a page asking for login/password *or* auth token.
96 try:
97 browser.form.find_control("oath_token")
98 except mechanize.ControlNotFoundError:
99 if bad_creds:
100 print >> sys.stderr, "\rBad credentials"
101 bad_creds = True
102 username, password = prompt_for_credentials()
103 browser["email"] = username
104 browser["password"] = password
105 browser.submit()
106 else:
107 if bad_code:
108 print >> sys.stderr, "\rBad code"
109 bad_code = True
110 code = prompt_for_code()
111 browser["oath_token"] = code
112 browser.submit()
113 # Get session id from cookiejar
114 cookiejar = browser._ua_handlers["_cookies"].cookiejar
115 oemshare_cookies = cookiejar._cookies["certification.canonical.com"]
116 return oemshare_cookies["/"]["sessionid"].value, browser
117
118
119def extract_cid(path):
120 head = path
121 for i in range(6):
122 head, tail = os.path.split(head)
123 return tail
124
125
126def get_dmi_data(username, api_key, max_records):
127 cookie, browser = get_session_cookie()
128 request_params = {"username": username,
129 "api_key": api_key,
130 "limit": 20,
131 "offset": 0}
132 keep_going = True
133 i = 1
134
135 while keep_going:
136 try:
137 results = api.single_query(C3_URL + '/api/v1/attachment/',
138 params=request_params)
139 except QueryError:
140 print("Failed to retrieve metadata!")
141 sys.exit(1)
142
143 for k, v in results.iteritems():
144 if k == 'meta':
145 total_count = v['total_count']
146 if k == 'objects':
147 for att in v:
148 if att['name'] == 'dmidecode_attachment':
149 try:
150 cid = extract_cid(att['url'])
151 dmidec = browser.open(C3_URL + att['url'])
152 filename = "dmidecode." + str(i) + "." + str(cid) + ".txt"
153 print("Saving to " + filename)
154 f = open(filename, "w")
155 f.write(dmidec.read())
156 f.close()
157 i = i + 1
158 except:
159 print("Could not retrieve data")
160
161 if i >= max_records or request_params['offset'] > total_count:
162 keep_going = False
163 request_params['offset'] = request_params['offset'] + request_params['limit']
164
165
166def main():
167 parser = ArgumentParser("Extract dmidecode data from C3.")
168 parser.add_argument('username',
169 help="Launchpad username used to access C3.")
170 parser.add_argument('api_key',
171 help="API key used to access C3.")
172 parser.add_argument('max_records',
173 help="Limit on number of attachments to save")
174 args = parser.parse_args()
175
176 get_dmi_data(args.username, args.api_key, int(args.max_records))
177
178if __name__ == "__main__":
179 sys.exit(main())

Subscribers

People subscribed via source and target branches