-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Include image information in Checkbox submission (New) (#1460)
This creates a new system_information collector that collects the URL if possible (namely, if ubuntu-report is installed on the machine and if the DCD string is there and valid). This safely fails in unexpected situations, reporting the error. This also stores (in the stderr of the collector) the full report non-destructively, so in any situation we can go back and re-interpret the data. This is inspired by PC Sanity provider's `get-image-url.sh` script.
- Loading branch information
Showing
4 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
#!/usr/bin/env python3 | ||
import sys | ||
import json | ||
import argparse | ||
import subprocess | ||
|
||
BASE_URL = "https://oem-share.canonical.com/partners" | ||
VERSION = 1 | ||
|
||
|
||
def parse_args(argv): | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument( | ||
"--version", | ||
"-v", | ||
help="Prints the version of the tool and exits", | ||
action="store_true", | ||
) | ||
|
||
return parser.parse_args(argv) | ||
|
||
|
||
def parse_ubuntu_report(): | ||
try: | ||
return json.loads( | ||
subprocess.check_output( | ||
["ubuntu-report", "show"], | ||
universal_newlines=True, | ||
), | ||
) | ||
except FileNotFoundError: | ||
raise SystemExit( | ||
"ubuntu-report is not installed, " | ||
"install it to collect this information" | ||
) | ||
|
||
|
||
def dcd_string_to_info(dcd_string): | ||
""" | ||
Creates a dict with all available information that can be extracted from | ||
the dcd string, at the very least: | ||
- project | ||
- series | ||
- kernel type | ||
- build date | ||
- build number | ||
- url | ||
""" | ||
# prefix, should always be present | ||
dcd_string = dcd_string.replace("canonical-", "") | ||
dcd_string = dcd_string.replace("oem-", "") | ||
dcd_string_arr = dcd_string.split("-") | ||
if len(dcd_string_arr) == 5: | ||
project, series, kernel_type, build_date, build_number = dcd_string_arr | ||
info = { | ||
"base_url": BASE_URL, | ||
"project": project, | ||
"series": series, | ||
"kernel_type": kernel_type, | ||
"build_date": build_date, | ||
"build_number": build_number, | ||
} | ||
info["url"] = ( | ||
"{base_url}/{project}/share/releases/" | ||
"{series}/{kernel_type}/{build_date}-{build_number}/" | ||
).format(**info) | ||
elif len(dcd_string_arr) == 6: | ||
( | ||
project, | ||
series, | ||
kernel_type, | ||
kernel_version, | ||
build_date, | ||
build_number, | ||
) = dcd_string_arr | ||
info = { | ||
"base_url": BASE_URL, | ||
"project": project, | ||
"series": series, | ||
"kernel_type": kernel_type, | ||
"kernel_version": kernel_version, | ||
"build_date": build_date, | ||
"build_number": build_number, | ||
} | ||
info["url"] = ( | ||
"{base_url}/{project}/share/releases/" | ||
"{series}/{kernel_type}-{kernel_version}/" | ||
"{build_date}-{build_number}/" | ||
).format(**info) | ||
elif len(dcd_string_arr) == 7: | ||
( | ||
project, | ||
series, | ||
kernel_type, | ||
kernel_version, | ||
kernel_suffix, | ||
build_date, | ||
build_number, | ||
) = dcd_string_arr | ||
info = { | ||
"base_url": BASE_URL, | ||
"project": project, | ||
"series": series, | ||
"kernel_type": kernel_type, | ||
"kernel_version": kernel_version, | ||
"kernel_suffix": kernel_suffix, | ||
"build_date": build_date, | ||
"build_number": build_number, | ||
} | ||
info["url"] = ( | ||
"{base_url}/{project}/share/releases/" | ||
"{series}/{kernel_type}-{kernel_version}-{kernel_suffix}/" | ||
"{build_date}-{build_number}/" | ||
).format(**info) | ||
else: | ||
raise SystemExit("Unknown dcd string format: {}".format(dcd_string)) | ||
return info | ||
|
||
|
||
def dcd_info(): | ||
ubuntu_report = parse_ubuntu_report() | ||
print( | ||
"Parsed report: {}".format(json.dumps(ubuntu_report)), file=sys.stderr | ||
) | ||
try: | ||
dcd_string = ubuntu_report["OEM"]["DCD"] | ||
except KeyError: | ||
raise SystemExit( | ||
"Unable to find the OEM DCD string in the parsed report" | ||
) | ||
return dcd_string_to_info(dcd_string) | ||
|
||
|
||
def main(argv=None): | ||
if argv is None: | ||
argv = sys.argv[1:] | ||
args = parse_args(argv) | ||
if args.version: | ||
print(VERSION) | ||
return | ||
info = dcd_info() | ||
json.dump(info, sys.stdout) | ||
|
||
|
||
if __name__ == "__main__": | ||
main(sys.argv[1:]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
from unittest import TestCase | ||
from unittest.mock import patch | ||
from plainbox.vendor import image_info | ||
|
||
|
||
class TestDCDStringToInfo(TestCase): | ||
def test_len_5(self): | ||
example = "canonical-oem-pinktiger-noble-hwe-20240709-33.iso" | ||
info = image_info.dcd_string_to_info(example) | ||
|
||
self.assertEqual(info["project"], "pinktiger") | ||
self.assertEqual(info["series"], "noble") | ||
|
||
def test_len_6(self): | ||
example = "canonical-oem-pinktiger-noble-oem-24.04a-20240709-33.iso" | ||
info = image_info.dcd_string_to_info(example) | ||
|
||
self.assertEqual(info["project"], "pinktiger") | ||
self.assertEqual(info["series"], "noble") | ||
|
||
def test_len_7(self): | ||
example = ( | ||
"canonical-oem-pinktiger-noble-oem-24.04a-proposed-20240709-33.iso" | ||
) | ||
info = image_info.dcd_string_to_info(example) | ||
|
||
self.assertEqual(info["project"], "pinktiger") | ||
self.assertEqual(info["series"], "noble") | ||
|
||
def test_len_wrong(self): | ||
with self.assertRaises(SystemExit): | ||
image_info.dcd_string_to_info("canonical-oem-test-stub-dcd") | ||
|
||
with self.assertRaises(SystemExit): | ||
image_info.dcd_string_to_info("") | ||
|
||
|
||
class TestDCDStringE2E(TestCase): | ||
@patch("subprocess.check_output") | ||
def test_ok_output(self, mock_check_output): | ||
mock_check_output.return_value = """{ | ||
"Version": "24.04", | ||
"OEM": { | ||
"Vendor": "Some Inc.", | ||
"Product": "13312", | ||
"Family": "NOFAMILY", | ||
"DCD": "canonical-oem-pinktiger-noble-oem-24.04a-20240823-74" | ||
}, | ||
"BIOS": { | ||
"Vendor": "Some Inc.", | ||
"Version": "0.1.20" | ||
}, | ||
"Arch": "amd64", | ||
"HwCap": "x86-64-v3", | ||
"GPU": [ | ||
{ | ||
"Vendor": "0000", | ||
"Model": "0000" | ||
} | ||
], | ||
"RAM": 16, | ||
"Partitions": [ | ||
477.7, | ||
1.1 | ||
], | ||
"Autologin": true, | ||
"LivePatch": false, | ||
"Session": { | ||
"DE": "", | ||
"Name": "", | ||
"Type": "tty" | ||
}, | ||
"Language": "en_US", | ||
"Timezone": "Etc/UTC", | ||
"Install": { | ||
"Type": "Flutter", | ||
"OEM": false, | ||
"Media": "Ubuntu OEM 24.04.1 LTS", | ||
"Stages": { | ||
"20": "loading", | ||
"218": "done" | ||
} | ||
} | ||
}""" | ||
image_info.main([]) | ||
|
||
@patch("subprocess.check_output") | ||
def test_fail_no_dcd_output(self, mock_check_output): | ||
mock_check_output.return_value = """{ | ||
"Version": "24.04", | ||
"BIOS": { | ||
"Vendor": "Some Inc.", | ||
"Version": "0.1.20" | ||
}, | ||
"Arch": "amd64", | ||
"HwCap": "x86-64-v3", | ||
"GPU": [ | ||
{ | ||
"Vendor": "0000", | ||
"Model": "0000" | ||
} | ||
], | ||
"RAM": 16, | ||
"Partitions": [ | ||
477.7, | ||
1.1 | ||
], | ||
"Autologin": true, | ||
"LivePatch": false, | ||
"Session": { | ||
"DE": "", | ||
"Name": "", | ||
"Type": "tty" | ||
}, | ||
"Language": "en_US", | ||
"Timezone": "Etc/UTC", | ||
"Install": { | ||
"Type": "Flutter", | ||
"OEM": false, | ||
"Media": "Ubuntu OEM 24.04.1 LTS", | ||
"Stages": { | ||
"20": "loading", | ||
"218": "done" | ||
} | ||
} | ||
}""" | ||
with self.assertRaises(SystemExit): | ||
image_info.main([]) |