Merge ~chad.smith/ubuntu/+source/ubuntu-advantage-tools:pkg-upload-24.4 into ubuntu/+source/ubuntu-advantage-tools:ubuntu/devel
- Git
- lp:~chad.smith/ubuntu/+source/ubuntu-advantage-tools
- pkg-upload-24.4
- Merge into ubuntu/devel
Status: | Needs review |
---|---|
Proposed branch: | ~chad.smith/ubuntu/+source/ubuntu-advantage-tools:pkg-upload-24.4 |
Merge into: | ubuntu/+source/ubuntu-advantage-tools:ubuntu/devel |
Diff against target: |
297 lines (+82/-35) 10 files modified
debian/changelog (+9/-0) uaclient/entitlements/cc.py (+0/-1) uaclient/entitlements/cis.py (+0/-1) uaclient/entitlements/fips.py (+14/-11) uaclient/entitlements/repo.py (+13/-1) uaclient/entitlements/tests/conftest.py (+11/-3) uaclient/entitlements/tests/test_cc.py (+1/-0) uaclient/entitlements/tests/test_cis.py (+1/-1) uaclient/entitlements/tests/test_fips.py (+32/-16) uaclient/version.py (+1/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bryce Harrington (community) | Approve | ||
Review via email: mp+390109@code.launchpad.net |
Commit message
bug-fix-only release 24.4 for upload into groovy
cherry-
- Honor additionalPackages directives as provided by the contract server machine-token
Known issues still present:
tox -p auto will still exhibit a known upstream flake issue[3]
references:
[1] https:/
<- upstream commit which was backported, some part was inapplicable to release-24 branch
[2] https:/
[3] known upstream flake issue with tox https:/
Groovy package from this branch is available adding this PPA:
sudo add-apt-repository ppa:chad.
Description of the change
Bryce Harrington (bryce) wrote : | # |
tox passes for me, modulo the known-issue (#1062) which showed for xenial and bionic:
py3: commands succeeded
flake8: commands succeeded
py3-xenial: commands succeeded
py3-bionic: commands succeeded
py3-eoan: commands succeeded
flake8-trusty: commands succeeded
ERROR: flake8-xenial: commands failed
ERROR: flake8-bionic: commands failed
flake8-eoan: commands succeeded
mypy: commands succeeded
black: commands succeeded
Chad Smith (chad.smith) wrote : | # |
> I've had a chance to study the code and think I understand it. I have a
> couple questions to clarify before approving. I also have several code
> suggestions but these are just code style so not required or expected for this
> upload, and provided just for future refactoring ideas if you wish.
>
> ### Questions ###
>
> In cc.py and cis.py the packages data member is dropped, allowing these
> classes to rely on the base class' packages() property, which provides a list
> of packages from the configuration.
Correct base class implementation should work for most repo-based subclasses. FIPS* have an unique behavior in that -hmac packages need to additionally be installed only if the corresponding base package is already installed on the system which is why there is a fips-override of that behavior (so it doesn't automatically install all packages listed in additionalPackages directive).
> fips.py does something similar but
> overrides the base packages() prop with its own, dropping the fips_packages
> dict. Two questions:
>
> a. The old code specified two packages "ubuntu-
> cisbenchmark-
> of a config file going forward? Guessing this is the "contract server"
> mentioned in bug 1173?
Correct, here is an excerpt of that "contract" and cis service itself is a beta service that isn't even supported/
]
},
...
>
> b. Is there a risk if a user already had a config file that did not have
> these values, of things breaking? Or do we 100% control the contract server
> and already have the required data in place?
>
Any connected machine will already have the /var/lib/
>
>
> ### Code Suggestions (Optional) ###
>
> 1. I notice in the test cases, test_cc.py uses "ubuntu-
> sample data, but test_cis.py uses "pkg1". Would it be more convenient to use
> "pkg1" in both cases, or alternatively use "ubuntu-
> test_cis.py
+1 we can take this to master branch.
>
> 2. repo.py's packages() prop adds logic to lookup
> "entitlement"
> then return it, or an empty list if not found. It strikes me this might be a
> situation where the code would be clearer ...
Bryce Harrington (bryce) wrote : | # |
I saw `tox -e behave` listed in README.md as an integration test, so tried running that too. I don't know if that is an applicable testsuite for acceptance testing, nor if it is currently expected to pass or not, but it failed for me:
~/pkg/UbuntuAdv
GLOB sdist-make: /home/bryce/
behave create: /home/bryce/
behave installdeps: -rrequirements.txt, -rtest-
behave inst: /home/bryce/
behave installed: appdirs=
behave run-test-pre: PYTHONHASHSEED=
behave run-test: commands[0] | behave --verbose
Loading config defaults from "./tox.ini"
Using defaults:
color True
show_snippets True
show_skipped True
dry_run False
show_source True
show_timings True
stdout_capture True
stderr_capture True
log_capture True
logging_format %(levelname)
logging_level 20
steps_catalog False
summary True
junit False
stage None
userdata {}
default_format pretty
default_tags
scenario_
more_formatters {}
Using default path "./features"
Trying base directory: /home/bryce/
Config options:
image_clean = True
destroy_instances = True
contract_token = None
reuse_image = None
Creating behave-
Starting behave-
Unexpected runlevel output:
Unexpected runlevel output:
Unexpected runlevel output:
Unexpected runlevel output:
Unexpected runlevel output:
HOOK-ERROR in before_all: Exception: System did not boot in 10s
File "/home/
self.
File "features/
create_
File "features/
launch_
File "/home/
Chad Smith (chad.smith) wrote : | # |
As mentioned in chat. behave isn't expected to pass on this branch as
.travis.yml marks that job:
allow_failures:
- python: 3.7
env: TOXENV=behave
script:
Chad Smith (chad.smith) wrote : | # |
That said, when we release version 25.0 we expect the behave targets to pass
Bryce Harrington (bryce) wrote : | # |
One other minor niggle, the indentation on the changelog entry is one space too many:
* New bug-fix-only release 24.4:
- uaclient.version bump to 24.4
- fips: honor additionalPackage directive from contract for bionic
(GH #1173)
I dedented locally for the upload but you may want to update your git tree too.
Otherwise, thanks for confirming my assumptions on the config data, so everything looks good for upload.
Bryce Harrington (bryce) wrote : | # |
$ dput ubuntu ubuntu-
Checking signature on .changes
gpg: /home/bryce/
Checking signature on .dsc
gpg: /home/bryce/
Uploading to ubuntu (via ftp to upload.ubuntu.com):
Uploading ubuntu-
Uploading ubuntu-
Uploading ubuntu-
Uploading ubuntu-
Successfully uploaded packages.
Unmerged commits
- 90f9fae... by Chad Smith
-
changelog: update 24.4 version for bug-fix-release
- 79e7bd0... by Chad Smith
-
version: update version 24.4
- 7e391ae... by Lucas Albuquerque Medeiros de Moura
-
Use additionalPackages from service payload (#1064)
Right now, ua-client is not using the additionalPackages field when enabling repo services, like cc-eal and fips. This PR adds the possibility for ua-client to start using these data when enabling repo services.
For fips, we extend packages() to understand which conditional extra packages should be installed when enabling the service.
Preview Diff
1 | diff --git a/debian/changelog b/debian/changelog |
2 | index 4be1a7a..08a2b57 100644 |
3 | --- a/debian/changelog |
4 | +++ b/debian/changelog |
5 | @@ -1,3 +1,12 @@ |
6 | +ubuntu-advantage-tools (24.4) groovy; urgency=medium |
7 | + |
8 | + * New bug-fix-only release 24.4: |
9 | + - uaclient.version bump to 24.4 |
10 | + - fips: honor additionalPackage directive from contract for bionic |
11 | + (GH #1173) |
12 | + |
13 | + -- Chad Smith <chad.smith@canonical.com> Tue, 01 Sep 2020 11:14:39 -0600 |
14 | + |
15 | ubuntu-advantage-tools (24.3) groovy; urgency=medium |
16 | |
17 | * New bug-fix-only release 24.3: |
18 | diff --git a/uaclient/entitlements/cc.py b/uaclient/entitlements/cc.py |
19 | index 961f3a2..628121b 100644 |
20 | --- a/uaclient/entitlements/cc.py |
21 | +++ b/uaclient/entitlements/cc.py |
22 | @@ -10,7 +10,6 @@ class CommonCriteriaEntitlement(repo.RepoEntitlement): |
23 | title = "CC EAL2" |
24 | description = "Common Criteria EAL2 Provisioning Packages" |
25 | repo_key_file = "ubuntu-cc-keyring.gpg" |
26 | - packages = ["ubuntu-commoncriteria"] |
27 | messaging = { |
28 | "pre_install": [ |
29 | "(This will download more than 500MB of packages, so may take some" |
30 | diff --git a/uaclient/entitlements/cis.py b/uaclient/entitlements/cis.py |
31 | index 8cddb0a..43330ce 100644 |
32 | --- a/uaclient/entitlements/cis.py |
33 | +++ b/uaclient/entitlements/cis.py |
34 | @@ -8,4 +8,3 @@ class CISEntitlement(repo.RepoEntitlement): |
35 | title = "CIS Audit" |
36 | description = "Center for Internet Security Audit Tools" |
37 | repo_key_file = "ubuntu-securitybenchmarks-keyring.gpg" |
38 | - packages = ["ubuntu-cisbenchmark-16.04"] |
39 | diff --git a/uaclient/entitlements/fips.py b/uaclient/entitlements/fips.py |
40 | index f3ad25f..8503229 100644 |
41 | --- a/uaclient/entitlements/fips.py |
42 | +++ b/uaclient/entitlements/fips.py |
43 | @@ -1,3 +1,5 @@ |
44 | +from itertools import groupby |
45 | + |
46 | from uaclient.entitlements import repo |
47 | from uaclient import apt, status, util |
48 | |
49 | @@ -12,23 +14,24 @@ class FIPSCommonEntitlement(repo.RepoEntitlement): |
50 | |
51 | repo_pin_priority = 1001 |
52 | fips_required_packages = frozenset({"fips-initramfs", "linux-fips"}) |
53 | - fips_packages = { |
54 | - "libssl1.0.0": {"libssl1.0.0-hmac"}, |
55 | - "openssh-client": {"openssh-client-hmac"}, |
56 | - "openssh-server": {"openssh-server-hmac"}, |
57 | - "openssl": set(), |
58 | - "strongswan": {"strongswan-hmac"}, |
59 | - } # type: Dict[str, Set[str]] |
60 | repo_key_file = "ubuntu-advantage-fips.gpg" # Same for fips & fips-updates |
61 | |
62 | @property |
63 | def packages(self) -> "List[str]": |
64 | - packages = list(self.fips_required_packages) |
65 | + packages = [] # type: List[str] |
66 | installed_packages = apt.get_installed_packages() |
67 | - for pkg_name, extra_pkgs in self.fips_packages.items(): |
68 | + |
69 | + pkg_groups = groupby( |
70 | + super().packages, |
71 | + key=lambda pkg_name: pkg_name.replace("-hmac", ""), |
72 | + ) |
73 | + |
74 | + for pkg_name, pkg_list in pkg_groups: |
75 | if pkg_name in installed_packages: |
76 | - packages.append(pkg_name) |
77 | - packages.extend(extra_pkgs) |
78 | + packages += pkg_list |
79 | + elif pkg_name in self.fips_required_packages: |
80 | + packages += pkg_list |
81 | + |
82 | return packages |
83 | |
84 | def application_status(self) -> "Tuple[status.ApplicationStatus, str]": |
85 | diff --git a/uaclient/entitlements/repo.py b/uaclient/entitlements/repo.py |
86 | index c288db6..b5dcc3c 100644 |
87 | --- a/uaclient/entitlements/repo.py |
88 | +++ b/uaclient/entitlements/repo.py |
89 | @@ -45,7 +45,19 @@ class RepoEntitlement(base.UAEntitlement): |
90 | @property |
91 | def packages(self) -> "List[str]": |
92 | """debs to install on enablement""" |
93 | - return [] |
94 | + packages = [] |
95 | + |
96 | + entitlement = self.cfg.entitlements.get(self.name, {}).get( |
97 | + "entitlement", {} |
98 | + ) |
99 | + |
100 | + if entitlement: |
101 | + directives = entitlement.get("directives", {}) |
102 | + additional_packages = directives.get("additionalPackages", []) |
103 | + |
104 | + packages = additional_packages |
105 | + |
106 | + return packages |
107 | |
108 | @property |
109 | @abc.abstractmethod |
110 | diff --git a/uaclient/entitlements/tests/conftest.py b/uaclient/entitlements/tests/conftest.py |
111 | index 542b591..49dc37d 100644 |
112 | --- a/uaclient/entitlements/tests/conftest.py |
113 | +++ b/uaclient/entitlements/tests/conftest.py |
114 | @@ -16,7 +16,8 @@ def machine_token( |
115 | directives: "Dict[str, Any]" = None, |
116 | entitled: bool = True, |
117 | obligations: "Dict[str, Any]" = None, |
118 | - suites: "List[str]" = None |
119 | + suites: "List[str]" = None, |
120 | + additional_packages: "List[str]" = None |
121 | ) -> "Dict[str, Any]": |
122 | return { |
123 | "resourceTokens": [ |
124 | @@ -36,6 +37,7 @@ def machine_token( |
125 | entitled=entitled, |
126 | obligations=obligations, |
127 | suites=suites, |
128 | + additional_packages=additional_packages, |
129 | ) |
130 | ] |
131 | } |
132 | @@ -50,7 +52,8 @@ def machine_access( |
133 | directives: "Dict[str, Any]" = None, |
134 | entitled: bool = True, |
135 | obligations: "Dict[str, Any]" = None, |
136 | - suites: "List[str]" = None |
137 | + suites: "List[str]" = None, |
138 | + additional_packages: "List[str]" = None |
139 | ) -> "Dict[str, Any]": |
140 | if affordances is None: |
141 | affordances = {"series": []} # Will match all series |
142 | @@ -64,6 +67,9 @@ def machine_access( |
143 | "aptKey": "APTKEY", |
144 | "suites": suites, |
145 | } |
146 | + |
147 | + if additional_packages: |
148 | + directives["additionalPackages"] = additional_packages |
149 | return { |
150 | "obligations": obligations, |
151 | "type": entitlement_type, |
152 | @@ -90,7 +96,8 @@ def entitlement_factory(tmpdir): |
153 | affordances: "Dict[str, Any]" = None, |
154 | directives: "Dict[str, Any]" = None, |
155 | entitled: bool = True, |
156 | - suites: "List[str]" = None |
157 | + suites: "List[str]" = None, |
158 | + additional_packages: "List[str]" = None |
159 | ): |
160 | cfg = config.UAConfig(cfg={"data_dir": tmpdir.strpath}) |
161 | cfg.write_cache( |
162 | @@ -101,6 +108,7 @@ def entitlement_factory(tmpdir): |
163 | directives=directives, |
164 | entitled=entitled, |
165 | suites=suites, |
166 | + additional_packages=additional_packages, |
167 | ), |
168 | ) |
169 | return cls(cfg) |
170 | diff --git a/uaclient/entitlements/tests/test_cc.py b/uaclient/entitlements/tests/test_cc.py |
171 | index d1e3419..5115339 100644 |
172 | --- a/uaclient/entitlements/tests/test_cc.py |
173 | +++ b/uaclient/entitlements/tests/test_cc.py |
174 | @@ -24,6 +24,7 @@ CC_MACHINE_TOKEN = machine_token( |
175 | "aptURL": "http://CC", |
176 | "aptKey": "APTKEY", |
177 | "suites": ["xenial"], |
178 | + "additionalPackages": ["ubuntu-commoncriteria"], |
179 | }, |
180 | affordances={ |
181 | "architectures": ["x86_64", "ppc64le", "s390x"], |
182 | diff --git a/uaclient/entitlements/tests/test_cis.py b/uaclient/entitlements/tests/test_cis.py |
183 | index 821c75d..bb2f905 100644 |
184 | --- a/uaclient/entitlements/tests/test_cis.py |
185 | +++ b/uaclient/entitlements/tests/test_cis.py |
186 | @@ -14,7 +14,7 @@ M_REPOPATH = "uaclient.entitlements.repo." |
187 | |
188 | @pytest.fixture |
189 | def entitlement(entitlement_factory): |
190 | - return entitlement_factory(CISEntitlement) |
191 | + return entitlement_factory(CISEntitlement, additional_packages=["pkg1"]) |
192 | |
193 | |
194 | class TestCISEntitlementCanEnable: |
195 | diff --git a/uaclient/entitlements/tests/test_fips.py b/uaclient/entitlements/tests/test_fips.py |
196 | index 84a533a..a74a907 100644 |
197 | --- a/uaclient/entitlements/tests/test_fips.py |
198 | +++ b/uaclient/entitlements/tests/test_fips.py |
199 | @@ -11,11 +11,7 @@ import pytest |
200 | from uaclient import apt |
201 | from uaclient import defaults |
202 | from uaclient import status, util |
203 | -from uaclient.entitlements.fips import ( |
204 | - FIPSCommonEntitlement, |
205 | - FIPSEntitlement, |
206 | - FIPSUpdatesEntitlement, |
207 | -) |
208 | +from uaclient.entitlements.fips import FIPSEntitlement, FIPSUpdatesEntitlement |
209 | from uaclient import exceptions |
210 | |
211 | |
212 | @@ -27,7 +23,25 @@ M_GETPLATFORM = M_REPOPATH + "util.get_platform_info" |
213 | @pytest.fixture(params=[FIPSEntitlement, FIPSUpdatesEntitlement]) |
214 | def fips_entitlement_factory(request, entitlement_factory): |
215 | """Parameterized fixture so we apply all tests to both FIPS and Updates""" |
216 | - return partial(entitlement_factory, request.param) |
217 | + additional_packages = [ |
218 | + "fips-initramfs", |
219 | + "libssl1.0.0", |
220 | + "libssl1.0.0-hmac", |
221 | + "linux-fips", |
222 | + "openssh-client", |
223 | + "openssh-client-hmac", |
224 | + "openssh-server", |
225 | + "openssh-server-hmac", |
226 | + "openssl", |
227 | + "strongswan", |
228 | + "strongswan-hmac", |
229 | + ] |
230 | + |
231 | + return partial( |
232 | + entitlement_factory, |
233 | + request.param, |
234 | + additional_packages=additional_packages, |
235 | + ) |
236 | |
237 | |
238 | @pytest.fixture |
239 | @@ -234,9 +248,17 @@ class TestFIPSEntitlementEnable: |
240 | |
241 | def _fips_pkg_combinations(): |
242 | """Construct all combinations of fips_packages and expected installs""" |
243 | + fips_packages = { |
244 | + "libssl1.0.0": {"libssl1.0.0-hmac"}, |
245 | + "openssh-client": {"openssh-client-hmac"}, |
246 | + "openssh-server": {"openssh-server-hmac"}, |
247 | + "openssl": set(), |
248 | + "strongswan": {"strongswan-hmac"}, |
249 | + } |
250 | + |
251 | items = [ # These are the items that we will combine together |
252 | (pkg_name, [pkg_name] + list(extra_pkgs)) |
253 | - for pkg_name, extra_pkgs in FIPSCommonEntitlement.fips_packages.items() |
254 | + for pkg_name, extra_pkgs in fips_packages.items() |
255 | ] |
256 | # This produces combinations in all possible combination lengths |
257 | combinations = itertools.chain.from_iterable( |
258 | @@ -283,7 +305,7 @@ class TestFipsEntitlementPackages: |
259 | full_expected_installs = ( |
260 | list(entitlement.fips_required_packages) + expected_installs |
261 | ) |
262 | - assert full_expected_installs == entitlement.packages |
263 | + assert sorted(full_expected_installs) == sorted(entitlement.packages) |
264 | |
265 | @mock.patch(M_PATH + "apt.get_installed_packages") |
266 | def test_multiple_packages_calls_dont_mutate_state( |
267 | @@ -292,17 +314,11 @@ class TestFipsEntitlementPackages: |
268 | # Make it appear like all packages are installed |
269 | m_get_installed_packages.return_value.__contains__.return_value = True |
270 | |
271 | - before = ( |
272 | - copy.deepcopy(entitlement.fips_required_packages), |
273 | - copy.deepcopy(entitlement.fips_packages), |
274 | - ) |
275 | + before = copy.deepcopy(entitlement.fips_required_packages) |
276 | |
277 | assert entitlement.packages |
278 | |
279 | - after = ( |
280 | - copy.deepcopy(entitlement.fips_required_packages), |
281 | - copy.deepcopy(entitlement.fips_packages), |
282 | - ) |
283 | + after = copy.deepcopy(entitlement.fips_required_packages) |
284 | |
285 | assert before == after |
286 | |
287 | diff --git a/uaclient/version.py b/uaclient/version.py |
288 | index e64f3ae..4e9b7a7 100644 |
289 | --- a/uaclient/version.py |
290 | +++ b/uaclient/version.py |
291 | @@ -8,7 +8,7 @@ import os.path |
292 | from uaclient import util |
293 | |
294 | |
295 | -__VERSION__ = "24.3" |
296 | +__VERSION__ = "24.4" |
297 | PACKAGED_VERSION = "@@PACKAGED_VERSION@@" |
298 | |
299 |
I've had a chance to study the code and think I understand it. I have a couple questions to clarify before approving. I also have several code suggestions but these are just code style so not required or expected for this upload, and provided just for future refactoring ideas if you wish.
### Questions ###
In cc.py and cis.py the packages data member is dropped, allowing these classes to rely on the base class' packages() property, which provides a list of packages from the configuration. fips.py does something similar but overrides the base packages() prop with its own, dropping the fips_packages dict. Two questions:
a. The old code specified two packages "ubuntu- commoncriteria" and "ubuntu- cisbenchmark- 16.04". My assumption is that these are going to be loaded out of a config file going forward? Guessing this is the "contract server" mentioned in bug 1173?
b. Is there a risk if a user already had a config file that did not have these values, of things breaking? Or do we 100% control the contract server and already have the required data in place?
### Code Suggestions (Optional) ###
1. I notice in the test cases, test_cc.py uses "ubuntu- commoncriteria" as its sample data, but test_cis.py uses "pkg1". Would it be more convenient to use "pkg1" in both cases, or alternatively use "ubuntu- cisbenchmark- 16.04" in test_cis.py
2. repo.py's packages() prop adds logic to lookup "entitlement" ->"directives" ->"additionalPa ckages" from the configuration and then return it, or an empty list if not found. It strikes me this might be a situation where the code would be clearer to just wrap in a try block:
try: entitlements[ self.name] ['entitlement' ]['directives' ]['additionalPa ckages' ]
return self.cfg.
except:
return []
3. The packages() prop in repo.py could use a bit more explanation in its code doc. E.g.:
def packages(self) -> "List[str]":
"""
Packages to install on enablement.
Returns the list of packages specified in the additionalPackages
directive, or an empty list if none were configured.
"""
4. fips.py's packages() prop has an interesting use of groupby (I had to look that up, wasn't familiar with it - nice). But as the logic here is a bit more sophisticated it would be worthwhile to give this packages() property its own code docs. For example, maybe something like:
@property
def packages(self) -> "List[str]":
"""
Packages to install on enablement.
Returns only packages from additionalPackages that are
either already installed or required for fips.
"""
5. Also in fips.py's packages() prop, the list assembler at the end could be shortened by combining the if statements since they have the same body:
for pkg_name, pkg_list in pkg_groups: required_ packages:
packages += pkg_list
if pkg_name in installed_packages + self.fips_