Merge ~lamoura/ubuntu/+source/ubuntu-advantage-tools:upload-27.8-jammy into ubuntu/+source/ubuntu-advantage-tools:ubuntu/devel

Proposed by Lucas Albuquerque Medeiros de Moura
Status: Merged
Merged at revision: 06882843231c960ea65fdd1fcb2d9f06fec8b071
Proposed branch: ~lamoura/ubuntu/+source/ubuntu-advantage-tools:upload-27.8-jammy
Merge into: ubuntu/+source/ubuntu-advantage-tools:ubuntu/devel
Diff against target: 3242 lines (+1504/-374)
41 files modified
debian/changelog (+21/-0)
features/_version.feature (+1/-1)
features/attach_validtoken.feature (+6/-6)
features/attached_commands.feature (+23/-18)
features/attached_enable.feature (+103/-17)
features/aws-ids.yaml (+1/-0)
features/azure-ids.yaml (+1/-0)
features/enable_fips_vm.feature (+48/-37)
features/realtime_kernel.feature (+128/-0)
features/staging_commands.feature (+1/-1)
features/ubuntu_pro.feature (+9/-9)
features/ubuntu_pro_fips.feature (+270/-9)
features/ubuntu_upgrade.feature (+1/-2)
features/unattached_status.feature (+85/-68)
help_data.yaml (+10/-0)
lib/upgrade_lts_contract.py (+25/-5)
tools/refresh-keyrings.sh (+4/-1)
tox.ini (+3/-0)
uaclient/clouds/identity.py (+2/-0)
uaclient/clouds/tests/test_identity.py (+6/-3)
uaclient/config.py (+1/-1)
uaclient/contract.py (+1/-1)
uaclient/entitlements/__init__.py (+2/-0)
uaclient/entitlements/base.py (+19/-9)
uaclient/entitlements/cis.py (+1/-1)
uaclient/entitlements/fips.py (+69/-44)
uaclient/entitlements/livepatch.py (+5/-0)
uaclient/entitlements/realtime.py (+84/-0)
uaclient/entitlements/tests/test_cc.py (+2/-0)
uaclient/entitlements/tests/test_fips.py (+60/-35)
uaclient/entitlements/tests/test_livepatch.py (+8/-0)
uaclient/entitlements/tests/test_repo.py (+17/-7)
uaclient/messages.py (+46/-0)
uaclient/status.py (+4/-4)
uaclient/tests/test_cli_attach.py (+2/-2)
uaclient/tests/test_cli_collect_logs.py (+2/-2)
uaclient/tests/test_cli_status.py (+49/-39)
uaclient/tests/test_upgrade_lts_contract.py (+67/-1)
uaclient/tests/test_util.py (+221/-27)
uaclient/util.py (+95/-23)
uaclient/version.py (+1/-1)
Reviewer Review Type Date Requested Status
Robie Basak ubuntu-sru Approve
Canonical Server Pending
Review via email: mp+419498@code.launchpad.net

Description of the change

This MR represents the release of 27.8 for Jammy.
We have already uploaded the new package into our staging PPA:
https://launchpad.net/~ua-client/+archive/ubuntu/staging/

And we have already created an SRU bug for it:
https://bugs.launchpad.net/ubuntu/+source/ubuntu-advantage-tools/+bug/1969125

Let us know if there is anything else we need to address here

To post a comment you must log in.
Revision history for this message
Robie Basak (racb) wrote :

+1 from an SRU perspective. I would like the usual QA done on this though. For a 0-day SRU, I'm not sure how this would work and have asked in #ubuntu-release. The upload can go in now though as it'll be held in Unapproved since it's seeded.

review: Approve (ubuntu-sru)
Revision history for this message
Sergio Durigan Junior (sergiodj) :
Revision history for this message
Chad Smith (chad.smith) wrote :

LGTM. Versioning looks good as previous upload to -proposed was rejected.

Revision history for this message
Sergio Durigan Junior (sergiodj) wrote :

Uploaded:

$ dput ubuntu-advantage-tools_27.8~22.04.1_source.changes
Trying to upload package to ubuntu
Checking signature on .changes
gpg: /home/sergio/work/ubuntu-advantage-tools/ubuntu-advantage-tools_27.8~22.04.1_source.changes: Valid signature from 106DA1C8C3CBBF14
Checking signature on .dsc
gpg: /home/sergio/work/ubuntu-advantage-tools/ubuntu-advantage-tools_27.8~22.04.1.dsc: Valid signature from 106DA1C8C3CBBF14
Uploading to ubuntu (via ftp to upload.ubuntu.com):
  Uploading ubuntu-advantage-tools_27.8~22.04.1.dsc: done.
  Uploading ubuntu-advantage-tools_27.8~22.04.1.tar.xz: done.
  Uploading ubuntu-advantage-tools_27.8~22.04.1_source.buildinfo: done.
  Uploading ubuntu-advantage-tools_27.8~22.04.1_source.changes: done.
Successfully uploaded packages.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/debian/changelog b/debian/changelog
index b44d4d9..a272000 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,24 @@
1ubuntu-advantage-tools (27.8~22.04.1) jammy; urgency=medium
2
3 * New upstream release 27.8 (LP: #1969125)
4 - entitlements: apply overrides from the contract response
5 - fips:
6 + unhold fips packages when enabling fips-updates
7 + Automatically disable fips service before enabling fips-updates
8 + unhold more packages when enabling fips
9 - lib: fix upgrade script for unsupported releases (LP: #1968067)
10 - realtime: add support for realtime kernel beta service on Jammy
11
12 -- Lucas Moura <lucas.moura@canonical.com> Wed, 13 Apr 2022 18:17:02 -0300
13
14ubuntu-advantage-tools (27.7.1~22.04.1) jammy; urgency=medium
15
16 * fips:
17 - make fips service incompatible with fips-updates
18 - unhold more packages when enabling fips
19
20 -- Lucas Moura <lucas.moura@canonical.com> Thu, 31 Mar 2022 16:18:36 -0300
21
1ubuntu-advantage-tools (27.7~22.04.1) jammy; urgency=medium22ubuntu-advantage-tools (27.7~22.04.1) jammy; urgency=medium
223
3 * d/changelog:24 * d/changelog:
diff --git a/features/_version.feature b/features/_version.feature
index b972500..35b73f7 100644
--- a/features/_version.feature
+++ b/features/_version.feature
@@ -15,7 +15,7 @@ Feature: UA is expected version
15 Scenario Outline: Check ua version15 Scenario Outline: Check ua version
16 Given a `<release>` machine with ubuntu-advantage-tools installed16 Given a `<release>` machine with ubuntu-advantage-tools installed
17 When I run `dpkg-query --showformat='${Version}' --show ubuntu-advantage-tools` with sudo17 When I run `dpkg-query --showformat='${Version}' --show ubuntu-advantage-tools` with sudo
18 Then stdout matches regexp:18 Then I will see the following on stdout
19 """19 """
20 {UACLIENT_BEHAVE_CHECK_VERSION}20 {UACLIENT_BEHAVE_CHECK_VERSION}
21 """21 """
diff --git a/features/attach_validtoken.feature b/features/attach_validtoken.feature
index 25f763b..35fd90f 100644
--- a/features/attach_validtoken.feature
+++ b/features/attach_validtoken.feature
@@ -11,7 +11,7 @@ Feature: Command behaviour when attaching a machine to an Ubuntu Advantage
11 And I run `ua status --all` as non-root11 And I run `ua status --all` as non-root
12 Then stdout matches regexp:12 Then stdout matches regexp:
13 """13 """
14 SERVICE ENTITLED STATUS DESCRIPTION14 SERVICE +ENTITLED STATUS DESCRIPTION
15 cc-eal +yes +n/a +Common Criteria EAL2 Provisioning Packages15 cc-eal +yes +n/a +Common Criteria EAL2 Provisioning Packages
16 cis +yes +n/a +Security compliance and audit tools16 cis +yes +n/a +Security compliance and audit tools
17 esm-apps +yes +n/a +UA Apps: Extended Security Maintenance \(ESM\)17 esm-apps +yes +n/a +UA Apps: Extended Security Maintenance \(ESM\)
@@ -58,7 +58,7 @@ Feature: Command behaviour when attaching a machine to an Ubuntu Advantage
58 """58 """
59 And stdout matches regexp:59 And stdout matches regexp:
60 """60 """
61 SERVICE ENTITLED STATUS DESCRIPTION61 SERVICE +ENTITLED STATUS DESCRIPTION
62 cc-eal +yes +<cc_status> +Common Criteria EAL2 Provisioning Packages62 cc-eal +yes +<cc_status> +Common Criteria EAL2 Provisioning Packages
63 """63 """
64 And stdout matches regexp:64 And stdout matches regexp:
@@ -315,7 +315,7 @@ Feature: Command behaviour when attaching a machine to an Ubuntu Advantage
315 """315 """
316 And stdout matches regexp:316 And stdout matches regexp:
317 """317 """
318 SERVICE ENTITLED STATUS DESCRIPTION318 SERVICE +ENTITLED STATUS DESCRIPTION
319 cc-eal +yes +<cc_status> +Common Criteria EAL2 Provisioning Packages319 cc-eal +yes +<cc_status> +Common Criteria EAL2 Provisioning Packages
320 """320 """
321 And stdout matches regexp:321 And stdout matches regexp:
@@ -375,7 +375,7 @@ Feature: Command behaviour when attaching a machine to an Ubuntu Advantage
375 """375 """
376 And stdout matches regexp:376 And stdout matches regexp:
377 """377 """
378 SERVICE ENTITLED STATUS DESCRIPTION378 SERVICE +ENTITLED STATUS DESCRIPTION
379 cc-eal +yes +<cc_status> +Common Criteria EAL2 Provisioning Packages379 cc-eal +yes +<cc_status> +Common Criteria EAL2 Provisioning Packages
380 """380 """
381 And stdout matches regexp:381 And stdout matches regexp:
@@ -435,7 +435,7 @@ Feature: Command behaviour when attaching a machine to an Ubuntu Advantage
435 """435 """
436 And stdout matches regexp:436 And stdout matches regexp:
437 """437 """
438 SERVICE ENTITLED STATUS DESCRIPTION438 SERVICE +ENTITLED STATUS DESCRIPTION
439 cc-eal +yes +<cc_status> +Common Criteria EAL2 Provisioning Packages439 cc-eal +yes +<cc_status> +Common Criteria EAL2 Provisioning Packages
440 """440 """
441 And stdout matches regexp:441 And stdout matches regexp:
@@ -477,7 +477,7 @@ Feature: Command behaviour when attaching a machine to an Ubuntu Advantage
477 When I run `ua status` with sudo477 When I run `ua status` with sudo
478 Then stdout matches regexp:478 Then stdout matches regexp:
479 """479 """
480 SERVICE ENTITLED STATUS DESCRIPTION480 SERVICE +ENTITLED STATUS DESCRIPTION
481 cc-eal +yes +<cc-eal> +Common Criteria EAL2 Provisioning Packages481 cc-eal +yes +<cc-eal> +Common Criteria EAL2 Provisioning Packages
482 """482 """
483 And stdout matches regexp:483 And stdout matches regexp:
diff --git a/features/attached_commands.feature b/features/attached_commands.feature
index dd6cf1a..f3ed252 100644
--- a/features/attached_commands.feature
+++ b/features/attached_commands.feature
@@ -129,9 +129,9 @@ Feature: Command behaviour when attached to an UA subscription
129129
130 Examples: ubuntu release130 Examples: ubuntu release
131 | release | valid_services |131 | release | valid_services |
132 | xenial | cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch, ros,\nros-updates. |132 | xenial | cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch,\nrealtime-kernel, ros, ros-updates. |
133 | bionic | cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch, ros,\nros-updates. |133 | bionic | cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch,\nrealtime-kernel, ros, ros-updates. |
134 | focal | cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, ros,\nros-updates, usg. |134 | focal | cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, realtime-kernel,\nros, ros-updates, usg. |
135135
136 @series.xenial136 @series.xenial
137 @series.bionic137 @series.bionic
@@ -148,8 +148,8 @@ Feature: Command behaviour when attached to an UA subscription
148 And stderr matches regexp:148 And stderr matches regexp:
149 """149 """
150 Cannot disable unknown service 'foobar'.150 Cannot disable unknown service 'foobar'.
151 Try cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch, ros,151 Try cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch,
152 ros-updates.152 realtime-kernel, ros, ros-updates.
153 """153 """
154 And I verify that running `ua disable esm-infra` `as non-root` exits `1`154 And I verify that running `ua disable esm-infra` `as non-root` exits `1`
155 And stderr matches regexp:155 And stderr matches regexp:
@@ -187,8 +187,8 @@ Feature: Command behaviour when attached to an UA subscription
187 And stderr matches regexp:187 And stderr matches regexp:
188 """188 """
189 Cannot disable unknown service 'foobar'.189 Cannot disable unknown service 'foobar'.
190 Try cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, ros,190 Try cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, realtime-kernel,
191 ros-updates, usg.191 ros, ros-updates, usg.
192 """192 """
193 And I verify that running `ua disable esm-infra` `as non-root` exits `1`193 And I verify that running `ua disable esm-infra` `as non-root` exits `1`
194 And stderr matches regexp:194 And stderr matches regexp:
@@ -231,7 +231,7 @@ Feature: Command behaviour when attached to an UA subscription
231 When I run `ua status --all` as non-root231 When I run `ua status --all` as non-root
232 Then stdout matches regexp:232 Then stdout matches regexp:
233 """233 """
234 SERVICE AVAILABLE DESCRIPTION234 SERVICE +AVAILABLE DESCRIPTION
235 cc-eal +<cc-eal> +Common Criteria EAL2 Provisioning Packages235 cc-eal +<cc-eal> +Common Criteria EAL2 Provisioning Packages
236 """236 """
237 Then stdout matches regexp:237 Then stdout matches regexp:
@@ -241,6 +241,7 @@ Feature: Command behaviour when attached to an UA subscription
241 fips +<fips> +NIST-certified core packages241 fips +<fips> +NIST-certified core packages
242 fips-updates +<fips> +NIST-certified core packages with priority security updates242 fips-updates +<fips> +NIST-certified core packages with priority security updates
243 livepatch +yes +Canonical Livepatch service243 livepatch +yes +Canonical Livepatch service
244 realtime-kernel +<realtime-kernel> +Beta-version Ubuntu Kernel with PREEMPT_RT patches
244 ros +<ros> +Security Updates for the Robot Operating System245 ros +<ros> +Security Updates for the Robot Operating System
245 ros-updates +<ros> +All Updates for the Robot Operating System246 ros-updates +<ros> +All Updates for the Robot Operating System
246 """247 """
@@ -280,10 +281,10 @@ Feature: Command behaviour when attached to an UA subscription
280 """281 """
281282
282 Examples: ubuntu release283 Examples: ubuntu release
283 | release | esm-apps | cc-eal | cis | fips | fips-update | ros | cis_or_usg |284 | release | esm-apps | cc-eal | cis | fips | fips-update | ros | cis_or_usg | realtime-kernel |
284 | xenial | yes | yes | yes | yes | yes | yes | cis |285 | xenial | yes | yes | yes | yes | yes | yes | cis | no |
285 | bionic | yes | yes | yes | yes | yes | yes | cis |286 | bionic | yes | yes | yes | yes | yes | yes | cis | no |
286 | focal | yes | no | yes | yes | yes | no | usg |287 | focal | yes | no | yes | yes | yes | no | usg | no |
287288
288 @series.all289 @series.all
289 @uses.config.machine_type.lxd.container290 @uses.config.machine_type.lxd.container
@@ -361,8 +362,8 @@ Feature: Command behaviour when attached to an UA subscription
361 And I run `ua status --all` with sudo362 And I run `ua status --all` with sudo
362 Then stdout matches regexp:363 Then stdout matches regexp:
363 """364 """
364 SERVICE ENTITLED STATUS DESCRIPTION365 SERVICE +ENTITLED STATUS DESCRIPTION
365 cc-eal no366 cc-eal +no
366 """367 """
367 When I run `ua --version` as non-root368 When I run `ua --version` as non-root
368 Then I will see the uaclient version on stdout with features ` +disable_auto_attach +machine_token_overlay -other`369 Then I will see the uaclient version on stdout with features ` +disable_auto_attach +machine_token_overlay -other`
@@ -403,8 +404,8 @@ Feature: Command behaviour when attached to an UA subscription
403 And stderr matches regexp:404 And stderr matches regexp:
404 """405 """
405 Cannot disable unknown service 'foobar'.406 Cannot disable unknown service 'foobar'.
406 Try cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch, ros,407 Try cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch,
407 ros-updates.408 realtime-kernel, ros, ros-updates.
408 """409 """
409 When I run `ua status` with sudo410 When I run `ua status` with sudo
410 Then stdout matches regexp:411 Then stdout matches regexp:
@@ -449,8 +450,8 @@ Feature: Command behaviour when attached to an UA subscription
449 And stderr matches regexp:450 And stderr matches regexp:
450 """451 """
451 Cannot disable unknown service 'foobar'.452 Cannot disable unknown service 'foobar'.
452 Try cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, ros,453 Try cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, realtime-kernel,
453 ros-updates, usg.454 ros, ros-updates, usg.
454 """455 """
455 When I run `ua status` with sudo456 When I run `ua status` with sudo
456 Then stdout matches regexp:457 Then stdout matches regexp:
@@ -558,6 +559,8 @@ Feature: Command behaviour when attached to an UA subscription
558 \(https://ubuntu.com/security/certifications#fips\)559 \(https://ubuntu.com/security/certifications#fips\)
559 - livepatch: Canonical Livepatch service560 - livepatch: Canonical Livepatch service
560 \(https://ubuntu.com/security/livepatch\)561 \(https://ubuntu.com/security/livepatch\)
562 - realtime-kernel: Beta-version Ubuntu Kernel with PREEMPT_RT patches
563 \(https://ubuntu.com/realtime-kernel\)
561 - ros-updates: All Updates for the Robot Operating System564 - ros-updates: All Updates for the Robot Operating System
562 \(https://ubuntu.com/robotics/ros-esm\)565 \(https://ubuntu.com/robotics/ros-esm\)
563 - ros: Security Updates for the Robot Operating System566 - ros: Security Updates for the Robot Operating System
@@ -657,6 +660,8 @@ Feature: Command behaviour when attached to an UA subscription
657 \(https://ubuntu.com/security/certifications#fips\)660 \(https://ubuntu.com/security/certifications#fips\)
658 - livepatch: Canonical Livepatch service661 - livepatch: Canonical Livepatch service
659 \(https://ubuntu.com/security/livepatch\)662 \(https://ubuntu.com/security/livepatch\)
663 - realtime-kernel: Beta-version Ubuntu Kernel with PREEMPT_RT patches
664 \(https://ubuntu.com/realtime-kernel\)
660 - ros-updates: All Updates for the Robot Operating System665 - ros-updates: All Updates for the Robot Operating System
661 \(https://ubuntu.com/robotics/ros-esm\)666 \(https://ubuntu.com/robotics/ros-esm\)
662 - ros: Security Updates for the Robot Operating System667 - ros: Security Updates for the Robot Operating System
diff --git a/features/attached_enable.feature b/features/attached_enable.feature
index 90a62cb..7944100 100644
--- a/features/attached_enable.feature
+++ b/features/attached_enable.feature
@@ -669,7 +669,7 @@ Feature: Enable command behaviour when attached to an UA subscription
669 And stdout is a json matching the `ua_operation` schema669 And stdout is a json matching the `ua_operation` schema
670 And I will see the following on stdout:670 And I will see the following on stdout:
671 """671 """
672 {"_schema_version": "0.1", "errors": [{"message": "Cannot enable FIPS when Livepatch is enabled.", "service": "fips", "type": "service"}], "failed_services": ["fips"], "needs_reboot": false, "processed_services": [], "result": "failure", "warnings": []}672 {"_schema_version": "0.1", "errors": [{"message": "Cannot enable FIPS when Livepatch is enabled.", "message_code": "incompatible-service-stops-enable", "service": "fips", "type": "service"}], "failed_services": ["fips"], "needs_reboot": false, "processed_services": [], "result": "failure", "warnings": []}
673 """673 """
674674
675 @slow675 @slow
@@ -693,6 +693,7 @@ Feature: Enable command behaviour when attached to an UA subscription
693 Then I will see the following on stdout693 Then I will see the following on stdout
694 """694 """
695 One moment, checking your subscription first695 One moment, checking your subscription first
696 Disabling incompatible service: Livepatch
696 Updating package lists697 Updating package lists
697 Installing FIPS packages698 Installing FIPS packages
698 FIPS enabled699 FIPS enabled
@@ -761,21 +762,21 @@ Feature: Enable command behaviour when attached to an UA subscription
761 And I run `ua status --all` as non-root762 And I run `ua status --all` as non-root
762 Then stdout matches regexp763 Then stdout matches regexp
763 """764 """
764 ros yes disabled Security Updates for the Robot Operating System765 ros +yes disabled Security Updates for the Robot Operating System
765 """766 """
766 When I run `ua enable ros --assume-yes --beta` with sudo767 When I run `ua enable ros --assume-yes --beta` with sudo
767 And I run `ua status --all` as non-root768 And I run `ua status --all` as non-root
768 Then stdout matches regexp769 Then stdout matches regexp
769 """770 """
770 ros yes enabled Security Updates for the Robot Operating System771 ros +yes enabled Security Updates for the Robot Operating System
771 """772 """
772 And stdout matches regexp773 And stdout matches regexp
773 """774 """
774 esm-apps yes enabled UA Apps: Extended Security Maintenance \(ESM\)775 esm-apps +yes enabled UA Apps: Extended Security Maintenance \(ESM\)
775 """776 """
776 And stdout matches regexp777 And stdout matches regexp
777 """778 """
778 esm-infra yes enabled UA Infra: Extended Security Maintenance \(ESM\)779 esm-infra +yes enabled UA Infra: Extended Security Maintenance \(ESM\)
779 """780 """
780 When I verify that running `ua disable esm-apps` `with sudo` and stdin `N` exits `1`781 When I verify that running `ua disable esm-apps` `with sudo` and stdin `N` exits `1`
781 Then stdout matches regexp782 Then stdout matches regexp
@@ -793,11 +794,11 @@ Feature: Enable command behaviour when attached to an UA subscription
793 When I run `ua status --all` as non-root794 When I run `ua status --all` as non-root
794 Then stdout matches regexp795 Then stdout matches regexp
795 """796 """
796 ros yes disabled Security Updates for the Robot Operating System797 ros +yes disabled Security Updates for the Robot Operating System
797 """798 """
798 And stdout matches regexp799 And stdout matches regexp
799 """800 """
800 esm-apps yes disabled UA Apps: Extended Security Maintenance \(ESM\)801 esm-apps +yes disabled UA Apps: Extended Security Maintenance \(ESM\)
801 """802 """
802 When I verify that running `ua enable ros --beta` `with sudo` and stdin `N` exits `1`803 When I verify that running `ua enable ros --beta` `with sudo` and stdin `N` exits `1`
803 Then stdout matches regexp804 Then stdout matches regexp
@@ -818,15 +819,15 @@ Feature: Enable command behaviour when attached to an UA subscription
818 When I run `ua status --all` as non-root819 When I run `ua status --all` as non-root
819 Then stdout matches regexp820 Then stdout matches regexp
820 """821 """
821 ros yes enabled Security Updates for the Robot Operating System822 ros +yes enabled Security Updates for the Robot Operating System
822 """823 """
823 And stdout matches regexp824 And stdout matches regexp
824 """825 """
825 esm-apps yes enabled UA Apps: Extended Security Maintenance \(ESM\)826 esm-apps +yes enabled UA Apps: Extended Security Maintenance \(ESM\)
826 """827 """
827 And stdout matches regexp828 And stdout matches regexp
828 """829 """
829 esm-infra yes enabled UA Infra: Extended Security Maintenance \(ESM\)830 esm-infra +yes enabled UA Infra: Extended Security Maintenance \(ESM\)
830 """831 """
831 When I run `apt-cache policy` as non-root832 When I run `apt-cache policy` as non-root
832 Then apt-cache policy for the following url has permission `500`833 Then apt-cache policy for the following url has permission `500`
@@ -840,7 +841,7 @@ Feature: Enable command behaviour when attached to an UA subscription
840 And I run `ua status --all` as non-root841 And I run `ua status --all` as non-root
841 Then stdout matches regexp842 Then stdout matches regexp
842 """843 """
843 ros-updates yes enabled All Updates for the Robot Operating System844 ros-updates +yes enabled All Updates for the Robot Operating System
844 """845 """
845 When I run `apt-cache policy` as non-root846 When I run `apt-cache policy` as non-root
846 Then apt-cache policy for the following url has permission `500`847 Then apt-cache policy for the following url has permission `500`
@@ -869,11 +870,11 @@ Feature: Enable command behaviour when attached to an UA subscription
869 When I run `ua status --all` as non-root870 When I run `ua status --all` as non-root
870 Then stdout matches regexp871 Then stdout matches regexp
871 """872 """
872 ros-updates yes enabled All Updates for the Robot Operating System873 ros-updates +yes enabled All Updates for the Robot Operating System
873 """874 """
874 And stdout matches regexp875 And stdout matches regexp
875 """876 """
876 ros yes enabled Security Updates for the Robot Operating System877 ros +yes enabled Security Updates for the Robot Operating System
877 """878 """
878 When I run `ua disable ros-updates --assume-yes` with sudo879 When I run `ua disable ros-updates --assume-yes` with sudo
879 When I run `ua disable ros --assume-yes` with sudo880 When I run `ua disable ros --assume-yes` with sudo
@@ -883,19 +884,19 @@ Feature: Enable command behaviour when attached to an UA subscription
883 When I run `ua status --all` as non-root884 When I run `ua status --all` as non-root
884 Then stdout matches regexp885 Then stdout matches regexp
885 """886 """
886 ros-updates yes enabled All Updates for the Robot Operating System887 ros-updates +yes enabled All Updates for the Robot Operating System
887 """888 """
888 And stdout matches regexp889 And stdout matches regexp
889 """890 """
890 ros yes enabled Security Updates for the Robot Operating System891 ros +yes enabled Security Updates for the Robot Operating System
891 """892 """
892 And stdout matches regexp893 And stdout matches regexp
893 """894 """
894 esm-apps yes enabled UA Apps: Extended Security Maintenance \(ESM\)895 esm-apps +yes enabled UA Apps: Extended Security Maintenance \(ESM\)
895 """896 """
896 And stdout matches regexp897 And stdout matches regexp
897 """898 """
898 esm-infra yes enabled UA Infra: Extended Security Maintenance \(ESM\)899 esm-infra +yes enabled UA Infra: Extended Security Maintenance \(ESM\)
899 """900 """
900 When I run `ua detach` `with sudo` and stdin `y`901 When I run `ua detach` `with sudo` and stdin `y`
901 Then stdout matches regexp:902 Then stdout matches regexp:
@@ -911,3 +912,88 @@ Feature: Enable command behaviour when attached to an UA subscription
911 | release | ros-security-source | ros-updates-source |912 | release | ros-security-source | ros-updates-source |
912 | xenial | https://esm.ubuntu.com/ros/ubuntu xenial-security/main | https://esm.ubuntu.com/ros-updates/ubuntu xenial-updates/main |913 | xenial | https://esm.ubuntu.com/ros/ubuntu xenial-security/main | https://esm.ubuntu.com/ros-updates/ubuntu xenial-updates/main |
913 | bionic | https://esm.ubuntu.com/ros/ubuntu bionic-security/main | https://esm.ubuntu.com/ros-updates/ubuntu bionic-updates/main |914 | bionic | https://esm.ubuntu.com/ros/ubuntu bionic-security/main | https://esm.ubuntu.com/ros-updates/ubuntu bionic-updates/main |
915
916 # Overall test for overrides; in the future, when many services
917 # have overrides, we can consider removing this
918 # FIPS is a good choice because we expect to have it
919 @series.focal
920 @uses.config.machine_type.aws.generic
921 Scenario: Cloud overrides for a generic aws Focal instance
922 Given a `focal` machine with ubuntu-advantage-tools installed
923 When I create the file `/tmp/machine-token-overlay.json` with the following:
924 """
925 {
926 "machineTokenInfo": {
927 "contractInfo": {
928 "resourceEntitlements": [
929 {
930 "type": "fips",
931 "entitled": true,
932 "affordances": {
933 "architectures": [
934 "amd64",
935 "ppc64el",
936 "ppc64le",
937 "s390x",
938 "x86_64"
939 ],
940 "series": [
941 "xenial",
942 "bionic",
943 "focal"
944 ]
945 },
946 "directives": {
947 "additionalPackages": [
948 "ubuntu-fips"
949 ],
950 "aptKey": "E23341B2A1467EDBF07057D6C1997C40EDE22758",
951 "aptURL": "https://esm.ubuntu.com/fips",
952 "suites": [
953 "xenial",
954 "bionic",
955 "focal"
956 ]
957 },
958 "obligations": {
959 "enableByDefault": false
960 },
961 "overrides": [
962 {
963 "selector": {
964 "series": "focal"
965 },
966 "directives": {
967 "additionalPackages": [
968 "some-package-focal"
969 ]
970 }
971 },
972 {
973 "selector": {
974 "cloud": "aws"
975 },
976 "directives": {
977 "additionalPackages": [
978 "some-package-aws"
979 ]
980 }
981 }
982 ]
983 }
984 ]
985 }
986 }
987 }
988 """
989 And I append the following on uaclient config:
990 """
991 features:
992 machine_token_overlay: "/tmp/machine-token-overlay.json"
993 """
994 And I attach `contract_token` with sudo
995 And I verify that running `ua enable fips --assume-yes` `with sudo` exits `1`
996 Then stderr matches regexp:
997 """
998 Stderr: E: Unable to locate package some-package-aws
999 """
diff --git a/features/aws-ids.yaml b/features/aws-ids.yaml
index f2376ad..ec6c43c 100644
--- a/features/aws-ids.yaml
+++ b/features/aws-ids.yaml
@@ -3,3 +3,4 @@ bionic-fips: ami-03b75f613f80bcff1
3focal: ami-0489b8bdbbf3a3b323focal: ami-0489b8bdbbf3a3b32
4xenial: ami-011bcfe2bea365b6a4xenial: ami-011bcfe2bea365b6a
5xenial-fips: ami-077e4c339a098fc9f5xenial-fips: ami-077e4c339a098fc9f
6focal-fips: ami-02782bf2569bf457c
diff --git a/features/azure-ids.yaml b/features/azure-ids.yaml
index 735223f..10b1155 100644
--- a/features/azure-ids.yaml
+++ b/features/azure-ids.yaml
@@ -3,3 +3,4 @@ focal: "Canonical:0001-com-ubuntu-pro-focal:pro-20_04-lts"
3xenial: "Canonical:0001-com-ubuntu-pro-xenial:pro-16_04-lts"3xenial: "Canonical:0001-com-ubuntu-pro-xenial:pro-16_04-lts"
4bionic-fips: "Canonical:0001-com-ubuntu-pro-bionic-fips:pro-fips-18_04"4bionic-fips: "Canonical:0001-com-ubuntu-pro-bionic-fips:pro-fips-18_04"
5xenial-fips: "Canonical:0001-com-ubuntu-pro-xenial-fips:pro-fips-16_04-private"5xenial-fips: "Canonical:0001-com-ubuntu-pro-xenial-fips:pro-fips-16_04-private"
6focal-fips: "Canonical:0001-com-ubuntu-pro-focal-fips:pro-fips-20_04"
diff --git a/features/enable_fips_vm.feature b/features/enable_fips_vm.feature
index a055354..03ccd39 100644
--- a/features/enable_fips_vm.feature
+++ b/features/enable_fips_vm.feature
@@ -462,14 +462,11 @@ Feature: FIPS enablement in lxd VMs
462 | focal | FIPS Updates | fips-updates |https://esm.ubuntu.com/fips-updates/ubuntu focal-updates/main |462 | focal | FIPS Updates | fips-updates |https://esm.ubuntu.com/fips-updates/ubuntu focal-updates/main |
463463
464 @slow464 @slow
465 @series.xenial465 @series.lts
466 @series.bionic
467 @uses.config.machine_type.lxd.vm466 @uses.config.machine_type.lxd.vm
468 Scenario Outline: Attached enable fips-updates on fips enabled vm467 Scenario Outline: Attached enable fips-updates on fips enabled vm
469 Given a `<release>` machine with ubuntu-advantage-tools installed468 Given a `<release>` machine with ubuntu-advantage-tools installed
470 When I attach `contract_token` with sudo469 When I attach `contract_token` with sudo
471 And I run `ua disable livepatch` with sudo
472 And I run `DEBIAN_FRONTEND=noninteractive apt-get install -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -y openssh-client openssh-server strongswan` with sudo, retrying exit [100]
473 And I run `ua enable fips --assume-yes` with sudo470 And I run `ua enable fips --assume-yes` with sudo
474 Then stdout matches regexp:471 Then stdout matches regexp:
475 """472 """
@@ -484,47 +481,61 @@ Feature: FIPS enablement in lxd VMs
484 fips +yes enabled481 fips +yes enabled
485 """482 """
486 When I reboot the `<release>` machine483 When I reboot the `<release>` machine
487 And I run `ua enable fips-updates --assume-yes` with sudo484 And I run `uname -r` as non-root
488 Then stdout matches regexp:485 Then stdout matches regexp:
489 """486 """
490 Updating package lists487 fips
491 Installing FIPS Updates packages
492 FIPS Updates enabled
493 A reboot is required to complete install
494 """488 """
495 When I run `ua status --all` with sudo489 When I verify that running `ua enable fips-updates --assume-yes` `with sudo` exits `0`
496 Then stdout matches regexp:490 Then stdout matches regexp:
497 """491 """
498 fips +yes n/a492 One moment, checking your subscription first
499 """493 Disabling incompatible service: FIPS
500 And stdout matches regexp:494 Updating package lists
501 """495 Installing FIPS Updates packages
502 fips-updates +yes enabled496 FIPS Updates enabled
503 """497 A reboot is required to complete install.
504 When I reboot the `<release>` machine498 """
505 Then I verify that running `apt update` `with sudo` exits `0`499 When I run `ua status --all` with sudo
506 And I verify that `ubuntu-fips` is installed from apt source `<fips-apt-source>`500 Then stdout matches regexp:
507 And I verify that `openssh-server` is installed from apt source `<fips-apt-source>`501 """
508 And I verify that `openssh-client` is installed from apt source `<fips-apt-source>`502 fips-updates +yes enabled
509 And I verify that `strongswan` is installed from apt source `<fips-apt-source>`503 """
510 And I verify that `openssh-server-hmac` is installed from apt source `<fips-apt-source>`504 And stdout matches regexp:
511 And I verify that `openssh-client-hmac` is installed from apt source `<fips-apt-source>`505 """
512 And I verify that `strongswan-hmac` is installed from apt source `<fips-apt-source>`506 fips +yes n/a
513 When I run `uname -r` as non-root507 """
514 Then stdout matches regexp:508 When I reboot the `<release>` machine
515 """509 And I run `ua enable livepatch` with sudo
516 fips510 And I run `ua status --all` with sudo
511 Then stdout matches regexp:
512 """
513 fips-updates +yes enabled
514 """
515 And stdout matches regexp:
516 """
517 fips +yes n/a
518 """
519 And stdout matches regexp:
520 """
521 livepatch +yes enabled
522 """
523 When I run `uname -r` as non-root
524 Then stdout matches regexp:
525 """
526 fips
527 """
528 When I run `cat /proc/sys/crypto/fips_enabled` with sudo
529 Then I will see the following on stdout:
530 """
531 1
517 """532 """
518 When I run `cat /proc/sys/crypto/fips_enabled` with sudo
519 Then I will see the following on stdout:
520 """
521 1
522 """
523533
524 Examples: ubuntu release534 Examples: ubuntu release
525 | release | fips-apt-source |535 | release |
526 | xenial | https://esm.ubuntu.com/fips-updates/ubuntu xenial-updates/main |536 | xenial |
527 | bionic | https://esm.ubuntu.com/fips-updates/ubuntu bionic-updates/main |537 | bionic |
538 | focal |
528539
529 @slow540 @slow
530 @series.xenial541 @series.xenial
diff --git a/features/realtime_kernel.feature b/features/realtime_kernel.feature
531new file mode 100644542new file mode 100644
index 0000000..a04664c
--- /dev/null
+++ b/features/realtime_kernel.feature
@@ -0,0 +1,128 @@
1@uses.config.contract_token
2Feature: Enable command behaviour when attached to an UA subscription
3
4 @series.jammy
5 @uses.config.machine_type.lxd.container
6 Scenario Outline: Enable Real-Time Kernel service in a container
7 Given a `<release>` machine with ubuntu-advantage-tools installed
8 When I attach `contract_token` with sudo
9 Then I verify that running `ua enable realtime-kernel` `as non-root` exits `1`
10 And I will see the following on stderr:
11 """
12 This command must be run as root (try using sudo).
13 """
14 Then I verify that running `ua enable realtime-kernel --beta` `with sudo` exits `1`
15 Then I will see the following on stdout:
16 """
17 One moment, checking your subscription first
18 Cannot install Real-Time Kernel on a container.
19 """
20 Examples: ubuntu release
21 | release |
22 | jammy |
23
24 @series.lts
25 @uses.config.machine_type.lxd.vm
26 Scenario Outline: Enable Real-Time Kernel service on unsupported release
27 Given a `<release>` machine with ubuntu-advantage-tools installed
28 When I attach `contract_token` with sudo
29 Then I verify that running `ua enable realtime-kernel` `as non-root` exits `1`
30 And I will see the following on stderr:
31 """
32 This command must be run as root (try using sudo).
33 """
34 Then I verify that running `ua enable realtime-kernel --beta` `with sudo` exits `1`
35 Then I will see the following on stdout:
36 """
37 One moment, checking your subscription first
38 Real-Time Kernel is not available for Ubuntu <version> (<full_name>).
39 """
40 Examples: ubuntu release
41 | release | version | full_name |
42 | xenial | 16.04 LTS | Xenial Xerus |
43 | bionic | 18.04 LTS | Bionic Beaver |
44 | focal | 20.04 LTS | Focal Fossa |
45 | jammy | 22.04 | Jammy Jellyfish |
46
47 @series.jammy
48 @uses.config.machine_type.gcp.generic
49 Scenario Outline: Enable Real-Time Kernel service
50 Given a `<release>` machine with ubuntu-advantage-tools installed
51 When I create the file `/home/ubuntu/machine-token-overlay.json` with the following:
52 """
53 {
54 "machineTokenInfo": {
55 "contractInfo": {
56 "resourceEntitlements": [
57 {
58 "type": "realtime-kernel",
59 "affordances": {
60 "series": ["jammy"]
61 }
62 }
63 ]
64 }
65 }
66 }
67 """
68 And I append the following on uaclient config:
69 """
70 features:
71 machine_token_overlay: "/home/ubuntu/machine-token-overlay.json"
72 """
73 When I attach `contract_token` with sudo
74 And I run `ua disable livepatch --assume-yes` with sudo
75 Then I verify that running `ua enable realtime-kernel` `as non-root` exits `1`
76 And I will see the following on stderr:
77 """
78 This command must be run as root (try using sudo).
79 """
80 Then I verify that running `ua enable realtime-kernel` `with sudo` exits `1`
81 And stderr matches regexp:
82 """
83 Cannot enable unknown service 'realtime-kernel'.
84 """
85 When I run `ua enable realtime-kernel --beta` `with sudo` and stdin `y`
86 Then stdout matches regexp:
87 """
88 One moment, checking your subscription first
89 The real-time kernel is a beta version of the 22.04 Ubuntu kernel with the
90 PREEMPT_RT patchset integrated for x86_64 and ARM64.
91
92 .*You will not be able to revert to your original kernel after enabling real-time..*
93
94 Do you want to continue\? \[ default = Yes \]: \(Y/n\) Updating package lists
95 Installing Real-Time Kernel packages
96 Real-Time Kernel enabled
97 A reboot is required to complete install.
98 """
99 When I run `apt-cache policy linux-realtime` as non-root
100 Then stdout does not match regexp:
101 """
102 .*Installed: \(none\)
103 """
104 And stdout matches regexp:
105 """
106 \s* 500 https://esm.ubuntu.com/realtime/ubuntu <release>/main amd64 Packages
107 """
108 When I verify that running `ua enable realtime-kernel --beta` `with sudo` exits `1`
109 Then stdout matches regexp
110 """
111 One moment, checking your subscription first
112 Real-Time Kernel is already enabled.
113 See: sudo ua status
114 """
115 When I reboot the `<release>` machine
116 When I run `uname -r` as non-root
117 Then stdout matches regexp:
118 """
119 realtime
120 """
121 When I run `ua disable realtime-kernel` `with sudo` and stdin `y`
122 Then stdout matches regexp:
123 """
124 This will disable the Real-Time Kernel entitlement but the Real-Time Kernel will remain installed.
125 """
126 Examples: ubuntu release
127 | release |
128 | jammy |
diff --git a/features/staging_commands.feature b/features/staging_commands.feature
index 360b329..23aed73 100644
--- a/features/staging_commands.feature
+++ b/features/staging_commands.feature
@@ -9,7 +9,7 @@ Feature: Enable command behaviour when attached to an UA staging subscription
9 And I run `ua status --all` as non-root9 And I run `ua status --all` as non-root
10 Then stdout matches regexp10 Then stdout matches regexp
11 """11 """
12 esm-apps yes enabled UA Apps: Extended Security Maintenance \(ESM\)12 esm-apps +yes enabled UA Apps: Extended Security Maintenance \(ESM\)
13 """13 """
14 And I verify that running `apt update` `with sudo` exits `0`14 And I verify that running `apt update` `with sudo` exits `0`
15 When I run `apt-cache policy` as non-root15 When I run `apt-cache policy` as non-root
diff --git a/features/ubuntu_pro.feature b/features/ubuntu_pro.feature
index 04ef4fc..0f336ef 100644
--- a/features/ubuntu_pro.feature
+++ b/features/ubuntu_pro.feature
@@ -25,7 +25,7 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO image
25 When I run `ua auto-attach` with sudo25 When I run `ua auto-attach` with sudo
26 Then stdout matches regexp:26 Then stdout matches regexp:
27 """27 """
28 SERVICE ENTITLED STATUS DESCRIPTION28 SERVICE +ENTITLED STATUS DESCRIPTION
29 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages29 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages
30 """30 """
31 Then stdout matches regexp:31 Then stdout matches regexp:
@@ -96,7 +96,7 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO image
96 When I run `ua auto-attach` with sudo96 When I run `ua auto-attach` with sudo
97 Then stdout matches regexp:97 Then stdout matches regexp:
98 """98 """
99 SERVICE ENTITLED STATUS DESCRIPTION99 SERVICE +ENTITLED STATUS DESCRIPTION
100 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages100 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages
101 """101 """
102 Then stdout matches regexp:102 Then stdout matches regexp:
@@ -167,7 +167,7 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO image
167 When I run `ua auto-attach` with sudo167 When I run `ua auto-attach` with sudo
168 Then stdout matches regexp:168 Then stdout matches regexp:
169 """169 """
170 SERVICE ENTITLED STATUS DESCRIPTION170 SERVICE +ENTITLED STATUS DESCRIPTION
171 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages171 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages
172 """172 """
173 Then stdout matches regexp:173 Then stdout matches regexp:
@@ -228,7 +228,7 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO image
228 And I run `ua status --wait` as non-root228 And I run `ua status --wait` as non-root
229 Then stdout matches regexp:229 Then stdout matches regexp:
230 """230 """
231 SERVICE ENTITLED STATUS DESCRIPTION231 SERVICE +ENTITLED STATUS DESCRIPTION
232 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages232 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages
233 """233 """
234 Then stdout matches regexp:234 Then stdout matches regexp:
@@ -246,7 +246,7 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO image
246 When I run `ua status --all` as non-root246 When I run `ua status --all` as non-root
247 Then stdout matches regexp:247 Then stdout matches regexp:
248 """248 """
249 SERVICE ENTITLED STATUS DESCRIPTION249 SERVICE +ENTITLED STATUS DESCRIPTION
250 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages250 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages
251 """251 """
252 Then stdout matches regexp:252 Then stdout matches regexp:
@@ -362,7 +362,7 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO image
362 And I run `ua status` as non-root362 And I run `ua status` as non-root
363 Then stdout matches regexp:363 Then stdout matches regexp:
364 """364 """
365 SERVICE ENTITLED STATUS DESCRIPTION365 SERVICE +ENTITLED STATUS DESCRIPTION
366 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages366 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages
367 """367 """
368 Then stdout matches regexp:368 Then stdout matches regexp:
@@ -380,7 +380,7 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO image
380 When I run `ua status --all` as non-root380 When I run `ua status --all` as non-root
381 Then stdout matches regexp:381 Then stdout matches regexp:
382 """382 """
383 SERVICE ENTITLED STATUS DESCRIPTION383 SERVICE +ENTITLED STATUS DESCRIPTION
384 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages384 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages
385 """385 """
386 Then stdout matches regexp:386 Then stdout matches regexp:
@@ -496,7 +496,7 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO image
496 And I run `ua status` as non-root496 And I run `ua status` as non-root
497 Then stdout matches regexp:497 Then stdout matches regexp:
498 """498 """
499 SERVICE ENTITLED STATUS DESCRIPTION499 SERVICE +ENTITLED STATUS DESCRIPTION
500 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages500 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages
501 """501 """
502 Then stdout matches regexp:502 Then stdout matches regexp:
@@ -514,7 +514,7 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO image
514 When I run `ua status --all` as non-root514 When I run `ua status --all` as non-root
515 Then stdout matches regexp:515 Then stdout matches regexp:
516 """516 """
517 SERVICE ENTITLED STATUS DESCRIPTION517 SERVICE +ENTITLED STATUS DESCRIPTION
518 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages518 cc-eal +yes +<cc-eal-s> +Common Criteria EAL2 Provisioning Packages
519 """519 """
520 Then stdout matches regexp:520 Then stdout matches regexp:
diff --git a/features/ubuntu_pro_fips.feature b/features/ubuntu_pro_fips.feature
index 7a18b03..1e83ee3 100644
--- a/features/ubuntu_pro_fips.feature
+++ b/features/ubuntu_pro_fips.feature
@@ -26,12 +26,6 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO fips image
26 """26 """
27 And I verify that running `apt update` `with sudo` exits `0`27 And I verify that running `apt update` `with sudo` exits `0`
28 And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1`28 And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1`
29 And I verify that `openssh-server` is installed from apt source `<fips-apt-source>`
30 And I verify that `openssh-client` is installed from apt source `<fips-apt-source>`
31 And I verify that `strongswan` is installed from apt source `<fips-apt-source>`
32 And I verify that `openssh-server-hmac` is installed from apt source `<fips-apt-source>`
33 And I verify that `openssh-client-hmac` is installed from apt source `<fips-apt-source>`
34 And I verify that `strongswan-hmac` is installed from apt source `<fips-apt-source>`
35 When I run `uname -r` as non-root29 When I run `uname -r` as non-root
36 Then stdout matches regexp:30 Then stdout matches regexp:
37 """31 """
@@ -79,6 +73,10 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO fips image
79 """73 """
80 https://esm.ubuntu.com/apps/ubuntu <release>-apps-security/main amd64 Packages74 https://esm.ubuntu.com/apps/ubuntu <release>-apps-security/main amd64 Packages
81 """75 """
76 And apt-cache policy for the following url has permission `1001`
77 """
78 <fips-apt-source> amd64 Packages
79 """
82 And I verify that running `apt update` `with sudo` exits `0`80 And I verify that running `apt update` `with sudo` exits `0`
83 When I run `apt install -y <infra-pkg>/<release>-infra-security` with sudo, retrying exit [100]81 When I run `apt install -y <infra-pkg>/<release>-infra-security` with sudo, retrying exit [100]
84 And I run `apt-cache policy <infra-pkg>` as non-root82 And I run `apt-cache policy <infra-pkg>` as non-root
@@ -99,15 +97,48 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO fips image
99 \s*\*\*\* .* 50097 \s*\*\*\* .* 500
100 \s*500 https://esm.ubuntu.com/apps/ubuntu <release>-apps-security/main amd64 Packages98 \s*500 https://esm.ubuntu.com/apps/ubuntu <release>-apps-security/main amd64 Packages
101 """99 """
100 When I run `ua enable fips-updates --assume-yes` with sudo
101 Then I will see the following on stdout:
102 """
103 One moment, checking your subscription first
104 Disabling incompatible service: FIPS
105 Updating package lists
106 Installing FIPS Updates packages
107 FIPS Updates enabled
108 A reboot is required to complete install.
109 """
110 When I run `ua status` with sudo
111 Then stdout matches regexp:
112 """
113 fips +yes +n/a +NIST-certified core packages
114 fips-updates +yes +enabled +NIST-certified core packages with priority security updates
115 """
116 When I reboot the `<release>` machine
117 And I run `uname -r` as non-root
118 Then stdout matches regexp:
119 """
120 <fips-kernel-version>
121 """
122 When I run `apt-cache policy ubuntu-azure-fips` as non-root
123 Then stdout does not match regexp:
124 """
125 .*Installed: \(none\)
126 """
127 When I run `cat /proc/sys/crypto/fips_enabled` with sudo
128 Then I will see the following on stdout:
129 """
130 1
131 """
102132
103 Examples: ubuntu release133 Examples: ubuntu release
104 | release | infra-pkg | apps-pkg | fips-apt-source | fips-kernel-version |134 | release | infra-pkg | apps-pkg | fips-apt-source | fips-kernel-version |
105 | xenial | libkrad0 | jq | https://esm.ubuntu.com/fips/ubuntu xenial/main | fips |135 | xenial | libkrad0 | jq | https://esm.ubuntu.com/fips/ubuntu xenial/main | fips |
106 | bionic | libkrad0 | bundler | https://esm.ubuntu.com/fips/ubuntu bionic/main | azure-fips |136 | bionic | libkrad0 | bundler | https://esm.ubuntu.com/fips/ubuntu bionic/main | azure-fips |
137 | focal | hello | 389-ds | https://esm.ubuntu.com/fips/ubuntu focal/main | azure-fips |
107138
108 @series.lts139 @series.focal
109 @uses.config.machine_type.aws.pro.fips140 @uses.config.machine_type.azure.pro.fips
110 Scenario Outline: Check fips is enabled correctly on Ubuntu pro fips AWS machine141 Scenario Outline: Check fips packages are correctly installed on Azure Focal machine
111 Given a `<release>` machine with ubuntu-advantage-tools installed142 Given a `<release>` machine with ubuntu-advantage-tools installed
112 When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following:143 When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following:
113 """144 """
@@ -115,6 +146,44 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO fips image
115 data_dir: /var/lib/ubuntu-advantage146 data_dir: /var/lib/ubuntu-advantage
116 log_level: debug147 log_level: debug
117 log_file: /var/log/ubuntu-advantage.log148 log_file: /var/log/ubuntu-advantage.log
149 features:
150 allow_xenial_fips_on_cloud: true
151 """
152 And I run `ua auto-attach` with sudo
153 And I run `ua status --wait` as non-root
154 And I run `ua status` as non-root
155 Then stdout matches regexp:
156 """
157 esm-apps +yes +enabled +UA Apps: Extended Security Maintenance \(ESM\)
158 esm-infra +yes +enabled +UA Infra: Extended Security Maintenance \(ESM\)
159 fips +yes +enabled +NIST-certified core packages
160 fips-updates +yes +disabled +NIST-certified core packages with priority security updates
161 livepatch +yes +n/a +Canonical Livepatch service
162 """
163 And I verify that running `apt update` `with sudo` exits `0`
164 And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1`
165 And I verify that `openssh-server` is installed from apt source `<fips-apt-source>`
166 And I verify that `openssh-client` is installed from apt source `<fips-apt-source>`
167 And I verify that `strongswan` is installed from apt source `<fips-apt-source>`
168 And I verify that `strongswan-hmac` is installed from apt source `<fips-apt-source>`
169
170 Examples: ubuntu release
171 | release | fips-apt-source |
172 | focal | https://esm.ubuntu.com/fips/ubuntu focal/main |
173
174 @series.xenial
175 @series.bionic
176 @uses.config.machine_type.azure.pro.fips
177 Scenario Outline: Check fips packages are correctly installed on Azure Bionic & Xenial machines
178 Given a `<release>` machine with ubuntu-advantage-tools installed
179 When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following:
180 """
181 contract_url: 'https://contracts.canonical.com'
182 data_dir: /var/lib/ubuntu-advantage
183 log_level: debug
184 log_file: /var/log/ubuntu-advantage.log
185 features:
186 allow_xenial_fips_on_cloud: true
118 """187 """
119 And I run `ua auto-attach` with sudo188 And I run `ua auto-attach` with sudo
120 And I run `ua status --wait` as non-root189 And I run `ua status --wait` as non-root
@@ -135,6 +204,36 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO fips image
135 And I verify that `openssh-server-hmac` is installed from apt source `<fips-apt-source>`204 And I verify that `openssh-server-hmac` is installed from apt source `<fips-apt-source>`
136 And I verify that `openssh-client-hmac` is installed from apt source `<fips-apt-source>`205 And I verify that `openssh-client-hmac` is installed from apt source `<fips-apt-source>`
137 And I verify that `strongswan-hmac` is installed from apt source `<fips-apt-source>`206 And I verify that `strongswan-hmac` is installed from apt source `<fips-apt-source>`
207
208 Examples: ubuntu release
209 | release | fips-apt-source |
210 | xenial | https://esm.ubuntu.com/fips/ubuntu xenial/main |
211 | bionic | https://esm.ubuntu.com/fips/ubuntu bionic/main |
212
213 @series.lts
214 @uses.config.machine_type.aws.pro.fips
215 Scenario Outline: Check fips is enabled correctly on Ubuntu pro fips AWS machine
216 Given a `<release>` machine with ubuntu-advantage-tools installed
217 When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following:
218 """
219 contract_url: 'https://contracts.canonical.com'
220 data_dir: /var/lib/ubuntu-advantage
221 log_level: debug
222 log_file: /var/log/ubuntu-advantage.log
223 """
224 And I run `ua auto-attach` with sudo
225 And I run `ua status --wait` as non-root
226 And I run `ua status` as non-root
227 Then stdout matches regexp:
228 """
229 esm-apps +yes +enabled +UA Apps: Extended Security Maintenance \(ESM\)
230 esm-infra +yes +enabled +UA Infra: Extended Security Maintenance \(ESM\)
231 fips +yes +enabled +NIST-certified core packages
232 fips-updates +yes +disabled +NIST-certified core packages with priority security updates
233 livepatch +yes +n/a +Canonical Livepatch service
234 """
235 And I verify that running `apt update` `with sudo` exits `0`
236 And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1`
138 When I run `uname -r` as non-root237 When I run `uname -r` as non-root
139 Then stdout matches regexp:238 Then stdout matches regexp:
140 """239 """
@@ -182,6 +281,10 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO fips image
182 """281 """
183 https://esm.ubuntu.com/apps/ubuntu <release>-apps-security/main amd64 Packages282 https://esm.ubuntu.com/apps/ubuntu <release>-apps-security/main amd64 Packages
184 """283 """
284 And apt-cache policy for the following url has permission `1001`
285 """
286 <fips-apt-source> amd64 Packages
287 """
185 And I verify that running `apt update` `with sudo` exits `0`288 And I verify that running `apt update` `with sudo` exits `0`
186 When I run `apt install -y <infra-pkg>/<release>-infra-security` with sudo, retrying exit [100]289 When I run `apt install -y <infra-pkg>/<release>-infra-security` with sudo, retrying exit [100]
187 And I run `apt-cache policy <infra-pkg>` as non-root290 And I run `apt-cache policy <infra-pkg>` as non-root
@@ -202,9 +305,167 @@ Feature: Command behaviour when auto-attached in an ubuntu PRO fips image
202 \s*\*\*\* .* 500305 \s*\*\*\* .* 500
203 \s*500 https://esm.ubuntu.com/apps/ubuntu <release>-apps-security/main amd64 Packages306 \s*500 https://esm.ubuntu.com/apps/ubuntu <release>-apps-security/main amd64 Packages
204 """307 """
308 When I run `ua enable fips-updates --assume-yes` with sudo
309 Then I will see the following on stdout:
310 """
311 One moment, checking your subscription first
312 Disabling incompatible service: FIPS
313 Updating package lists
314 Installing FIPS Updates packages
315 FIPS Updates enabled
316 A reboot is required to complete install.
317 """
318 When I run `ua status` with sudo
319 Then stdout matches regexp:
320 """
321 fips +yes +n/a +NIST-certified core packages
322 fips-updates +yes +enabled +NIST-certified core packages with priority security updates
323 """
324 When I reboot the `<release>` machine
325 And I run `uname -r` as non-root
326 Then stdout matches regexp:
327 """
328 <fips-kernel-version>
329 """
330 When I run `apt-cache policy ubuntu-aws-fips` as non-root
331 Then stdout does not match regexp:
332 """
333 .*Installed: \(none\)
334 """
335 When I run `cat /proc/sys/crypto/fips_enabled` with sudo
336 Then I will see the following on stdout:
337 """
338 1
339 """
205340
206 Examples: ubuntu release341 Examples: ubuntu release
207 | release | infra-pkg | apps-pkg | fips-apt-source | fips-kernel-version |342 | release | infra-pkg | apps-pkg | fips-apt-source | fips-kernel-version |
208 | xenial | libkrad0 | jq | https://esm.ubuntu.com/fips/ubuntu xenial/main | fips |343 | xenial | libkrad0 | jq | https://esm.ubuntu.com/fips/ubuntu xenial/main | fips |
209 | bionic | libkrad0 | bundler | https://esm.ubuntu.com/fips/ubuntu bionic/main | aws-fips |344 | bionic | libkrad0 | bundler | https://esm.ubuntu.com/fips/ubuntu bionic/main | aws-fips |
345 | focal | hello | 389-ds | https://esm.ubuntu.com/fips/ubuntu focal/main | aws-fips |
210346
347 @series.focal
348 @uses.config.machine_type.aws.pro.fips
349 Scenario Outline: Check fips packages are correctly installed on AWS Focal machine
350 Given a `<release>` machine with ubuntu-advantage-tools installed
351 When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following:
352 """
353 contract_url: 'https://contracts.canonical.com'
354 data_dir: /var/lib/ubuntu-advantage
355 log_level: debug
356 log_file: /var/log/ubuntu-advantage.log
357 features:
358 allow_xenial_fips_on_cloud: true
359 """
360 And I run `ua auto-attach` with sudo
361 And I run `ua status --wait` as non-root
362 And I run `ua status` as non-root
363 Then stdout matches regexp:
364 """
365 esm-apps +yes +enabled +UA Apps: Extended Security Maintenance \(ESM\)
366 esm-infra +yes +enabled +UA Infra: Extended Security Maintenance \(ESM\)
367 fips +yes +enabled +NIST-certified core packages
368 fips-updates +yes +disabled +NIST-certified core packages with priority security updates
369 livepatch +yes +n/a +Canonical Livepatch service
370 """
371 And I verify that running `apt update` `with sudo` exits `0`
372 And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1`
373 And I verify that `openssh-server` is installed from apt source `<fips-apt-source>`
374 And I verify that `openssh-client` is installed from apt source `<fips-apt-source>`
375 And I verify that `strongswan` is installed from apt source `<fips-apt-source>`
376 And I verify that `strongswan-hmac` is installed from apt source `<fips-apt-source>`
377
378 Examples: ubuntu release
379 | release | fips-apt-source |
380 | focal | https://esm.ubuntu.com/fips/ubuntu focal/main |
381
382 @series.xenial
383 @series.bionic
384 @uses.config.machine_type.aws.pro.fips
385 Scenario Outline: Check fips packages are correctly installed on AWS Bionic & Xenial machines
386 Given a `<release>` machine with ubuntu-advantage-tools installed
387 When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following:
388 """
389 contract_url: 'https://contracts.canonical.com'
390 data_dir: /var/lib/ubuntu-advantage
391 log_level: debug
392 log_file: /var/log/ubuntu-advantage.log
393 features:
394 allow_xenial_fips_on_cloud: true
395 """
396 And I run `ua auto-attach` with sudo
397 And I run `ua status --wait` as non-root
398 And I run `ua status` as non-root
399 Then stdout matches regexp:
400 """
401 esm-apps +yes +enabled +UA Apps: Extended Security Maintenance \(ESM\)
402 esm-infra +yes +enabled +UA Infra: Extended Security Maintenance \(ESM\)
403 fips +yes +enabled +NIST-certified core packages
404 fips-updates +yes +disabled +NIST-certified core packages with priority security updates
405 livepatch +yes +n/a +Canonical Livepatch service
406 """
407 And I verify that running `apt update` `with sudo` exits `0`
408 And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1`
409 And I verify that `openssh-server` is installed from apt source `<fips-apt-source>`
410 And I verify that `openssh-client` is installed from apt source `<fips-apt-source>`
411 And I verify that `strongswan` is installed from apt source `<fips-apt-source>`
412 And I verify that `openssh-server-hmac` is installed from apt source `<fips-apt-source>`
413 And I verify that `openssh-client-hmac` is installed from apt source `<fips-apt-source>`
414 And I verify that `strongswan-hmac` is installed from apt source `<fips-apt-source>`
415
416 Examples: ubuntu release
417 | release | fips-apt-source |
418 | xenial | https://esm.ubuntu.com/fips/ubuntu xenial/main |
419 | bionic | https://esm.ubuntu.com/fips/ubuntu bionic/main |
420
421 @series.focal
422 @uses.config.machine_type.azure.pro.fips
423 @uses.config.machine_type.aws.pro.fips
424 Scenario Outline: Check fips-updates can be enable in a focal PRO FIPS machine
425 Given a `<release>` machine with ubuntu-advantage-tools installed
426 When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following:
427 """
428 contract_url: 'https://contracts.canonical.com'
429 data_dir: /var/lib/ubuntu-advantage
430 log_level: debug
431 log_file: /var/log/ubuntu-advantage.log
432 """
433 And I run `ua auto-attach` with sudo
434 And I run `ua status --wait` as non-root
435 And I run `ua status` as non-root
436 Then stdout matches regexp:
437 """
438 fips +yes +enabled +NIST-certified core packages
439 fips-updates +yes +disabled +NIST-certified core packages with priority security updates
440 """
441 When I run `ua enable fips-updates --assume-yes` with sudo
442 Then stdout matches regexp:
443 """
444 One moment, checking your subscription first
445 Disabling incompatible service: FIPS
446 Updating package lists
447 Installing FIPS Updates packages
448 FIPS Updates enabled
449 A reboot is required to complete install.
450 """
451 When I run `ua status` with sudo
452 Then stdout matches regexp:
453 """
454 fips +yes +n/a +NIST-certified core packages
455 fips-updates +yes +enabled +NIST-certified core packages with priority security updates
456 """
457 When I reboot the `<release>` machine
458 And I run `uname -r` as non-root
459 Then stdout matches regexp:
460 """
461 fips
462 """
463 When I run `cat /proc/sys/crypto/fips_enabled` with sudo
464 Then I will see the following on stdout:
465 """
466 1
467 """
468
469 Examples: ubuntu release
470 | release |
471 | focal |
diff --git a/features/ubuntu_upgrade.feature b/features/ubuntu_upgrade.feature
index 4cf3407..0ffa683 100644
--- a/features/ubuntu_upgrade.feature
+++ b/features/ubuntu_upgrade.feature
@@ -17,7 +17,6 @@ Feature: Upgrade between releases when uaclient is attached
17 [Sources]17 [Sources]
18 AllowThirdParty=yes18 AllowThirdParty=yes
19 """19 """
20 And I run `sed -i 's/Prompt=lts/Prompt=normal/' /etc/update-manager/release-upgrades` with sudo
21 And I run `do-release-upgrade <devel_release> --frontend DistUpgradeViewNonInteractive` `with sudo` and stdin `y\n`20 And I run `do-release-upgrade <devel_release> --frontend DistUpgradeViewNonInteractive` `with sudo` and stdin `y\n`
22 And I reboot the `<release>` machine21 And I reboot the `<release>` machine
23 And I run `lsb_release -cs` as non-root22 And I run `lsb_release -cs` as non-root
@@ -42,7 +41,7 @@ Feature: Upgrade between releases when uaclient is attached
4241
43 Examples: ubuntu release42 Examples: ubuntu release
44 | release | next_release | devel_release |43 | release | next_release | devel_release |
45 | focal | impish | |44 | focal | jammy | --devel-release |
46 | impish | jammy | --devel-release |45 | impish | jammy | --devel-release |
4746
48 @slow47 @slow
diff --git a/features/unattached_status.feature b/features/unattached_status.feature
index 08538a2..eccaf60 100644
--- a/features/unattached_status.feature
+++ b/features/unattached_status.feature
@@ -47,13 +47,13 @@ Feature: Unattached status
47 When I run `ua status` as non-root47 When I run `ua status` as non-root
48 Then stdout matches regexp:48 Then stdout matches regexp:
49 """49 """
50 SERVICE AVAILABLE DESCRIPTION50 SERVICE +AVAILABLE DESCRIPTION
51 cc-eal <cc-eal> +Common Criteria EAL2 Provisioning Packages51 cc-eal +<cc-eal> +Common Criteria EAL2 Provisioning Packages
52 ?<cis>( +<cis-available> +Security compliance and audit tools)?52 ?<cis>( +<cis-available> +Security compliance and audit tools)?
53 ?esm-infra <esm-infra> +UA Infra: Extended Security Maintenance \(ESM\)53 ?esm-infra +<esm-infra> +UA Infra: Extended Security Maintenance \(ESM\)
54 fips <fips> +NIST-certified core packages54 fips +<fips> +NIST-certified core packages
55 fips-updates <fips> +NIST-certified core packages with priority security updates55 fips-updates +<fips> +NIST-certified core packages with priority security updates
56 livepatch <livepatch> +Canonical Livepatch service56 livepatch +<livepatch> +Canonical Livepatch service
57 ?<usg>( +<cis-available> +Security compliance and audit tools)?57 ?<usg>( +<cis-available> +Security compliance and audit tools)?
5858
59 This machine is not attached to a UA subscription.59 This machine is not attached to a UA subscription.
@@ -62,16 +62,17 @@ Feature: Unattached status
62 When I run `ua status --all` as non-root62 When I run `ua status --all` as non-root
63 Then stdout matches regexp:63 Then stdout matches regexp:
64 """64 """
65 SERVICE AVAILABLE DESCRIPTION65 SERVICE +AVAILABLE DESCRIPTION
66 cc-eal <cc-eal> +Common Criteria EAL2 Provisioning Packages66 cc-eal +<cc-eal> +Common Criteria EAL2 Provisioning Packages
67 ?<cis>( +<cis-available> +Security compliance and audit tools)?67 ?<cis>( +<cis-available> +Security compliance and audit tools)?
68 ?esm-apps <esm-apps> +UA Apps: Extended Security Maintenance \(ESM\)68 ?esm-apps +<esm-apps> +UA Apps: Extended Security Maintenance \(ESM\)
69 esm-infra <esm-infra> +UA Infra: Extended Security Maintenance \(ESM\)69 esm-infra +<esm-infra> +UA Infra: Extended Security Maintenance \(ESM\)
70 fips <fips> +NIST-certified core packages70 fips +<fips> +NIST-certified core packages
71 fips-updates <fips> +NIST-certified core packages with priority security updates71 fips-updates +<fips> +NIST-certified core packages with priority security updates
72 livepatch <livepatch> +Canonical Livepatch service72 livepatch +<livepatch> +Canonical Livepatch service
73 ros <ros> +Security Updates for the Robot Operating System73 realtime-kernel +<realtime-kernel> +Beta-version Ubuntu Kernel with PREEMPT_RT patches
74 ros-updates <ros> +All Updates for the Robot Operating System74 ros +<ros> +Security Updates for the Robot Operating System
75 ros-updates +<ros> +All Updates for the Robot Operating System
75 ?<usg>( +<cis-available> +Security compliance and audit tools)?76 ?<usg>( +<cis-available> +Security compliance and audit tools)?
7677
77 This machine is not attached to a UA subscription.78 This machine is not attached to a UA subscription.
@@ -80,13 +81,13 @@ Feature: Unattached status
80 When I run `ua status` with sudo81 When I run `ua status` with sudo
81 Then stdout matches regexp:82 Then stdout matches regexp:
82 """83 """
83 SERVICE AVAILABLE DESCRIPTION84 SERVICE +AVAILABLE DESCRIPTION
84 cc-eal <cc-eal> +Common Criteria EAL2 Provisioning Packages85 cc-eal +<cc-eal> +Common Criteria EAL2 Provisioning Packages
85 ?<cis>( +<cis-available> +Security compliance and audit tools)?86 ?<cis>( +<cis-available> +Security compliance and audit tools)?
86 ?esm-infra <esm-infra> +UA Infra: Extended Security Maintenance \(ESM\)87 ?esm-infra +<esm-infra> +UA Infra: Extended Security Maintenance \(ESM\)
87 fips <fips> +NIST-certified core packages88 fips +<fips> +NIST-certified core packages
88 fips-updates <fips> +NIST-certified core packages with priority security updates89 fips-updates +<fips> +NIST-certified core packages with priority security updates
89 livepatch <livepatch> +Canonical Livepatch service90 livepatch +<livepatch> +Canonical Livepatch service
90 ?<usg>( +<cis-available> +Security compliance and audit tools)?91 ?<usg>( +<cis-available> +Security compliance and audit tools)?
9192
92 This machine is not attached to a UA subscription.93 This machine is not attached to a UA subscription.
@@ -95,16 +96,17 @@ Feature: Unattached status
95 When I run `ua status --all` with sudo96 When I run `ua status --all` with sudo
96 Then stdout matches regexp:97 Then stdout matches regexp:
97 """98 """
98 SERVICE AVAILABLE DESCRIPTION99 SERVICE +AVAILABLE DESCRIPTION
99 cc-eal <cc-eal> +Common Criteria EAL2 Provisioning Packages100 cc-eal +<cc-eal> +Common Criteria EAL2 Provisioning Packages
100 ?<cis>( +<cis-available> +Security compliance and audit tools)?101 ?<cis>( +<cis-available> +Security compliance and audit tools)?
101 ?esm-apps <esm-apps> +UA Apps: Extended Security Maintenance \(ESM\)102 ?esm-apps +<esm-apps> +UA Apps: Extended Security Maintenance \(ESM\)
102 esm-infra <esm-infra> +UA Infra: Extended Security Maintenance \(ESM\)103 esm-infra +<esm-infra> +UA Infra: Extended Security Maintenance \(ESM\)
103 fips <fips> +NIST-certified core packages104 fips +<fips> +NIST-certified core packages
104 fips-updates <fips> +NIST-certified core packages with priority security updates105 fips-updates +<fips> +NIST-certified core packages with priority security updates
105 livepatch <livepatch> +Canonical Livepatch service106 livepatch +<livepatch> +Canonical Livepatch service
106 ros <ros> +Security Updates for the Robot Operating System107 realtime-kernel +<realtime-kernel> +Beta-version Ubuntu Kernel with PREEMPT_RT patches
107 ros-updates <ros> +All Updates for the Robot Operating System108 ros +<ros> +Security Updates for the Robot Operating System
109 ros-updates +<ros> +All Updates for the Robot Operating System
108 ?<usg>( +<cis-available> +Security compliance and audit tools)?110 ?<usg>( +<cis-available> +Security compliance and audit tools)?
109111
110 This machine is not attached to a UA subscription.112 This machine is not attached to a UA subscription.
@@ -118,16 +120,17 @@ Feature: Unattached status
118 And I run `ua status` as non-root120 And I run `ua status` as non-root
119 Then stdout matches regexp:121 Then stdout matches regexp:
120 """122 """
121 SERVICE AVAILABLE DESCRIPTION123 SERVICE +AVAILABLE DESCRIPTION
122 cc-eal <cc-eal> +Common Criteria EAL2 Provisioning Packages124 cc-eal +<cc-eal> +Common Criteria EAL2 Provisioning Packages
123 ?<cis>( +<cis-available> +Security compliance and audit tools)?125 ?<cis>( +<cis-available> +Security compliance and audit tools)?
124 ?esm-apps <esm-apps> +UA Apps: Extended Security Maintenance \(ESM\)126 ?esm-apps +<esm-apps> +UA Apps: Extended Security Maintenance \(ESM\)
125 esm-infra <esm-infra> +UA Infra: Extended Security Maintenance \(ESM\)127 esm-infra +<esm-infra> +UA Infra: Extended Security Maintenance \(ESM\)
126 fips <fips> +NIST-certified core packages128 fips +<fips> +NIST-certified core packages
127 fips-updates <fips> +NIST-certified core packages with priority security updates129 fips-updates +<fips> +NIST-certified core packages with priority security updates
128 livepatch <livepatch> +Canonical Livepatch service130 livepatch +<livepatch> +Canonical Livepatch service
129 ros <ros> +Security Updates for the Robot Operating System131 realtime-kernel +<realtime-kernel> +Beta-version Ubuntu Kernel with PREEMPT_RT patches
130 ros-updates <ros> +All Updates for the Robot Operating System132 ros +<ros> +Security Updates for the Robot Operating System
133 ros-updates +<ros> +All Updates for the Robot Operating System
131 ?<usg>( +<cis-available> +Security compliance and audit tools)?134 ?<usg>( +<cis-available> +Security compliance and audit tools)?
132135
133 This machine is not attached to a UA subscription.136 This machine is not attached to a UA subscription.
@@ -135,44 +138,44 @@ Feature: Unattached status
135 """ 138 """
136139
137 Examples: ubuntu release140 Examples: ubuntu release
138 | release | esm-apps | cc-eal | cis | cis-available | fips | esm-infra | ros | livepatch | usg |141 | release | esm-apps | cc-eal | cis | cis-available | fips | esm-infra | ros | livepatch | usg | realtime-kernel |
139 | xenial | yes | yes | cis | yes | yes | yes | yes | yes | |142 | xenial | yes | yes | cis | yes | yes | yes | yes | yes | | no |
140 | bionic | yes | yes | cis | yes | yes | yes | yes | yes | |143 | bionic | yes | yes | cis | yes | yes | yes | yes | yes | | no |
141 | focal | yes | no | | yes | yes | yes | no | yes | usg |144 | focal | yes | no | | yes | yes | yes | no | yes | usg | no |
142 | impish | no | no | cis | no | no | no | no | no | |145 | impish | no | no | cis | no | no | no | no | no | | no |
143 | jammy | no | no | cis | no | no | no | no | no | |146 | jammy | no | no | cis | no | no | no | no | no | | yes |
144147
145 @series.all148 @series.all
146 @uses.config.machine_type.lxd.container149 @uses.config.machine_type.lxd.container
147 @uses.config.contract_token150 @uses.config.contract_token
148 @uses.config.contract_token_staging_expired
149 Scenario Outline: Simulate status in a ubuntu machine151 Scenario Outline: Simulate status in a ubuntu machine
150 Given a `<release>` machine with ubuntu-advantage-tools installed152 Given a `<release>` machine with ubuntu-advantage-tools installed
151 When I do a preflight check for `contract_token` without the all flag153 When I do a preflight check for `contract_token` without the all flag
152 Then stdout matches regexp:154 Then stdout matches regexp:
153 """155 """
154 SERVICE AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION156 SERVICE +AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION
155 cc-eal <cc-eal> +yes +no +Common Criteria EAL2 Provisioning Packages157 cc-eal +<cc-eal> +yes +no +Common Criteria EAL2 Provisioning Packages
156 ?<cis>( +<cis-available> +yes +no +Security compliance and audit tools)?158 ?<cis>( +<cis-available> +yes +no +Security compliance and audit tools)?
157 ?esm-infra <esm-infra> +yes +yes +UA Infra: Extended Security Maintenance \(ESM\)159 ?esm-infra +<esm-infra> +yes +yes +UA Infra: Extended Security Maintenance \(ESM\)
158 fips <fips> +yes +no +NIST-certified core packages160 fips +<fips> +yes +no +NIST-certified core packages
159 fips-updates <fips> +yes +no +NIST-certified core packages with priority security updates161 fips-updates +<fips> +yes +no +NIST-certified core packages with priority security updates
160 livepatch <livepatch> +yes +yes +Canonical Livepatch service162 livepatch +<livepatch> +yes +yes +Canonical Livepatch service
161 ?<usg>( +<cis-available> +yes +no +Security compliance and audit tools)?163 ?<usg>( +<cis-available> +yes +no +Security compliance and audit tools)?
162 """164 """
163 When I do a preflight check for `contract_token` with the all flag165 When I do a preflight check for `contract_token` with the all flag
164 Then stdout matches regexp:166 Then stdout matches regexp:
165 """167 """
166 SERVICE AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION168 SERVICE +AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION
167 cc-eal <cc-eal> +yes +no +Common Criteria EAL2 Provisioning Packages169 cc-eal +<cc-eal> +yes +no +Common Criteria EAL2 Provisioning Packages
168 ?<cis>( +<cis-available> +yes +no +Security compliance and audit tools)?170 ?<cis>( +<cis-available> +yes +no +Security compliance and audit tools)?
169 ?esm-apps <esm-apps> +yes +yes +UA Apps: Extended Security Maintenance \(ESM\)171 ?esm-apps +<esm-apps> +yes +yes +UA Apps: Extended Security Maintenance \(ESM\)
170 esm-infra <esm-infra> +yes +yes +UA Infra: Extended Security Maintenance \(ESM\)172 esm-infra +<esm-infra> +yes +yes +UA Infra: Extended Security Maintenance \(ESM\)
171 fips <fips> +yes +no +NIST-certified core packages173 fips +<fips> +yes +no +NIST-certified core packages
172 fips-updates <fips> +yes +no +NIST-certified core packages with priority security updates174 fips-updates +<fips> +yes +no +NIST-certified core packages with priority security updates
173 livepatch <livepatch> +yes +yes +Canonical Livepatch service175 livepatch +<livepatch> +yes +yes +Canonical Livepatch service
174 ros <ros> +yes +no +Security Updates for the Robot Operating System176 realtime-kernel +<realtime-kernel> +yes +no +Beta-version Ubuntu Kernel with PREEMPT_RT patches
175 ros-updates <ros> +yes +no +All Updates for the Robot Operating System177 ros +<ros> +yes +no +Security Updates for the Robot Operating System
178 ros-updates +<ros> +yes +no +All Updates for the Robot Operating System
176 ?<usg>( +<cis-available> +yes +no +Security compliance and audit tools)?179 ?<usg>( +<cis-available> +yes +no +Security compliance and audit tools)?
177 """180 """
178 When I do a preflight check for `contract_token` formatted as json181 When I do a preflight check for `contract_token` formatted as json
@@ -199,6 +202,20 @@ Feature: Unattached status
199 services: []202 services: []
200 warnings: []203 warnings: []
201 """204 """
205 Examples: ubuntu release
206 | release | esm-apps | cc-eal | cis | cis-available | fips | esm-infra | ros | livepatch | usg | realtime-kernel |
207 | xenial | yes | yes | cis | yes | yes | yes | yes | yes | | no |
208 | bionic | yes | yes | cis | yes | yes | yes | yes | yes | | no |
209 | focal | yes | no | | yes | yes | yes | no | yes | usg | no |
210 | impish | no | no | cis | no | no | no | no | no | | no |
211 | jammy | no | no | cis | no | no | no | no | no | | yes |
212
213
214 @series.all
215 @uses.config.machine_type.lxd.container
216 @uses.config.contract_token_staging_expired
217 Scenario Outline: Simulate status with expired token in a ubuntu machine
218 Given a `<release>` machine with ubuntu-advantage-tools installed
202 When I run `sed -i 's/contracts.can/contracts.staging.can/' /etc/ubuntu-advantage/uaclient.conf` with sudo219 When I run `sed -i 's/contracts.can/contracts.staging.can/' /etc/ubuntu-advantage/uaclient.conf` with sudo
203 And I verify that a preflight check for `contract_token_staging_expired` formatted as json exits 1220 And I verify that a preflight check for `contract_token_staging_expired` formatted as json exits 1
204 Then stdout is a json matching the `ua_status` schema221 Then stdout is a json matching the `ua_status` schema
@@ -223,13 +240,13 @@ Feature: Unattached status
223 This token is not valid.240 This token is not valid.
224 Contract \".*\" expired on .*241 Contract \".*\" expired on .*
225242
226 SERVICE AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION243 SERVICE +AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION
227 cc-eal <cc-eal> +yes +no +Common Criteria EAL2 Provisioning Packages244 cc-eal +<cc-eal> +yes +no +Common Criteria EAL2 Provisioning Packages
228 ?<cis>( +<cis-available> +yes +no +Security compliance and audit tools)?245 ?<cis>( +<cis-available> +yes +no +Security compliance and audit tools)?
229 ?esm-infra <esm-infra> +yes +yes +UA Infra: Extended Security Maintenance \(ESM\)246 ?esm-infra +<esm-infra> +yes +yes +UA Infra: Extended Security Maintenance \(ESM\)
230 fips <fips> +yes +no +NIST-certified core packages247 fips +<fips> +yes +no +NIST-certified core packages
231 fips-updates <fips> +yes +no +NIST-certified core packages with priority security updates248 fips-updates +<fips> +yes +no +NIST-certified core packages with priority security updates
232 livepatch <livepatch> +yes +yes +Canonical Livepatch service249 livepatch +<livepatch> +yes +yes +Canonical Livepatch service
233 ?<usg>( +<cis-available> +yes +no +Security compliance and audit tools)?250 ?<usg>( +<cis-available> +yes +no +Security compliance and audit tools)?
234 """251 """
235252
@@ -239,4 +256,4 @@ Feature: Unattached status
239 | bionic | yes | yes | cis | yes | yes | yes | yes | yes | |256 | bionic | yes | yes | cis | yes | yes | yes | yes | yes | |
240 | focal | yes | no | | yes | yes | yes | no | yes | usg |257 | focal | yes | no | | yes | yes | yes | no | yes | usg |
241 | impish | no | no | cis | no | no | no | no | no | |258 | impish | no | no | cis | no | no | no | no | no | |
242 | jammy | no | no | cis | no | no | no | no | no | |259 | jammy | no | no | cis | no | no | yes | no | no | |
diff --git a/help_data.yaml b/help_data.yaml
index d5d6486..c301573 100644
--- a/help_data.yaml
+++ b/help_data.yaml
@@ -61,6 +61,16 @@ livepatch:
61 more about Ubuntu Kernel Livepatch service at61 more about Ubuntu Kernel Livepatch service at
62 https://ubuntu.com/security/livepatch62 https://ubuntu.com/security/livepatch
6363
64realtime-kernel:
65 help: |
66 The real-time kernel is a beta version of the 22.04 Ubuntu kernel with the
67 PREEMPT_RT patchset integrated for x86_64 and ARM64. It services extreme
68 latency-dependent use cases and provides deterministic response times to
69 service events. By meeting stringent preemption specifications, the
70 real-time kernel is suitable for telco applications and embedded devices
71 in industrial automation and robotics. To enroll in the beta program, visit
72 https://ubuntu.com/realtime-kernel
73
64ros:74ros:
65 help: |75 help: |
66 ros provides access to a private PPA which includes security-related76 ros provides access to a private PPA which includes security-related
diff --git a/keyrings/ubuntu-advantage-realtime-kernel.gpg b/keyrings/ubuntu-advantage-realtime-kernel.gpg
67new file mode 10064477new file mode 100644
index 0000000..edf9246
68Binary files /dev/null and b/keyrings/ubuntu-advantage-realtime-kernel.gpg differ78Binary files /dev/null and b/keyrings/ubuntu-advantage-realtime-kernel.gpg differ
diff --git a/lib/upgrade_lts_contract.py b/lib/upgrade_lts_contract.py
index 2da9d58..ca7af18 100755
--- a/lib/upgrade_lts_contract.py
+++ b/lib/upgrade_lts_contract.py
@@ -34,21 +34,27 @@ version_to_codename = {
34 "16.04": "xenial",34 "16.04": "xenial",
35 "18.04": "bionic",35 "18.04": "bionic",
36 "20.04": "focal",36 "20.04": "focal",
37 "20.10": "groovy",37 "21.10": "impish",
38 "22.04": "jammy",
38}39}
3940
40current_codename_to_past_codename = {41current_codename_to_past_codename = {
41 "xenial": "trusty",42 "xenial": "trusty",
42 "bionic": "xenial",43 "bionic": "xenial",
43 "focal": "bionic",44 "focal": "bionic",
44 "groovy": "focal",45 "impish": "focal",
46 # We are considering the past release for Jammy to be Focal
47 # because we don't have any services available on Impish.
48 # Therefore, it is safer for us to try to process contract deltas
49 # using Focal
50 "jammy": "focal",
45}51}
4652
4753
48def process_contract_delta_after_apt_lock() -> None:54def process_contract_delta_after_apt_lock() -> None:
49 logging.debug("Check whether to upgrade-lts-contract")55 logging.debug("Check whether to upgrade-lts-contract")
50 if not UAConfig().is_attached:56 if not UAConfig().is_attached:
51 logging.debug("Skiping upgrade-lts-contract. Machine is unattached")57 logging.debug("Skipping upgrade-lts-contract. Machine is unattached")
52 return58 return
53 out, _err = subp(["lsof", "/var/lib/apt/lists/lock"], rcs=[0, 1])59 out, _err = subp(["lsof", "/var/lib/apt/lists/lock"], rcs=[0, 1])
54 msg = "Starting upgrade-lts-contract."60 msg = "Starting upgrade-lts-contract."
@@ -58,7 +64,15 @@ def process_contract_delta_after_apt_lock() -> None:
58 logging.debug(msg)64 logging.debug(msg)
5965
60 current_version = parse_os_release()["VERSION_ID"]66 current_version = parse_os_release()["VERSION_ID"]
61 current_release = version_to_codename[current_version]67 current_release = version_to_codename.get(current_version)
68
69 if current_release is None:
70 msg = "Unable to get release codename for version: {}".format(
71 current_version
72 )
73 print(msg)
74 logging.warning(msg)
75 sys.exit(1)
6276
63 if current_release == "trusty":77 if current_release == "trusty":
64 msg = "Unable to execute upgrade-lts-contract.py on trusty"78 msg = "Unable to execute upgrade-lts-contract.py on trusty"
@@ -66,7 +80,13 @@ def process_contract_delta_after_apt_lock() -> None:
66 logging.warning(msg)80 logging.warning(msg)
67 sys.exit(1)81 sys.exit(1)
6882
69 past_release = current_codename_to_past_codename[current_release]83 past_release = current_codename_to_past_codename.get(current_release)
84 if past_release is None:
85 msg = "Could not find past release for: {}".format(current_release)
86 print(msg)
87 logging.warning(msg)
88 sys.exit(1)
89
70 past_entitlements = UAConfig(series=past_release).entitlements90 past_entitlements = UAConfig(series=past_release).entitlements
71 new_entitlements = UAConfig(series=current_release).entitlements91 new_entitlements = UAConfig(series=current_release).entitlements
7292
diff --git a/tools/refresh-keyrings.sh b/tools/refresh-keyrings.sh
index f4c1db1..850d8fb 100755
--- a/tools/refresh-keyrings.sh
+++ b/tools/refresh-keyrings.sh
@@ -28,6 +28,7 @@ ESM_APPS_KEY_ID="E8A443CE358113D187BEE0E6AB01A101DB53907B"
28FIPS_KEY_ID="E23341B2A1467EDBF07057D6C1997C40EDE22758"28FIPS_KEY_ID="E23341B2A1467EDBF07057D6C1997C40EDE22758"
29CIS_KEY_ID="81CF06E53F2C513A"29CIS_KEY_ID="81CF06E53F2C513A"
30ROS_KEY_ID="853874C8B0F10896"30ROS_KEY_ID="853874C8B0F10896"
31REALTIME_KEY_ID="F6D1E58F4DCD9F91"
3132
32generate_keyrings() {33generate_keyrings() {
33 KEYRING_DIR="$1"34 KEYRING_DIR="$1"
@@ -50,6 +51,8 @@ generate_keyrings() {
50 service_name="cis";;51 service_name="cis";;
51 $ROS_KEY_ID)52 $ROS_KEY_ID)
52 service_name="ros";;53 service_name="ros";;
54 $REALTIME_KEY_ID)
55 service_name="realtime-kernel";;
53 *)56 *)
54 echo "Unhandled key id provided: " $key57 echo "Unhandled key id provided: " $key
55 exit 1;58 exit 1;
@@ -70,6 +73,6 @@ generate_keyrings() {
70}73}
7174
7275
73generate_keyrings $TARGET_DIR $EAL_KEY_ID $ESM_INFRA_KEY_ID $ESM_APPS_KEY_ID $FIPS_KEY_ID $CIS_KEY_ID $ROS_KEY_ID76generate_keyrings $TARGET_DIR $EAL_KEY_ID $ESM_INFRA_KEY_ID $ESM_APPS_KEY_ID $FIPS_KEY_ID $CIS_KEY_ID $ROS_KEY_ID $REALTIME_KEY_ID
7477
75rm -rf $tmp_dir78rm -rf $tmp_dir
diff --git a/tox.ini b/tox.ini
index 45962e0..dffbfa8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -60,6 +60,7 @@ commands =
60 behave-vm-16.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.xenial,series.all,series.lts" --tags="~upgrade"60 behave-vm-16.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.xenial,series.all,series.lts" --tags="~upgrade"
61 behave-vm-18.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.bionic,series.all,series.lts" --tags="~upgrade"61 behave-vm-18.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.bionic,series.all,series.lts" --tags="~upgrade"
62 behave-vm-20.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.focal,series.all,series.lts" --tags="~upgrade"62 behave-vm-20.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.focal,series.all,series.lts" --tags="~upgrade"
63 behave-vm-22.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.jammy,series.all,series.lts" --tags="~upgrade"
63 behave-upgrade-16.04: behave -v {posargs} --tags="upgrade" --tags="series.xenial,series.all"64 behave-upgrade-16.04: behave -v {posargs} --tags="upgrade" --tags="series.xenial,series.all"
64 behave-upgrade-18.04: behave -v {posargs} --tags="upgrade" --tags="series.bionic,series.all"65 behave-upgrade-18.04: behave -v {posargs} --tags="upgrade" --tags="series.bionic,series.all"
65 behave-upgrade-20.04: behave -v {posargs} --tags="upgrade" --tags="series.focal,series.all"66 behave-upgrade-20.04: behave -v {posargs} --tags="upgrade" --tags="series.focal,series.all"
@@ -72,6 +73,7 @@ commands =
72 behave-awspro-20.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro" --tags="series.focal,series.lts,series.all"73 behave-awspro-20.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro" --tags="series.focal,series.lts,series.all"
73 behave-awspro-fips-16.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro.fips" --tags="series.xenial,series.lts,series.all"74 behave-awspro-fips-16.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro.fips" --tags="series.xenial,series.lts,series.all"
74 behave-awspro-fips-18.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro.fips" --tags="series.bionic,series.lts,series.all"75 behave-awspro-fips-18.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro.fips" --tags="series.bionic,series.lts,series.all"
76 behave-awspro-fips-20.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro.fips" --tags="series.focal,series.lts,series.all"
75 behave-azuregeneric-16.04: behave -v {posargs} --tags="uses.config.machine_type.azure.generic" --tags="series.xenial,series.lts,series.all" --tags="~upgrade"77 behave-azuregeneric-16.04: behave -v {posargs} --tags="uses.config.machine_type.azure.generic" --tags="series.xenial,series.lts,series.all" --tags="~upgrade"
76 behave-azuregeneric-18.04: behave -v {posargs} --tags="uses.config.machine_type.azure.generic" --tags="series.bionic,series.lts,series.all" --tags="~upgrade"78 behave-azuregeneric-18.04: behave -v {posargs} --tags="uses.config.machine_type.azure.generic" --tags="series.bionic,series.lts,series.all" --tags="~upgrade"
77 behave-azuregeneric-20.04: behave -v {posargs} --tags="uses.config.machine_type.azure.generic" --tags="series.focal,series.lts,series.all" --tags="~upgrade"79 behave-azuregeneric-20.04: behave -v {posargs} --tags="uses.config.machine_type.azure.generic" --tags="series.focal,series.lts,series.all" --tags="~upgrade"
@@ -80,6 +82,7 @@ commands =
80 behave-azurepro-20.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro" --tags="series.focal,series.lts,series.all"82 behave-azurepro-20.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro" --tags="series.focal,series.lts,series.all"
81 behave-azurepro-fips-16.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro.fips" --tags="series.xenial,series.lts,series.all"83 behave-azurepro-fips-16.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro.fips" --tags="series.xenial,series.lts,series.all"
82 behave-azurepro-fips-18.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro.fips" --tags="series.bionic,series.lts,series.all"84 behave-azurepro-fips-18.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro.fips" --tags="series.bionic,series.lts,series.all"
85 behave-azurepro-fips-20.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro.fips" --tags="series.focal,series.lts,series.all"
83 behave-gcpgeneric-16.04: behave -v {posargs} --tags="uses.config.machine_type.gcp.generic" --tags="series.xenial,series.lts,series.all" --tags="~upgrade"86 behave-gcpgeneric-16.04: behave -v {posargs} --tags="uses.config.machine_type.gcp.generic" --tags="series.xenial,series.lts,series.all" --tags="~upgrade"
84 behave-gcpgeneric-18.04: behave -v {posargs} --tags="uses.config.machine_type.gcp.generic" --tags="series.bionic,series.lts,series.all" --tags="~upgrade"87 behave-gcpgeneric-18.04: behave -v {posargs} --tags="uses.config.machine_type.gcp.generic" --tags="series.bionic,series.lts,series.all" --tags="~upgrade"
85 behave-gcpgeneric-20.04: behave -v {posargs} --tags="uses.config.machine_type.gcp.generic" --tags="series.focal,series.lts,series.all" --tags="~upgrade"88 behave-gcpgeneric-20.04: behave -v {posargs} --tags="uses.config.machine_type.gcp.generic" --tags="series.focal,series.lts,series.all" --tags="~upgrade"
diff --git a/uaclient/clouds/identity.py b/uaclient/clouds/identity.py
index 7542d35..a39fef0 100644
--- a/uaclient/clouds/identity.py
+++ b/uaclient/clouds/identity.py
@@ -1,5 +1,6 @@
1import logging1import logging
2from enum import Enum2from enum import Enum
3from functools import lru_cache
3from typing import Dict, Optional, Tuple, Type # noqa: F4014from typing import Dict, Optional, Tuple, Type # noqa: F401
45
5from uaclient import clouds, exceptions, util6from uaclient import clouds, exceptions, util
@@ -36,6 +37,7 @@ def get_instance_id() -> Optional[str]:
36 return None37 return None
3738
3839
40@lru_cache(maxsize=None)
39@apply_config_settings_override("cloud_type")41@apply_config_settings_override("cloud_type")
40def get_cloud_type() -> Tuple[Optional[str], Optional[NoCloudTypeReason]]:42def get_cloud_type() -> Tuple[Optional[str], Optional[NoCloudTypeReason]]:
41 if util.which("cloud-id"):43 if util.which("cloud-id"):
diff --git a/uaclient/clouds/tests/test_identity.py b/uaclient/clouds/tests/test_identity.py
index a21efee..ae2e4a6 100644
--- a/uaclient/clouds/tests/test_identity.py
+++ b/uaclient/clouds/tests/test_identity.py
@@ -40,7 +40,7 @@ class TestGetCloudType:
40 @mock.patch(M_PATH + "util.subp", return_value=("somecloud\n", ""))40 @mock.patch(M_PATH + "util.subp", return_value=("somecloud\n", ""))
41 def test_use_cloud_id_when_available(self, m_subp, m_which):41 def test_use_cloud_id_when_available(self, m_subp, m_which):
42 """Use cloud-id utility to discover cloud type."""42 """Use cloud-id utility to discover cloud type."""
43 assert ("somecloud", None) == get_cloud_type()43 assert ("somecloud", None) == get_cloud_type.__wrapped__()
44 assert [mock.call("cloud-id")] == m_which.call_args_list44 assert [mock.call("cloud-id")] == m_which.call_args_list
4545
46 @mock.patch(M_PATH + "util.which", return_value="/usr/bin/cloud-id")46 @mock.patch(M_PATH + "util.which", return_value="/usr/bin/cloud-id")
@@ -49,7 +49,10 @@ class TestGetCloudType:
49 side_effect=exceptions.ProcessExecutionError("cloud-id"),49 side_effect=exceptions.ProcessExecutionError("cloud-id"),
50 )50 )
51 def test_error_when_cloud_id_fails(self, m_subp, m_which):51 def test_error_when_cloud_id_fails(self, m_subp, m_which):
52 assert (None, NoCloudTypeReason.CLOUD_ID_ERROR) == get_cloud_type()52 assert (
53 None,
54 NoCloudTypeReason.CLOUD_ID_ERROR,
55 ) == get_cloud_type.__wrapped__()
5356
54 @pytest.mark.parametrize(57 @pytest.mark.parametrize(
55 "settings_overrides",58 "settings_overrides",
@@ -80,7 +83,7 @@ class TestGetCloudType:
80 expected_value = "test"83 expected_value = "test"
8184
82 m_load_file.return_value = settings_overrides85 m_load_file.return_value = settings_overrides
83 assert get_cloud_type() == (expected_value, None)86 assert get_cloud_type.__wrapped__() == (expected_value, None)
8487
8588
86@mock.patch(M_PATH + "get_cloud_type")89@mock.patch(M_PATH + "get_cloud_type")
diff --git a/uaclient/config.py b/uaclient/config.py
index 079708e..74bb06b 100644
--- a/uaclient/config.py
+++ b/uaclient/config.py
@@ -357,7 +357,7 @@ class UAConfig:
357 entitlement_cfg["resourceToken"] = tokens_by_name[357 entitlement_cfg["resourceToken"] = tokens_by_name[
358 entitlement_name358 entitlement_name
359 ]359 ]
360 util.apply_series_overrides(entitlement_cfg, self.series)360 util.apply_contract_overrides(entitlement_cfg, self.series)
361 self._entitlements[entitlement_name] = entitlement_cfg361 self._entitlements[entitlement_name] = entitlement_cfg
362 return self._entitlements362 return self._entitlements
363363
diff --git a/uaclient/contract.py b/uaclient/contract.py
index 47d0b5a..b47b484 100644
--- a/uaclient/contract.py
+++ b/uaclient/contract.py
@@ -347,7 +347,7 @@ def process_entitlement_delta(
347 from uaclient.entitlements import entitlement_factory347 from uaclient.entitlements import entitlement_factory
348348
349 if series_overrides:349 if series_overrides:
350 util.apply_series_overrides(new_access)350 util.apply_contract_overrides(new_access)
351351
352 deltas = util.get_dict_deltas(orig_access, new_access)352 deltas = util.get_dict_deltas(orig_access, new_access)
353 ret = False353 ret = False
diff --git a/uaclient/entitlements/__init__.py b/uaclient/entitlements/__init__.py
index 1c6a156..8f7356d 100644
--- a/uaclient/entitlements/__init__.py
+++ b/uaclient/entitlements/__init__.py
@@ -7,6 +7,7 @@ from uaclient.entitlements.cc import CommonCriteriaEntitlement
7from uaclient.entitlements.cis import CISEntitlement7from uaclient.entitlements.cis import CISEntitlement
8from uaclient.entitlements.esm import ESMAppsEntitlement, ESMInfraEntitlement8from uaclient.entitlements.esm import ESMAppsEntitlement, ESMInfraEntitlement
9from uaclient.entitlements.livepatch import LivepatchEntitlement9from uaclient.entitlements.livepatch import LivepatchEntitlement
10from uaclient.entitlements.realtime import RealtimeKernelEntitlement
10from uaclient.entitlements.ros import ROSEntitlement, ROSUpdatesEntitlement11from uaclient.entitlements.ros import ROSEntitlement, ROSUpdatesEntitlement
11from uaclient.exceptions import EntitlementNotFoundError12from uaclient.exceptions import EntitlementNotFoundError
12from uaclient.util import is_config_value_true13from uaclient.util import is_config_value_true
@@ -19,6 +20,7 @@ ENTITLEMENT_CLASSES = [
19 fips.FIPSEntitlement,20 fips.FIPSEntitlement,
20 fips.FIPSUpdatesEntitlement,21 fips.FIPSUpdatesEntitlement,
21 LivepatchEntitlement,22 LivepatchEntitlement,
23 RealtimeKernelEntitlement,
22 ROSEntitlement,24 ROSEntitlement,
23 ROSUpdatesEntitlement,25 ROSUpdatesEntitlement,
24] # type: List[Type[UAEntitlement]]26] # type: List[Type[UAEntitlement]]
diff --git a/uaclient/entitlements/base.py b/uaclient/entitlements/base.py
index bf1b926..4606b5c 100644
--- a/uaclient/entitlements/base.py
+++ b/uaclient/entitlements/base.py
@@ -209,7 +209,8 @@ class UAEntitlement(metaclass=abc.ABCMeta):
209 populated CanEnableFailure reason. This may expand to209 populated CanEnableFailure reason. This may expand to
210 include other types of reasons in the future.210 include other types of reasons in the future.
211 """211 """
212 msg_ops = self.messaging.get("pre_enable", [])212
213 msg_ops = self.messaging.get("pre_can_enable", [])
213 if not util.handle_message_operations(msg_ops):214 if not util.handle_message_operations(msg_ops):
214 return False, None215 return False, None
215216
@@ -237,6 +238,10 @@ class UAEntitlement(metaclass=abc.ABCMeta):
237 # every other reason means we can't continue238 # every other reason means we can't continue
238 return False, fail239 return False, fail
239240
241 msg_ops = self.messaging.get("pre_enable", [])
242 if not util.handle_message_operations(msg_ops):
243 return False, None
244
240 ret = self._perform_enable(silent=silent)245 ret = self._perform_enable(silent=silent)
241 if not ret:246 if not ret:
242 return False, None247 return False, None
@@ -449,7 +454,7 @@ class UAEntitlement(metaclass=abc.ABCMeta):
449 path_to_value="features.block_disable_on_enable",454 path_to_value="features.block_disable_on_enable",
450 )455 )
451 for service in self.blocking_incompatible_services():456 for service in self.blocking_incompatible_services():
452 ent = service.entitlement(self.cfg)457 ent = service.entitlement(self.cfg, assume_yes=True)
453458
454 user_msg = messages.INCOMPATIBLE_SERVICE.format(459 user_msg = messages.INCOMPATIBLE_SERVICE.format(
455 service_being_enabled=self.title,460 service_being_enabled=self.title,
@@ -474,7 +479,7 @@ class UAEntitlement(metaclass=abc.ABCMeta):
474 )479 )
475 event.info(disable_msg)480 event.info(disable_msg)
476481
477 ret = ent.disable()482 ret = ent.disable(silent=True)
478 if not ret:483 if not ret:
479 return ret, None484 return ret, None
480485
@@ -664,7 +669,7 @@ class UAEntitlement(metaclass=abc.ABCMeta):
664 event.info(info_msg=msg.msg, file_type=sys.stderr)669 event.info(info_msg=msg.msg, file_type=sys.stderr)
665 return False, msg670 return False, msg
666671
667 ent = ent_cls(self.cfg)672 ent = ent_cls(cfg=self.cfg, assume_yes=True)
668673
669 is_service_enabled = (674 is_service_enabled = (
670 ent.application_status()[0] == status.ApplicationStatus.ENABLED675 ent.application_status()[0] == status.ApplicationStatus.ENABLED
@@ -710,13 +715,16 @@ class UAEntitlement(metaclass=abc.ABCMeta):
710 """Check if system needs to be rebooted."""715 """Check if system needs to be rebooted."""
711 return util.should_reboot()716 return util.should_reboot()
712717
713 def _check_for_reboot_msg(self, operation: str) -> None:718 def _check_for_reboot_msg(
719 self, operation: str, silent: bool = False
720 ) -> None:
714 """Check if user should be alerted that a reboot must be performed.721 """Check if user should be alerted that a reboot must be performed.
715722
716 @param operation: The operation being executed.723 @param operation: The operation being executed.
724 @param silent: Boolean set True to silence print/log of messages
717 """725 """
718 if self._check_for_reboot():726 if self._check_for_reboot() and not silent:
719 print(727 event.info(
720 messages.ENABLE_REBOOT_REQUIRED_TMPL.format(728 messages.ENABLE_REBOOT_REQUIRED_TMPL.format(
721 operation=operation729 operation=operation
722 )730 )
@@ -763,7 +771,9 @@ class UAEntitlement(metaclass=abc.ABCMeta):
763 if not util.handle_message_operations(msg_ops):771 if not util.handle_message_operations(msg_ops):
764 return False, None772 return False, None
765773
766 self._check_for_reboot_msg(operation="disable operation")774 self._check_for_reboot_msg(
775 operation="disable operation", silent=silent
776 )
767 return True, None777 return True, None
768778
769 def contract_status(self) -> ContractStatus:779 def contract_status(self) -> ContractStatus:
@@ -836,7 +846,7 @@ class UAEntitlement(metaclass=abc.ABCMeta):
836 transition_to_unentitled = bool(delta_entitlement == util.DROPPED_KEY)846 transition_to_unentitled = bool(delta_entitlement == util.DROPPED_KEY)
837 if not transition_to_unentitled:847 if not transition_to_unentitled:
838 if delta_entitlement:848 if delta_entitlement:
839 util.apply_series_overrides(deltas)849 util.apply_contract_overrides(deltas)
840 delta_entitlement = deltas["entitlement"]850 delta_entitlement = deltas["entitlement"]
841 if orig_access and "entitled" in delta_entitlement:851 if orig_access and "entitled" in delta_entitlement:
842 transition_to_unentitled = delta_entitlement["entitled"] in (852 transition_to_unentitled = delta_entitlement["entitled"] in (
diff --git a/uaclient/entitlements/cis.py b/uaclient/entitlements/cis.py
index 07a6a2e..b5c81f4 100644
--- a/uaclient/entitlements/cis.py
+++ b/uaclient/entitlements/cis.py
@@ -29,7 +29,7 @@ class CISEntitlement(repo.RepoEntitlement):
29 ]29 ]
30 } # type: MessagingOperationsDict30 } # type: MessagingOperationsDict
31 if "usg" in self.valid_names:31 if "usg" in self.valid_names:
32 messages["pre_enable"] = [32 messages["pre_can_enable"] = [
33 "From Ubuntu 20.04 and onwards 'ua enable cis' has been",33 "From Ubuntu 20.04 and onwards 'ua enable cis' has been",
34 "replaced by 'ua enable usg'. See more information at:",34 "replaced by 'ua enable usg'. See more information at:",
35 USG_DOCS_URL,35 USG_DOCS_URL,
diff --git a/uaclient/entitlements/fips.py b/uaclient/entitlements/fips.py
index 7c78543..b83b47e 100644
--- a/uaclient/entitlements/fips.py
+++ b/uaclient/entitlements/fips.py
@@ -87,6 +87,27 @@ class FIPSCommonEntitlement(repo.RepoEntitlement):
8787
88 help_doc_url = "https://ubuntu.com/security/certifications#fips"88 help_doc_url = "https://ubuntu.com/security/certifications#fips"
8989
90 fips_pro_package_holds = [
91 "fips-initramfs",
92 "libssl1.1",
93 "libssl1.1-hmac",
94 "libssl1.0.0",
95 "libssl1.0.0-hmac",
96 "libssl1.0.0",
97 "libssl1.0.0-hmac",
98 "linux-fips",
99 "openssh-client",
100 "openssh-client-hmac",
101 "openssh-server",
102 "openssh-server-hmac",
103 "openssl",
104 "strongswan",
105 "strongswan-hmac",
106 "libgcrypt20",
107 "libgcrypt20-hmac",
108 "fips-initramfs-generic",
109 ]
110
90 @property111 @property
91 def conditional_packages(self):112 def conditional_packages(self):
92 """113 """
@@ -155,19 +176,23 @@ class FIPSCommonEntitlement(repo.RepoEntitlement):
155 )176 )
156 )177 )
157178
158 def _check_for_reboot_msg(self, operation: str) -> None:179 def _check_for_reboot_msg(
180 self, operation: str, silent: bool = False
181 ) -> None:
159 """Check if user should be alerted that a reboot must be performed.182 """Check if user should be alerted that a reboot must be performed.
160183
161 @param operation: The operation being executed.184 @param operation: The operation being executed.
185 @param silent: Boolean set True to silence print/log of messages
162 """186 """
163 reboot_required = util.should_reboot()187 reboot_required = util.should_reboot()
164 event.needs_reboot(reboot_required)188 event.needs_reboot(reboot_required)
165 if reboot_required:189 if reboot_required:
166 event.info(190 if not silent:
167 messages.ENABLE_REBOOT_REQUIRED_TMPL.format(191 event.info(
168 operation=operation192 messages.ENABLE_REBOOT_REQUIRED_TMPL.format(
193 operation=operation
194 )
169 )195 )
170 )
171 if operation == "install":196 if operation == "install":
172 self.cfg.add_notice(197 self.cfg.add_notice(
173 "", messages.FIPS_SYSTEM_REBOOT_REQUIRED.msg198 "", messages.FIPS_SYSTEM_REBOOT_REQUIRED.msg
@@ -361,6 +386,27 @@ class FIPSCommonEntitlement(repo.RepoEntitlement):
361386
362 return False387 return False
363388
389 def setup_apt_config(self, silent: bool = False) -> None:
390 """Setup apt config based on the resourceToken and directives.
391
392 FIPS-specifically handle apt-mark unhold
393
394 :raise UserFacingError: on failure to setup any aspect of this apt
395 configuration
396 """
397 cmd = ["apt-mark", "showholds"]
398 holds = apt.run_apt_command(cmd, " ".join(cmd) + " failed.")
399 unholds = []
400 for hold in holds.splitlines():
401 if hold in self.fips_pro_package_holds:
402 unholds.append(hold)
403 if unholds:
404 unhold_cmd = ["apt-mark", "unhold"] + unholds
405 holds = apt.run_apt_command(
406 unhold_cmd, " ".join(unhold_cmd) + " failed."
407 )
408 super().setup_apt_config(silent=silent)
409
364410
365class FIPSEntitlement(FIPSCommonEntitlement):411class FIPSEntitlement(FIPSCommonEntitlement):
366412
@@ -369,27 +415,10 @@ class FIPSEntitlement(FIPSCommonEntitlement):
369 description = "NIST-certified core packages"415 description = "NIST-certified core packages"
370 origin = "UbuntuFIPS"416 origin = "UbuntuFIPS"
371417
372 fips_pro_package_holds = [
373 "fips-initramfs",
374 "libssl1.1",
375 "libssl1.1-hmac",
376 "libssl1.0.0",
377 "libssl1.0.0-hmac",
378 "libssl1.0.0",
379 "libssl1.0.0-hmac",
380 "linux-fips",
381 "openssh-client",
382 "openssh-client-hmac",
383 "openssh-server",
384 "openssh-server-hmac",
385 "openssl",
386 "strongswan",
387 "strongswan-hmac",
388 ]
389
390 @property418 @property
391 def incompatible_services(self) -> Tuple[IncompatibleService, ...]:419 def incompatible_services(self) -> Tuple[IncompatibleService, ...]:
392 from uaclient.entitlements.livepatch import LivepatchEntitlement420 from uaclient.entitlements.livepatch import LivepatchEntitlement
421 from uaclient.entitlements.realtime import RealtimeKernelEntitlement
393422
394 return (423 return (
395 IncompatibleService(424 IncompatibleService(
@@ -398,6 +427,9 @@ class FIPSEntitlement(FIPSCommonEntitlement):
398 IncompatibleService(427 IncompatibleService(
399 FIPSUpdatesEntitlement, messages.FIPS_UPDATES_INVALIDATES_FIPS428 FIPSUpdatesEntitlement, messages.FIPS_UPDATES_INVALIDATES_FIPS
400 ),429 ),
430 IncompatibleService(
431 RealtimeKernelEntitlement, messages.REALTIME_FIPS_INCOMPATIBLE
432 ),
401 )433 )
402434
403 @property435 @property
@@ -464,27 +496,6 @@ class FIPSEntitlement(FIPSCommonEntitlement):
464 ],496 ],
465 }497 }
466498
467 def setup_apt_config(self, silent: bool = False) -> None:
468 """Setup apt config based on the resourceToken and directives.
469
470 FIPS-specifically handle apt-mark unhold
471
472 :raise UserFacingError: on failure to setup any aspect of this apt
473 configuration
474 """
475 cmd = ["apt-mark", "showholds"]
476 holds = apt.run_apt_command(cmd, " ".join(cmd) + " failed.")
477 unholds = []
478 for hold in holds.splitlines():
479 if hold in self.fips_pro_package_holds:
480 unholds.append(hold)
481 if unholds:
482 unhold_cmd = ["apt-mark", "unhold"] + unholds
483 holds = apt.run_apt_command(
484 unhold_cmd, " ".join(unhold_cmd) + " failed."
485 )
486 super().setup_apt_config(silent=silent)
487
488 def _perform_enable(self, silent: bool = False) -> bool:499 def _perform_enable(self, silent: bool = False) -> bool:
489 cloud_type, error = get_cloud_type()500 cloud_type, error = get_cloud_type()
490 if cloud_type is None and error == NoCloudTypeReason.CLOUD_ID_ERROR:501 if cloud_type is None and error == NoCloudTypeReason.CLOUD_ID_ERROR:
@@ -507,6 +518,20 @@ class FIPSUpdatesEntitlement(FIPSCommonEntitlement):
507 description = "NIST-certified core packages with priority security updates"518 description = "NIST-certified core packages with priority security updates"
508519
509 @property520 @property
521 def incompatible_services(self) -> Tuple[IncompatibleService, ...]:
522 from uaclient.entitlements.realtime import RealtimeKernelEntitlement
523
524 return (
525 IncompatibleService(
526 FIPSEntitlement, messages.FIPS_INVALIDATES_FIPS_UPDATES
527 ),
528 IncompatibleService(
529 RealtimeKernelEntitlement,
530 messages.REALTIME_FIPS_UPDATES_INCOMPATIBLE,
531 ),
532 )
533
534 @property
510 def messaging(self,) -> MessagingOperationsDict:535 def messaging(self,) -> MessagingOperationsDict:
511 post_enable = None # type: Optional[MessagingOperations]536 post_enable = None # type: Optional[MessagingOperations]
512 if util.is_container():537 if util.is_container():
diff --git a/uaclient/entitlements/livepatch.py b/uaclient/entitlements/livepatch.py
index f652eb0..4fc9127 100644
--- a/uaclient/entitlements/livepatch.py
+++ b/uaclient/entitlements/livepatch.py
@@ -109,11 +109,16 @@ class LivepatchEntitlement(UAEntitlement):
109 @property109 @property
110 def incompatible_services(self) -> Tuple[IncompatibleService, ...]:110 def incompatible_services(self) -> Tuple[IncompatibleService, ...]:
111 from uaclient.entitlements.fips import FIPSEntitlement111 from uaclient.entitlements.fips import FIPSEntitlement
112 from uaclient.entitlements.realtime import RealtimeKernelEntitlement
112113
113 return (114 return (
114 IncompatibleService(115 IncompatibleService(
115 FIPSEntitlement, messages.LIVEPATCH_INVALIDATES_FIPS116 FIPSEntitlement, messages.LIVEPATCH_INVALIDATES_FIPS
116 ),117 ),
118 IncompatibleService(
119 RealtimeKernelEntitlement,
120 messages.REALTIME_LIVEPATCH_INCOMPATIBLE,
121 ),
117 )122 )
118123
119 @property124 @property
diff --git a/uaclient/entitlements/realtime.py b/uaclient/entitlements/realtime.py
120new file mode 100644125new file mode 100644
index 0000000..35e5561
--- /dev/null
+++ b/uaclient/entitlements/realtime.py
@@ -0,0 +1,84 @@
1from typing import Tuple
2
3from uaclient import event_logger, messages, util
4from uaclient.entitlements import repo
5from uaclient.entitlements.base import IncompatibleService
6from uaclient.types import MessagingOperationsDict, StaticAffordance
7
8event = event_logger.get_event_logger()
9
10REALTIME_KERNEL_DOCS_URL = "https://ubuntu.com/realtime-kernel"
11
12
13class RealtimeKernelEntitlement(repo.RepoEntitlement):
14 name = "realtime-kernel"
15 title = "Real-Time Kernel"
16 description = "Beta-version Ubuntu Kernel with PREEMPT_RT patches"
17 help_doc_url = REALTIME_KERNEL_DOCS_URL
18 repo_key_file = "ubuntu-advantage-realtime-kernel.gpg"
19 is_beta = True
20 apt_noninteractive = True
21
22 def _check_for_reboot(self) -> bool:
23 """Check if system needs to be rebooted."""
24 reboot_required = util.should_reboot(
25 installed_pkgs=set(self.packages),
26 installed_pkgs_regex=set(["linux-.*-realtime"]),
27 )
28 event.needs_reboot(reboot_required)
29 return reboot_required
30
31 @property
32 def incompatible_services(self) -> Tuple[IncompatibleService, ...]:
33 from uaclient.entitlements.fips import (
34 FIPSEntitlement,
35 FIPSUpdatesEntitlement,
36 )
37 from uaclient.entitlements.livepatch import LivepatchEntitlement
38
39 return (
40 IncompatibleService(
41 FIPSEntitlement, messages.REALTIME_FIPS_INCOMPATIBLE
42 ),
43 IncompatibleService(
44 FIPSUpdatesEntitlement,
45 messages.REALTIME_FIPS_UPDATES_INCOMPATIBLE,
46 ),
47 IncompatibleService(
48 LivepatchEntitlement, messages.REALTIME_LIVEPATCH_INCOMPATIBLE
49 ),
50 )
51
52 @property
53 def static_affordances(self) -> Tuple[StaticAffordance, ...]:
54 return (
55 (
56 messages.REALTIME_ERROR_INSTALL_ON_CONTAINER,
57 lambda: util.is_container(),
58 False,
59 ),
60 )
61
62 @property
63 def messaging(self,) -> MessagingOperationsDict:
64 return {
65 "pre_enable": [
66 (
67 util.prompt_for_confirmation,
68 {
69 "msg": messages.REALTIME_BETA_PROMPT,
70 "assume_yes": self.assume_yes,
71 "default": True,
72 },
73 )
74 ],
75 "pre_disable": [
76 (
77 util.prompt_for_confirmation,
78 {
79 "msg": messages.REALTIME_PRE_DISABLE_PROMPT,
80 "assume_yes": self.assume_yes,
81 },
82 )
83 ],
84 }
diff --git a/uaclient/entitlements/tests/test_cc.py b/uaclient/entitlements/tests/test_cc.py
index 2e42b5f..362f5ea 100644
--- a/uaclient/entitlements/tests/test_cc.py
+++ b/uaclient/entitlements/tests/test_cc.py
@@ -110,8 +110,10 @@ class TestCommonCriteriaEntitlementEnable:
110 @mock.patch("uaclient.util.should_reboot")110 @mock.patch("uaclient.util.should_reboot")
111 @mock.patch("uaclient.util.subp")111 @mock.patch("uaclient.util.subp")
112 @mock.patch("uaclient.util.get_platform_info")112 @mock.patch("uaclient.util.get_platform_info")
113 @mock.patch("uaclient.util.apply_contract_overrides")
113 def test_enable_configures_apt_sources_and_auth_files(114 def test_enable_configures_apt_sources_and_auth_files(
114 self,115 self,
116 _m_contract_overrides,
115 m_platform_info,117 m_platform_info,
116 m_subp,118 m_subp,
117 m_should_reboot,119 m_should_reboot,
diff --git a/uaclient/entitlements/tests/test_fips.py b/uaclient/entitlements/tests/test_fips.py
index 8cf2898..51dc72f 100644
--- a/uaclient/entitlements/tests/test_fips.py
+++ b/uaclient/entitlements/tests/test_fips.py
@@ -21,6 +21,7 @@ from uaclient.entitlements.fips import (
21 FIPSEntitlement,21 FIPSEntitlement,
22 FIPSUpdatesEntitlement,22 FIPSUpdatesEntitlement,
23)23)
24from uaclient.status import CanEnableFailureReason
2425
25M_PATH = "uaclient.entitlements.fips."26M_PATH = "uaclient.entitlements.fips."
26M_LIVEPATCH_PATH = "uaclient.entitlements.livepatch.LivepatchEntitlement."27M_LIVEPATCH_PATH = "uaclient.entitlements.livepatch.LivepatchEntitlement."
@@ -302,9 +303,11 @@ class TestFIPSEntitlementEnable:
302 stack.enter_context(303 stack.enter_context(
303 mock.patch.object(type(entitlement), "packages", m_packages)304 mock.patch.object(type(entitlement), "packages", m_packages)
304 )305 )
306 stack.enter_context(
307 mock.patch("uaclient.util.is_container", return_value=False)
308 )
305309
306 m_can_enable.return_value = (True, None)310 m_can_enable.return_value = (True, None)
307
308 assert (True, None) == entitlement.enable()311 assert (True, None) == entitlement.enable()
309312
310 repo_url = "http://{}".format(entitlement.name.upper())313 repo_url = "http://{}".format(entitlement.name.upper())
@@ -364,27 +367,20 @@ class TestFIPSEntitlementEnable:
364 )367 )
365 )368 )
366369
367 if isinstance(entitlement, FIPSEntitlement):370 subp_calls = [
368 subp_calls = [371 mock.call(
369 mock.call(372 ["apt-mark", "showholds"],
370 ["apt-mark", "showholds"],373 capture=True,
371 capture=True,374 retry_sleeps=apt.APT_RETRIES,
372 retry_sleeps=apt.APT_RETRIES,375 env={},
373 env={},376 ),
374 )377 mock.call(
375 ]378 ["apt-get", "update"],
376 else:379 capture=True,
377 subp_calls = []380 retry_sleeps=apt.APT_RETRIES,
378 subp_calls.extend(381 env={},
379 [382 ),
380 mock.call(383 ]
381 ["apt-get", "update"],
382 capture=True,
383 retry_sleeps=apt.APT_RETRIES,
384 env={},
385 )
386 ]
387 )
388 subp_calls += install_cmd384 subp_calls += install_cmd
389385
390 assert [mock.call()] == m_can_enable.call_args_list386 assert [mock.call()] == m_can_enable.call_args_list
@@ -1092,6 +1088,10 @@ class TestFipsSetupAPTConfig:
1092 "openssh-server\nlibssl1.1-hmac\nasdf\n",1088 "openssh-server\nlibssl1.1-hmac\nasdf\n",
1093 ["openssh-server", "libssl1.1-hmac"],1089 ["openssh-server", "libssl1.1-hmac"],
1094 ),1090 ),
1091 (
1092 "libgcrypt20\nlibgcrypt20-hmac\nwow\n",
1093 ["libgcrypt20", "libgcrypt20-hmac"],
1094 ),
1095 ),1095 ),
1096 )1096 )
1097 @mock.patch(M_REPOPATH + "RepoEntitlement.setup_apt_config")1097 @mock.patch(M_REPOPATH + "RepoEntitlement.setup_apt_config")
@@ -1107,19 +1107,12 @@ class TestFipsSetupAPTConfig:
1107 """Unmark only fips-specific package holds if present."""1107 """Unmark only fips-specific package holds if present."""
1108 run_apt_command.return_value = held_packages1108 run_apt_command.return_value = held_packages
1109 entitlement.setup_apt_config(silent=False)1109 entitlement.setup_apt_config(silent=False)
1110 if isinstance(entitlement, FIPSUpdatesEntitlement):1110 expected_calls = [
1111 expected_calls = []1111 mock.call(["apt-mark", "showholds"], "apt-mark showholds failed.")
1112 else:1112 ]
1113 expected_calls = [1113 if unhold_packages:
1114 mock.call(1114 cmd = ["apt-mark", "unhold"] + unhold_packages
1115 ["apt-mark", "showholds"], "apt-mark showholds failed."1115 expected_calls.append(mock.call(cmd, " ".join(cmd) + " failed."))
1116 )
1117 ]
1118 if unhold_packages:
1119 cmd = ["apt-mark", "unhold"] + unhold_packages
1120 expected_calls.append(
1121 mock.call(cmd, " ".join(cmd) + " failed.")
1122 )
1123 assert expected_calls == run_apt_command.call_args_list1116 assert expected_calls == run_apt_command.call_args_list
1124 assert [mock.call(silent=False)] == setup_apt_config.call_args_list1117 assert [mock.call(silent=False)] == setup_apt_config.call_args_list
11251118
@@ -1287,3 +1280,35 @@ class TestFIPSUpdatesEntitlementEnable:
1287 else:1280 else:
1288 assert not m_read_cache.call_count1281 assert not m_read_cache.call_count
1289 assert not m_write_cache.call_count1282 assert not m_write_cache.call_count
1283
1284
1285class TestFIPSUpdatesEntitlementCanEnable:
1286 @mock.patch("uaclient.util.is_config_value_true", return_value=False)
1287 def test_can_enable_false_if_fips_enabled(
1288 self, m_is_config_value_true, capsys, entitlement_factory
1289 ):
1290 """When entitlement is disabled, can_enable returns True."""
1291 entitlement = entitlement_factory(FIPSUpdatesEntitlement)
1292 with mock.patch.object(
1293 entitlement,
1294 "applicability_status",
1295 return_value=(status.ApplicabilityStatus.APPLICABLE, ""),
1296 ):
1297 with mock.patch.object(
1298 entitlement,
1299 "application_status",
1300 return_value=(status.ApplicationStatus.DISABLED, ""),
1301 ):
1302 with mock.patch(
1303 M_PATH + "FIPSEntitlement.application_status"
1304 ) as m_fips_status:
1305 m_fips_status.return_value = (
1306 status.ApplicationStatus.ENABLED,
1307 None,
1308 )
1309 actual_ret, reason = entitlement.can_enable()
1310 assert actual_ret is False
1311 assert (
1312 reason.reason
1313 == CanEnableFailureReason.INCOMPATIBLE_SERVICE
1314 )
diff --git a/uaclient/entitlements/tests/test_livepatch.py b/uaclient/entitlements/tests/test_livepatch.py
index 191e91d..50fb50d 100644
--- a/uaclient/entitlements/tests/test_livepatch.py
+++ b/uaclient/entitlements/tests/test_livepatch.py
@@ -617,6 +617,7 @@ class TestLivepatchEntitlementEnable:
617 @pytest.mark.parametrize("apt_update_success", (True, False))617 @pytest.mark.parametrize("apt_update_success", (True, False))
618 @mock.patch("uaclient.util.get_platform_info")618 @mock.patch("uaclient.util.get_platform_info")
619 @mock.patch("uaclient.util.subp")619 @mock.patch("uaclient.util.subp")
620 @mock.patch("uaclient.util.apply_contract_overrides")
620 @mock.patch("uaclient.apt.run_apt_install_command")621 @mock.patch("uaclient.apt.run_apt_install_command")
621 @mock.patch("uaclient.apt.run_apt_update_command")622 @mock.patch("uaclient.apt.run_apt_update_command")
622 @mock.patch("uaclient.util.which", return_value=False)623 @mock.patch("uaclient.util.which", return_value=False)
@@ -631,6 +632,7 @@ class TestLivepatchEntitlementEnable:
631 m_which,632 m_which,
632 m_run_apt_update,633 m_run_apt_update,
633 m_run_apt_install,634 m_run_apt_install,
635 _m_contract_overrides,
634 m_subp,636 m_subp,
635 _m_get_platform_info,637 _m_get_platform_info,
636 m_livepatch_proxy,638 m_livepatch_proxy,
@@ -678,6 +680,7 @@ class TestLivepatchEntitlementEnable:
678680
679 @mock.patch("uaclient.util.get_platform_info")681 @mock.patch("uaclient.util.get_platform_info")
680 @mock.patch("uaclient.util.subp", return_value=("snapd", ""))682 @mock.patch("uaclient.util.subp", return_value=("snapd", ""))
683 @mock.patch("uaclient.util.apply_contract_overrides")
681 @mock.patch(684 @mock.patch(
682 "uaclient.util.which", side_effect=lambda cmd: cmd == "/usr/bin/snap"685 "uaclient.util.which", side_effect=lambda cmd: cmd == "/usr/bin/snap"
683 )686 )
@@ -690,6 +693,7 @@ class TestLivepatchEntitlementEnable:
690 m_can_enable,693 m_can_enable,
691 m_app_status,694 m_app_status,
692 m_which,695 m_which,
696 _m_contract_overrides,
693 m_subp,697 m_subp,
694 _m_get_platform_info,698 _m_get_platform_info,
695 m_livepatch_proxy,699 m_livepatch_proxy,
@@ -759,6 +763,7 @@ class TestLivepatchEntitlementEnable:
759 @mock.patch("uaclient.apt.get_installed_packages", return_value=["snapd"])763 @mock.patch("uaclient.apt.get_installed_packages", return_value=["snapd"])
760 @mock.patch("uaclient.util.get_platform_info")764 @mock.patch("uaclient.util.get_platform_info")
761 @mock.patch("uaclient.util.subp")765 @mock.patch("uaclient.util.subp")
766 @mock.patch("uaclient.util.apply_contract_overrides")
762 @mock.patch("uaclient.util.which", side_effect=[True, True])767 @mock.patch("uaclient.util.which", side_effect=[True, True])
763 @mock.patch(M_PATH + "LivepatchEntitlement.application_status")768 @mock.patch(M_PATH + "LivepatchEntitlement.application_status")
764 @mock.patch(769 @mock.patch(
@@ -769,6 +774,7 @@ class TestLivepatchEntitlementEnable:
769 m_can_enable,774 m_can_enable,
770 m_app_status,775 m_app_status,
771 m_which,776 m_which,
777 _m_contract_overrides,
772 m_subp,778 m_subp,
773 _m_get_platform_info,779 _m_get_platform_info,
774 _m_get_installed_packages,780 _m_get_installed_packages,
@@ -808,6 +814,7 @@ class TestLivepatchEntitlementEnable:
808 @mock.patch("uaclient.apt.get_installed_packages", return_value=["snapd"])814 @mock.patch("uaclient.apt.get_installed_packages", return_value=["snapd"])
809 @mock.patch("uaclient.util.get_platform_info")815 @mock.patch("uaclient.util.get_platform_info")
810 @mock.patch("uaclient.util.subp")816 @mock.patch("uaclient.util.subp")
817 @mock.patch("uaclient.util.apply_contract_overrides")
811 @mock.patch("uaclient.util.which", side_effect=[True, True])818 @mock.patch("uaclient.util.which", side_effect=[True, True])
812 @mock.patch(M_PATH + "LivepatchEntitlement.application_status")819 @mock.patch(M_PATH + "LivepatchEntitlement.application_status")
813 @mock.patch(820 @mock.patch(
@@ -818,6 +825,7 @@ class TestLivepatchEntitlementEnable:
818 m_can_enable,825 m_can_enable,
819 m_app_status,826 m_app_status,
820 m_which,827 m_which,
828 _m_contract_overrides,
821 m_subp,829 m_subp,
822 _m_get_platform_info,830 _m_get_platform_info,
823 _m_get_installed_packages,831 _m_get_installed_packages,
diff --git a/uaclient/entitlements/tests/test_repo.py b/uaclient/entitlements/tests/test_repo.py
index 084bab0..c59cb47 100644
--- a/uaclient/entitlements/tests/test_repo.py
+++ b/uaclient/entitlements/tests/test_repo.py
@@ -385,23 +385,25 @@ class TestProcessContractDeltas:
385385
386class TestRepoEnable:386class TestRepoEnable:
387 @pytest.mark.parametrize(387 @pytest.mark.parametrize(
388 "pre_enable_msg, output, can_enable_call_count",388 "pre_enable_msg, output, perform_enable_call_count",
389 (389 (
390 (["msg1", (lambda: False, {}), "msg2"], "msg1\n", 0),390 (["msg1", (lambda: False, {}), "msg2"], "msg1\n", 0),
391 (["msg1", (lambda: True, {}), "msg2"], "msg1\nmsg2\n", 1),391 (["msg1", (lambda: True, {}), "msg2"], "msg1\nmsg2\n", 1),
392 ),392 ),
393 )393 )
394 @mock.patch.object(394 @mock.patch.object(
395 RepoTestEntitlement,395 RepoTestEntitlement, "_perform_enable", return_value=False
396 "can_enable",396 )
397 return_value=(False, status.CanEnableFailure(None)),397 @mock.patch.object(
398 RepoTestEntitlement, "can_enable", return_value=(True, None)
398 )399 )
399 def test_enable_can_exit_on_pre_enable_messaging_hooks(400 def test_enable_can_exit_on_pre_enable_messaging_hooks(
400 self,401 self,
401 m_can_enable,402 _m_can_enable,
403 m_perform_enable,
402 pre_enable_msg,404 pre_enable_msg,
403 output,405 output,
404 can_enable_call_count,406 perform_enable_call_count,
405 entitlement,407 entitlement,
406 capsys,408 capsys,
407 ):409 ):
@@ -414,7 +416,7 @@ class TestRepoEnable:
414 entitlement.enable()416 entitlement.enable()
415 stdout, _ = capsys.readouterr()417 stdout, _ = capsys.readouterr()
416 assert output == stdout418 assert output == stdout
417 assert can_enable_call_count == m_can_enable.call_count419 assert perform_enable_call_count == m_perform_enable.call_count
418420
419 @pytest.mark.parametrize(421 @pytest.mark.parametrize(
420 "pre_disable_msg,post_disable_msg,output,retval",422 "pre_disable_msg,post_disable_msg,output,retval",
@@ -734,8 +736,10 @@ class TestRemoveAptConfig:
734 @mock.patch(M_PATH + "apt.remove_apt_list_files")736 @mock.patch(M_PATH + "apt.remove_apt_list_files")
735 @mock.patch(M_PATH + "apt.run_apt_command")737 @mock.patch(M_PATH + "apt.run_apt_command")
736 @mock.patch(M_PATH + "util.get_platform_info")738 @mock.patch(M_PATH + "util.get_platform_info")
739 @mock.patch(M_PATH + "util.apply_contract_overrides")
737 def test_repo_pin_priority_int_removes_apt_preferences(740 def test_repo_pin_priority_int_removes_apt_preferences(
738 self,741 self,
742 _m_contract_overrides,
739 m_get_platform,743 m_get_platform,
740 _m_run_apt_command,744 _m_run_apt_command,
741 _m_remove_apt_list_files,745 _m_remove_apt_list_files,
@@ -862,8 +866,10 @@ class TestSetupAptConfig:
862 @mock.patch("uaclient.apt.setup_apt_proxy")866 @mock.patch("uaclient.apt.setup_apt_proxy")
863 @mock.patch(M_PATH + "apt.add_auth_apt_repo")867 @mock.patch(M_PATH + "apt.add_auth_apt_repo")
864 @mock.patch(M_PATH + "apt.run_apt_install_command")868 @mock.patch(M_PATH + "apt.run_apt_install_command")
869 @mock.patch(M_PATH + "util.apply_contract_overrides")
865 def test_install_prerequisite_packages(870 def test_install_prerequisite_packages(
866 self,871 self,
872 _m_contract_overrides,
867 m_run_apt_install_command,873 m_run_apt_install_command,
868 m_add_auth_repo,874 m_add_auth_repo,
869 _m_setup_apt_proxy,875 _m_setup_apt_proxy,
@@ -908,8 +914,10 @@ class TestSetupAptConfig:
908 @mock.patch(M_PATH + "apt.add_auth_apt_repo")914 @mock.patch(M_PATH + "apt.add_auth_apt_repo")
909 @mock.patch(M_PATH + "apt.run_apt_command")915 @mock.patch(M_PATH + "apt.run_apt_command")
910 @mock.patch(M_PATH + "util.get_platform_info")916 @mock.patch(M_PATH + "util.get_platform_info")
917 @mock.patch(M_PATH + "util.apply_contract_overrides")
911 def test_setup_with_repo_pin_priority_never_removes_apt_preferences_file(918 def test_setup_with_repo_pin_priority_never_removes_apt_preferences_file(
912 self,919 self,
920 _m_contract_overrides,
913 m_get_platform_info,921 m_get_platform_info,
914 m_run_apt_command,922 m_run_apt_command,
915 m_add_auth_repo,923 m_add_auth_repo,
@@ -940,8 +948,10 @@ class TestSetupAptConfig:
940 @mock.patch(M_PATH + "apt.run_apt_update_command")948 @mock.patch(M_PATH + "apt.run_apt_update_command")
941 @mock.patch(M_PATH + "apt.add_ppa_pinning")949 @mock.patch(M_PATH + "apt.add_ppa_pinning")
942 @mock.patch(M_PATH + "util.get_platform_info")950 @mock.patch(M_PATH + "util.get_platform_info")
951 @mock.patch(M_PATH + "util.apply_contract_overrides")
943 def test_setup_with_repo_pin_priority_int_adds_a_pins_repo_apt_preference(952 def test_setup_with_repo_pin_priority_int_adds_a_pins_repo_apt_preference(
944 self,953 self,
954 _m_apply_overrides,
945 m_get_platform_info,955 m_get_platform_info,
946 m_add_ppa_pinning,956 m_add_ppa_pinning,
947 m_run_apt_update_command,957 m_run_apt_update_command,
diff --git a/uaclient/messages.py b/uaclient/messages.py
index b7640b8..e9f5d9c 100644
--- a/uaclient/messages.py
+++ b/uaclient/messages.py
@@ -22,6 +22,7 @@ class TxtColor:
22 OKGREEN = "\033[92m"22 OKGREEN = "\033[92m"
23 DISABLEGREY = "\033[37m"23 DISABLEGREY = "\033[37m"
24 FAIL = "\033[91m"24 FAIL = "\033[91m"
25 BOLD = "\033[1m"
25 ENDC = "\033[0m"26 ENDC = "\033[0m"
2627
2728
@@ -661,6 +662,12 @@ FIPS_UPDATES_INVALIDATES_FIPS = NamedMessage(
661 " FIPS Updates installs security patches that aren't officially"662 " FIPS Updates installs security patches that aren't officially"
662 " certified.",663 " certified.",
663)664)
665FIPS_INVALIDATES_FIPS_UPDATES = NamedMessage(
666 "fips-invalidates-fips-updates",
667 "FIPS Updates cannot be enabled if FIPS is enabled."
668 " FIPS Updates installs security patches that aren't officially"
669 " certified.",
670)
664LIVEPATCH_INVALIDATES_FIPS = NamedMessage(671LIVEPATCH_INVALIDATES_FIPS = NamedMessage(
665 "livepatch-invalidates-fips",672 "livepatch-invalidates-fips",
666 "Livepatch cannot be enabled while running the official FIPS"673 "Livepatch cannot be enabled while running the official FIPS"
@@ -668,6 +675,45 @@ LIVEPATCH_INVALIDATES_FIPS = NamedMessage(
668 " with additional bug fixes and security updates, you can use"675 " with additional bug fixes and security updates, you can use"
669 " the FIPS Updates service with Livepatch.",676 " the FIPS Updates service with Livepatch.",
670)677)
678REALTIME_FIPS_INCOMPATIBLE = NamedMessage(
679 "realtime-fips-incompatible",
680 "Realtime and FIPS require different kernels, so you cannot enable"
681 " both at the same time.",
682)
683REALTIME_FIPS_UPDATES_INCOMPATIBLE = NamedMessage(
684 "realtime-fips-updates-incompatible",
685 "Realtime and FIPS Updates require different kernels, so you cannot enable"
686 " both at the same time.",
687)
688REALTIME_LIVEPATCH_INCOMPATIBLE = NamedMessage(
689 "realtime-livepatch-incompatible",
690 "Livepatch is not currently supported for the real-time kernel.",
691)
692REALTIME_BETA_FLAG_REQUIRED = NamedMessage(
693 "beta-flag-required",
694 "Use `ua enable realtime-kernel --beta` to acknowledge the real-time"
695 " kernel is currently in beta and comes with no support.",
696)
697REALTIME_BETA_PROMPT = """\
698The real-time kernel is a beta version of the 22.04 Ubuntu kernel with the
699PREEMPT_RT patchset integrated for x86_64 and ARM64.
700
701{bold}You will not be able to revert to your original kernel after enabling\
702 real-time.{end_bold}
703
704Do you want to continue? [ default = Yes ]: (Y/n) """.format(
705 bold=TxtColor.BOLD, end_bold=TxtColor.ENDC
706)
707REALTIME_PRE_DISABLE_PROMPT = """\
708This will disable the Real-Time Kernel entitlement but the Real-Time Kernel\
709 will remain installed.
710Are you sure? (y/N) """
711
712REALTIME_ERROR_INSTALL_ON_CONTAINER = NamedMessage(
713 "realtime-error-install-on-container",
714 "Cannot install Real-Time Kernel on a container.",
715)
716
671717
672LOG_CONNECTIVITY_ERROR_TMPL = CONNECTIVITY_ERROR.msg + " {error}"718LOG_CONNECTIVITY_ERROR_TMPL = CONNECTIVITY_ERROR.msg + " {error}"
673LOG_CONNECTIVITY_ERROR_WITH_URL_TMPL = (719LOG_CONNECTIVITY_ERROR_WITH_URL_TMPL = (
diff --git a/uaclient/status.py b/uaclient/status.py
index 7dd5ba2..3db4b67 100644
--- a/uaclient/status.py
+++ b/uaclient/status.py
@@ -225,17 +225,17 @@ Open a browser to: {}/subscribe""".format(
225 BASE_UA_URL225 BASE_UA_URL
226)226)
227227
228STATUS_UNATTACHED_TMPL = "{name: <14}{available: <11}{description}"228STATUS_UNATTACHED_TMPL = "{name: <17}{available: <11}{description}"
229229
230STATUS_SIMULATED_TMPL = """\230STATUS_SIMULATED_TMPL = """\
231{name: <14}{available: <11}{entitled: <11}{auto_enabled: <14}{description}"""231{name: <17}{available: <11}{entitled: <11}{auto_enabled: <14}{description}"""
232232
233STATUS_HEADER = "SERVICE ENTITLED STATUS DESCRIPTION"233STATUS_HEADER = "SERVICE ENTITLED STATUS DESCRIPTION"
234# The widths listed below for entitled and status are actually 9 characters234# The widths listed below for entitled and status are actually 9 characters
235# less than reality because we colorize the values in entitled and status235# less than reality because we colorize the values in entitled and status
236# columns. Colorizing has an opening and closing set of unprintable characters236# columns. Colorizing has an opening and closing set of unprintable characters
237# that factor into formats len() calculations237# that factor into formats len() calculations
238STATUS_TMPL = "{name: <14}{entitled: <19}{status: <19}{description}"238STATUS_TMPL = "{name: <17}{entitled: <19}{status: <19}{description}"
239239
240240
241def colorize(string: str) -> str:241def colorize(string: str) -> str:
diff --git a/uaclient/tests/test_cli_attach.py b/uaclient/tests/test_cli_attach.py
index 75cd0e1..e568f5f 100644
--- a/uaclient/tests/test_cli_attach.py
+++ b/uaclient/tests/test_cli_attach.py
@@ -532,14 +532,14 @@ class TestActionAttach:
532 assert expected == json.loads(fake_stdout.getvalue())532 assert expected == json.loads(fake_stdout.getvalue())
533533
534 @mock.patch("uaclient.contract.process_entitlement_delta")534 @mock.patch("uaclient.contract.process_entitlement_delta")
535 @mock.patch("uaclient.util.apply_series_overrides")535 @mock.patch("uaclient.util.apply_contract_overrides")
536 @mock.patch("uaclient.contract.UAContractClient.request_url")536 @mock.patch("uaclient.contract.UAContractClient.request_url")
537 @mock.patch("uaclient.jobs.update_messaging.update_apt_and_motd_messages")537 @mock.patch("uaclient.jobs.update_messaging.update_apt_and_motd_messages")
538 def test_attach_when_one_service_fails_to_enable(538 def test_attach_when_one_service_fails_to_enable(
539 self,539 self,
540 _m_update_messages,540 _m_update_messages,
541 m_request_url,541 m_request_url,
542 _m_apply_series_overrides,542 _m_apply_contract_overrides,
543 m_process_entitlement_delta,543 m_process_entitlement_delta,
544 _m_getuid,544 _m_getuid,
545 FakeConfig,545 FakeConfig,
diff --git a/uaclient/tests/test_cli_collect_logs.py b/uaclient/tests/test_cli_collect_logs.py
index df6feba..accf283 100644
--- a/uaclient/tests/test_cli_collect_logs.py
+++ b/uaclient/tests/test_cli_collect_logs.py
@@ -124,8 +124,8 @@ class TestActionCollectLogs:
124 ),124 ),
125 ]125 ]
126126
127 assert m_copy.call_count == 14127 assert m_copy.call_count == 15
128 assert redact.call_count == 14128 assert redact.call_count == 15
129129
130130
131class TestParser:131class TestParser:
diff --git a/uaclient/tests/test_cli_status.py b/uaclient/tests/test_cli_status.py
index 125a896..1331955 100644
--- a/uaclient/tests/test_cli_status.py
+++ b/uaclient/tests/test_cli_status.py
@@ -24,6 +24,7 @@ RESPONSE_AVAILABLE_SERVICES = [
24 {"name": "esm-infra", "available": False},24 {"name": "esm-infra", "available": False},
25 {"name": "esm-apps", "available": True},25 {"name": "esm-apps", "available": True},
26 {"name": "fips-updates", "available": False},26 {"name": "fips-updates", "available": False},
27 {"name": "realtime-kernel", "available": False},
27 {"name": "ros", "available": False},28 {"name": "ros", "available": False},
28 {"name": "ros-updates", "available": False},29 {"name": "ros-updates", "available": False},
29]30]
@@ -68,41 +69,34 @@ RESPONSE_CONTRACT_INFO = {
68}69}
6970
70SIMULATED_STATUS = """\71SIMULATED_STATUS = """\
71SERVICE AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION72SERVICE AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION
72esm-infra no yes yes UA Infra: Extended Security\73esm-infra no yes yes UA Infra: Extended Security Maintenance (ESM)
73 Maintenance (ESM)74fips no no no NIST-certified core packages
74fips no no no NIST-certified core packages75fips-updates no no no NIST-certified core packages with priority security updates
75fips-updates no no no NIST-certified core packages\76livepatch yes yes no Canonical Livepatch service
76 with priority security updates77""" # noqa: E501
77livepatch yes yes no Canonical Livepatch service
78"""
7978
80UNATTACHED_STATUS = """\79UNATTACHED_STATUS = """\
81SERVICE AVAILABLE DESCRIPTION80SERVICE AVAILABLE DESCRIPTION
82esm-infra no UA Infra: Extended Security Maintenance (ESM)81esm-infra no UA Infra: Extended Security Maintenance (ESM)
83fips no NIST-certified core packages82fips no NIST-certified core packages
84fips-updates no NIST-certified core packages with priority\83fips-updates no NIST-certified core packages with priority security updates
85 security updates84livepatch yes Canonical Livepatch service
86livepatch yes Canonical Livepatch service
8785
88This machine is not attached to a UA subscription.86This machine is not attached to a UA subscription.
89See https://ubuntu.com/advantage87See https://ubuntu.com/advantage
90"""88""" # noqa: E501
9189
92ATTACHED_STATUS = """\90ATTACHED_STATUS = """\
93SERVICE ENTITLED STATUS DESCRIPTION91SERVICE ENTITLED STATUS DESCRIPTION
94esm-apps no {dash} UA Apps: Extended Security Maintenance\92esm-apps no {dash} UA Apps: Extended Security Maintenance (ESM)
95 (ESM)93esm-infra no {dash} UA Infra: Extended Security Maintenance (ESM)
96esm-infra no {dash} UA Infra: Extended Security Maintenance\94fips no {dash} NIST-certified core packages
97 (ESM)95fips-updates no {dash} NIST-certified core packages with priority security updates
98fips no {dash} NIST-certified core packages96livepatch no {dash} Canonical Livepatch service
99fips-updates no {dash} NIST-certified core packages with\97realtime-kernel no {dash} Beta-version Ubuntu Kernel with PREEMPT_RT patches
100 priority security updates98ros no {dash} Security Updates for the Robot Operating System
101livepatch no {dash} Canonical Livepatch service99ros-updates no {dash} All Updates for the Robot Operating System
102ros no {dash} Security Updates for the Robot\
103 Operating System
104ros-updates no {dash} All Updates for the Robot Operating\
105 System
106{notices}100{notices}
107Enable services with: ua enable <service>101Enable services with: ua enable <service>
108102
@@ -110,17 +104,15 @@ Enable services with: ua enable <service>
110 Subscription: test_contract104 Subscription: test_contract
111 Valid until: 2040-05-08 19:02:26+00:00105 Valid until: 2040-05-08 19:02:26+00:00
112Technical support level: n/a106Technical support level: n/a
113"""107""" # noqa: E501
114108
115# Omit beta services from status109# Omit beta services from status
116ATTACHED_STATUS_NOBETA = """\110ATTACHED_STATUS_NOBETA = """\
117SERVICE ENTITLED STATUS DESCRIPTION111SERVICE ENTITLED STATUS DESCRIPTION
118esm-infra no {dash} UA Infra: Extended Security Maintenance\112esm-infra no {dash} UA Infra: Extended Security Maintenance (ESM)
119 (ESM)113fips no {dash} NIST-certified core packages
120fips no {dash} NIST-certified core packages114fips-updates no {dash} NIST-certified core packages with priority security updates
121fips-updates no {dash} NIST-certified core packages with\115livepatch no {dash} Canonical Livepatch service
122 priority security updates
123livepatch no {dash} Canonical Livepatch service
124{notices}116{notices}
125Enable services with: ua enable <service>117Enable services with: ua enable <service>
126118
@@ -128,9 +120,9 @@ Enable services with: ua enable <service>
128 Subscription: test_contract120 Subscription: test_contract
129 Valid until: 2040-05-08 19:02:26+00:00121 Valid until: 2040-05-08 19:02:26+00:00
130Technical support level: n/a122Technical support level: n/a
131"""123""" # noqa: E501
132124
133BETA_SVC_NAMES = ["esm-apps", "ros", "ros-updates"]125BETA_SVC_NAMES = ["esm-apps", "realtime-kernel", "ros", "ros-updates"]
134126
135SERVICES_JSON_ALL = [127SERVICES_JSON_ALL = [
136 {128 {
@@ -186,6 +178,16 @@ SERVICES_JSON_ALL = [
186 "blocked_by": [],178 "blocked_by": [],
187 },179 },
188 {180 {
181 "description": "TODO",
182 "description_override": None,
183 "entitled": "no",
184 "name": "realtime-kernel",
185 "status": "—",
186 "status_details": "",
187 "available": "yes",
188 "blocked_by": [],
189 },
190 {
189 "description": "Security Updates for the Robot Operating System",191 "description": "Security Updates for the Robot Operating System",
190 "description_override": None,192 "description_override": None,
191 "entitled": "no",193 "entitled": "no",
@@ -739,6 +741,14 @@ class TestActionStatus:
739 {741 {
740 "auto_enabled": "no",742 "auto_enabled": "no",
741 "available": "no",743 "available": "no",
744 "description": "Beta-version Ubuntu Kernel with PREEMPT_RT"
745 " patches",
746 "entitled": "no",
747 "name": "realtime-kernel",
748 },
749 {
750 "auto_enabled": "no",
751 "available": "no",
742 "description": "Security Updates for the Robot Operating"752 "description": "Security Updates for the Robot Operating"
743 " System",753 " System",
744 "entitled": "no",754 "entitled": "no",
@@ -754,7 +764,7 @@ class TestActionStatus:
754 ]764 ]
755765
756 if not use_all:766 if not use_all:
757 expected_services = expected_services[1:-2]767 expected_services = expected_services[1:-3]
758768
759 expected = {769 expected = {
760 "_doc": "Content provided in json response is currently considered"770 "_doc": "Content provided in json response is currently considered"
diff --git a/uaclient/tests/test_upgrade_lts_contract.py b/uaclient/tests/test_upgrade_lts_contract.py
index 231fa17..7f76620 100644
--- a/uaclient/tests/test_upgrade_lts_contract.py
+++ b/uaclient/tests/test_upgrade_lts_contract.py
@@ -16,7 +16,7 @@ class TestUpgradeLTSContract:
16 def test_unattached_noops(self, m_is_attached, capsys, caplog_text):16 def test_unattached_noops(self, m_is_attached, capsys, caplog_text):
17 expected_logs = [17 expected_logs = [
18 "Check whether to upgrade-lts-contract",18 "Check whether to upgrade-lts-contract",
19 "Skiping upgrade-lts-contract. Machine is unattached",19 "Skipping upgrade-lts-contract. Machine is unattached",
20 ]20 ]
2121
22 process_contract_delta_after_apt_lock()22 process_contract_delta_after_apt_lock()
@@ -67,6 +67,72 @@ class TestUpgradeLTSContract:
67 )67 )
68 @mock.patch("lib.upgrade_lts_contract.parse_os_release")68 @mock.patch("lib.upgrade_lts_contract.parse_os_release")
69 @mock.patch("lib.upgrade_lts_contract.subp")69 @mock.patch("lib.upgrade_lts_contract.subp")
70 def test_upgrade_cancel_when_current_version_not_supported(
71 self, m_subp, m_parse_os, m_is_attached, capsys, caplog_text
72 ):
73 m_parse_os.return_value = {"VERSION_ID": "NOT-SUPPORTED"}
74 m_subp.return_value = ("", "")
75
76 expected_msgs = [
77 "Starting upgrade-lts-contract.",
78 "Unable to get release codename for version: NOT-SUPPORTED",
79 ]
80 expected_logs = ["Check whether to upgrade-lts-contract"]
81 with pytest.raises(SystemExit) as execinfo:
82 process_contract_delta_after_apt_lock()
83
84 assert 1 == execinfo.value.code
85 assert 1 == m_is_attached.call_count
86 assert 1 == m_parse_os.call_count
87 assert 1 == m_subp.call_count
88 out, _err = capsys.readouterr()
89 assert out == "\n".join(expected_msgs) + "\n"
90 debug_logs = caplog_text()
91 for log in expected_msgs + expected_logs:
92 assert log in debug_logs
93
94 @mock.patch(
95 "uaclient.config.UAConfig.is_attached",
96 new_callable=mock.PropertyMock,
97 return_value=True,
98 )
99 @mock.patch("lib.upgrade_lts_contract.parse_os_release")
100 @mock.patch("lib.upgrade_lts_contract.subp")
101 def test_upgrade_cancel_when_past_version_not_supported(
102 self, m_subp, m_parse_os, m_is_attached, capsys, caplog_text
103 ):
104 m_parse_os.return_value = {"VERSION_ID": "20.10"}
105 m_subp.return_value = ("", "")
106
107 expected_msgs = [
108 "Starting upgrade-lts-contract.",
109 "Could not find past release for: groovy",
110 ]
111 expected_logs = ["Check whether to upgrade-lts-contract"]
112 with pytest.raises(SystemExit) as execinfo:
113 with mock.patch(
114 "lib.upgrade_lts_contract.version_to_codename",
115 {"20.10": "groovy"},
116 ):
117 process_contract_delta_after_apt_lock()
118
119 assert 1 == execinfo.value.code
120 assert 1 == m_is_attached.call_count
121 assert 1 == m_parse_os.call_count
122 assert 1 == m_subp.call_count
123 out, _err = capsys.readouterr()
124 assert out == "\n".join(expected_msgs) + "\n"
125 debug_logs = caplog_text()
126 for log in expected_msgs + expected_logs:
127 assert log in debug_logs
128
129 @mock.patch(
130 "uaclient.config.UAConfig.is_attached",
131 new_callable=mock.PropertyMock,
132 return_value=True,
133 )
134 @mock.patch("lib.upgrade_lts_contract.parse_os_release")
135 @mock.patch("lib.upgrade_lts_contract.subp")
70 @mock.patch("lib.upgrade_lts_contract.process_entitlements_delta")136 @mock.patch("lib.upgrade_lts_contract.process_entitlements_delta")
71 @mock.patch("lib.upgrade_lts_contract.time.sleep")137 @mock.patch("lib.upgrade_lts_contract.time.sleep")
72 def test_upgrade_contract_when_apt_lock_is_held(138 def test_upgrade_contract_when_apt_lock_is_held(
diff --git a/uaclient/tests/test_util.py b/uaclient/tests/test_util.py
index 35bd8c0..99a7aa2 100644
--- a/uaclient/tests/test_util.py
+++ b/uaclient/tests/test_util.py
@@ -474,57 +474,244 @@ class TestGetPlatformInfo:
474 assert expected == util.get_platform_info.__wrapped__()474 assert expected == util.get_platform_info.__wrapped__()
475475
476476
477class TestApplySeriesOverrides:477class TestApplyContractOverrides:
478 @pytest.mark.parametrize(
479 "override_selector,expected_weight",
480 (
481 ({"selector1": "valueX", "selector2": "valueZ"}, 0),
482 ({"selector1": "valueA", "selector2": "valueZ"}, 0),
483 ({"selector1": "valueX", "selector2": "valueB"}, 0),
484 ({"selector1": "valueA"}, 1),
485 ({"selector2": "valueB"}, 2),
486 ({"selector1": "valueA", "selector2": "valueB"}, 3),
487 ),
488 )
489 def test_get_override_weight(self, override_selector, expected_weight):
490 selector_values = {"selector1": "valueA", "selector2": "valueB"}
491 selector_weights = {"selector1": 1, "selector2": 2}
492 with mock.patch(
493 "uaclient.util.OVERRIDE_SELECTOR_WEIGHTS", selector_weights
494 ):
495 assert expected_weight == util._get_override_weight(
496 override_selector, selector_values
497 )
498
478 def test_error_on_non_entitlement_dict(self):499 def test_error_on_non_entitlement_dict(self):
479 """Raise a runtime error when seeing invalid dict type."""500 """Raise a runtime error when seeing invalid dict type."""
480 with pytest.raises(RuntimeError) as exc:501 with pytest.raises(RuntimeError) as exc:
481 util.apply_series_overrides({"some": "dict"})502 util.apply_contract_overrides({"some": "dict"})
482 error = (503 error = (
483 'Expected entitlement access dict. Missing "entitlement" key:'504 'Expected entitlement access dict. Missing "entitlement" key:'
484 " {'some': 'dict'}"505 " {'some': 'dict'}"
485 )506 )
486 assert error == str(exc.value)507 assert error == str(exc.value)
487508
509 @pytest.mark.parametrize("include_overrides", (True, False))
488 @mock.patch(510 @mock.patch(
489 "uaclient.util.get_platform_info", return_value={"series": "xenial"}511 "uaclient.util.get_platform_info", return_value={"series": "ubuntuX"}
490 )512 )
491 def test_mutates_orig_access_dict(self, _):513 @mock.patch(
492 """Mutate orig_access dict when called."""514 "uaclient.clouds.identity.get_cloud_type", return_value=(None, "")
515 )
516 def test_return_same_dict_when_no_overrides_match(
517 self, _m_cloud_type, _m_platform_info, include_overrides
518 ):
493 orig_access = {519 orig_access = {
494 "entitlement": {520 "entitlement": {
495 "a": {"a1": "av1", "a2": {"aa2": "aav2"}},521 "affordances": {"some_affordance": ["ubuntuX"]},
496 "b": "b1",522 "directives": {"some_directive": ["ubuntuX"]},
497 "c": "c1",523 "obligations": {"some_obligation": False},
524 }
525 }
526 # exactly the same
527 expected = {
528 "entitlement": {
529 "affordances": {"some_affordance": ["ubuntuX"]},
530 "directives": {"some_directive": ["ubuntuX"]},
531 "obligations": {"some_obligation": False},
532 }
533 }
534 if include_overrides:
535 orig_access["entitlement"].update(
536 {
537 "series": {
538 "dontMatch": {
539 "affordances": {
540 "some_affordance": ["ubuntuX-series-overriden"]
541 }
542 }
543 },
544 "overrides": [
545 {
546 "selector": {"series": "dontMatch"},
547 "affordances": {
548 "some_affordance": ["ubuntuX-series-overriden"]
549 },
550 },
551 {
552 "selector": {"cloud": "dontMatch"},
553 "affordances": {
554 "some_affordance": ["ubuntuX-cloud-overriden"]
555 },
556 },
557 ],
558 }
559 )
560
561 util.apply_contract_overrides(orig_access)
562 assert expected == orig_access
563
564 @mock.patch(
565 "uaclient.util.get_platform_info", return_value={"series": "ubuntuX"}
566 )
567 def test_missing_keys_are_included(self, _m_platform_info):
568 orig_access = {
569 "entitlement": {
570 "series": {"ubuntuX": {"directives": {"suites": ["ubuntuX"]}}}
571 }
572 }
573 expected = {"entitlement": {"directives": {"suites": ["ubuntuX"]}}}
574
575 util.apply_contract_overrides(orig_access)
576
577 assert expected == orig_access
578
579 @pytest.mark.parametrize(
580 "series_selector,cloud_selector,series_cloud_selector,expected_value",
581 (
582 # apply_overrides_when_only_series_match
583 ("no-match", "no-match", "no-match", "old_series_overriden"),
584 # series selector is applied over old series override
585 ("ubuntuX", "no-match", "no-match", "series_overriden"),
586 # cloud selector is applied over series override
587 ("no-match", "cloudX", "no-match", "cloud_overriden"),
588 # cloud selector is applied over series selector
589 ("ubuntuX", "cloudX", "no-match", "cloud_overriden"),
590 # cloud and series together are applied over others
591 ("ubuntuX", "cloudX", "cloudX", "both_overriden"),
592 ),
593 )
594 @mock.patch(
595 "uaclient.util.get_platform_info", return_value={"series": "ubuntuX"}
596 )
597 @mock.patch(
598 "uaclient.clouds.identity.get_cloud_type",
599 return_value=("cloudX", None),
600 )
601 def test_applies_contract_overrides_respecting_weight(
602 self,
603 _m_cloud_type,
604 _m_platform_info,
605 series_selector,
606 cloud_selector,
607 series_cloud_selector,
608 expected_value,
609 ):
610 """Apply the expected overrides to orig_access dict when called."""
611 orig_access = {
612 "entitlement": {
613 "affordances": {"some_affordance": ["original_affordance"]},
498 "series": {614 "series": {
499 "trusty": {"a": "t1"},615 "ubuntuX": {
500 "xenial": {"a": {"a2": {"aa2": "xxv2"}}, "b": "bx1"},616 "affordances": {
617 "some_affordance": ["old_series_overriden"]
618 }
619 }
501 },620 },
621 "overrides": [
622 {
623 "selector": {"series": series_selector},
624 "affordances": {
625 "some_affordance": ["series_overriden"]
626 },
627 },
628 {
629 "selector": {"cloud": cloud_selector},
630 "affordances": {
631 "some_affordance": ["cloud_overriden"]
632 },
633 },
634 {
635 "selector": {
636 "series": series_selector,
637 "cloud": series_cloud_selector,
638 },
639 "affordances": {"some_affordance": ["both_overriden"]},
640 },
641 ],
502 }642 }
503 }643 }
644
504 expected = {645 expected = {
505 "entitlement": {646 "entitlement": {
506 "a": {"a1": "av1", "a2": {"aa2": "xxv2"}},647 "affordances": {"some_affordance": [expected_value]}
507 "b": "bx1",
508 "c": "c1",
509 }648 }
510 }649 }
511 util.apply_series_overrides(orig_access)650
651 util.apply_contract_overrides(orig_access)
512 assert orig_access == expected652 assert orig_access == expected
513653
514 @mock.patch(654 @mock.patch(
515 "uaclient.util.get_platform_info", return_value={"series": "xenial"}655 "uaclient.util.get_platform_info", return_value={"series": "ubuntuX"}
656 )
657 @mock.patch(
658 "uaclient.clouds.identity.get_cloud_type",
659 return_value=("cloudX", None),
516 )660 )
517 def test_missing_keys_are_handled(self, _):661 def test_different_overrides_applied_together(
662 self, _m_cloud_type, _m_platform_info
663 ):
664 """Apply different overrides from different matching selectors."""
518 orig_access = {665 orig_access = {
519 "entitlement": {666 "entitlement": {
520 "series": {"xenial": {"directives": {"suites": ["xenial"]}}}667 "affordances": {"some_affordance": ["original_affordance"]},
668 "directives": {"some_directive": ["original_directive"]},
669 "obligations": {"some_obligation": False},
670 "series": {
671 "ubuntuX": {
672 "affordances": {
673 "new_affordance": ["new_affordance_value"]
674 }
675 }
676 },
677 "overrides": [
678 {
679 "selector": {"series": "ubuntuX"},
680 "affordances": {
681 "some_affordance": ["series_overriden"]
682 },
683 },
684 {
685 "selector": {"cloud": "cloudX"},
686 "directives": {"some_directive": ["cloud_overriden"]},
687 },
688 {
689 "selector": {"series": "ubuntuX", "cloud": "cloudX"},
690 "obligations": {
691 "new_obligation": True,
692 "some_obligation": True,
693 },
694 },
695 ],
521 }696 }
522 }697 }
523 expected = {"entitlement": {"directives": {"suites": ["xenial"]}}}
524698
525 util.apply_series_overrides(orig_access)699 expected = {
700 "entitlement": {
701 "affordances": {
702 "new_affordance": ["new_affordance_value"],
703 "some_affordance": ["series_overriden"],
704 },
705 "directives": {"some_directive": ["cloud_overriden"]},
706 "obligations": {
707 "new_obligation": True,
708 "some_obligation": True,
709 },
710 }
711 }
526712
527 assert expected == orig_access713 util.apply_contract_overrides(orig_access)
714 assert orig_access == expected
528715
529716
530class TestGetMachineId:717class TestGetMachineId:
@@ -1263,13 +1450,18 @@ class TestShouldReboot:
1263 assert 1 == m_load_file.call_count1450 assert 1 == m_load_file.call_count
12641451
1265 @pytest.mark.parametrize(1452 @pytest.mark.parametrize(
1266 "installed_pkgs,reboot_required_pkgs,expected_ret",1453 "installed_pkgs,installed_pkgs_regex,reboot_required_pkgs,"
1454 "expected_ret",
1267 (1455 (
1268 (set(["a", "b", "c"]), "", False),1456 (set(["a", "b", "c"]), None, "", False),
1269 (set(["a", "b", "c"]), "a", True),1457 (set(["a", "b", "c"]), None, "a", True),
1270 (set(["a", "b", "c"]), "a\ne", True),1458 (set(["a", "b", "c"]), None, "a\ne", True),
1271 (set(["a", "b", "c"]), "d\ne", False),1459 (set(["a", "b", "c"]), None, "d\ne", False),
1272 (None, "a\ne", True),1460 (set(["a", "b", "c"]), set(["t.."]), "a\ne", True),
1461 (set(["a", "b", "c"]), set(["t.."]), "one\ntwo", True),
1462 (None, set(["^t..$"]), "one\ntwo", True),
1463 (None, set(["^t..$"]), "one\nthree", False),
1464 (None, None, "a\ne", True),
1273 ),1465 ),
1274 )1466 )
1275 @mock.patch("os.path.exists")1467 @mock.patch("os.path.exists")
@@ -1279,11 +1471,13 @@ class TestShouldReboot:
1279 m_load_file,1471 m_load_file,
1280 m_path,1472 m_path,
1281 installed_pkgs,1473 installed_pkgs,
1474 installed_pkgs_regex,
1282 reboot_required_pkgs,1475 reboot_required_pkgs,
1283 expected_ret,1476 expected_ret,
1284 ):1477 ):
1285 m_path.return_value = True1478 m_path.return_value = True
1286 m_load_file.return_value = reboot_required_pkgs1479 m_load_file.return_value = reboot_required_pkgs
1287 assert expected_ret == util.should_reboot(1480 assert expected_ret == util.should_reboot(
1288 installed_pkgs=installed_pkgs1481 installed_pkgs=installed_pkgs,
1482 installed_pkgs_regex=installed_pkgs_regex,
1289 )1483 )
diff --git a/uaclient/util.py b/uaclient/util.py
index 674f302..346f202 100644
--- a/uaclient/util.py
+++ b/uaclient/util.py
@@ -44,6 +44,8 @@ PROXY_VALIDATION_APT_HTTPS_URL = "https://esm.ubuntu.com"
44PROXY_VALIDATION_SNAP_HTTP_URL = "http://api.snapcraft.io"44PROXY_VALIDATION_SNAP_HTTP_URL = "http://api.snapcraft.io"
45PROXY_VALIDATION_SNAP_HTTPS_URL = "https://api.snapcraft.io"45PROXY_VALIDATION_SNAP_HTTPS_URL = "https://api.snapcraft.io"
4646
47OVERRIDE_SELECTOR_WEIGHTS = {"series_overrides": 1, "series": 2, "cloud": 3}
48
47event = event_logger.get_event_logger()49event = event_logger.get_event_logger()
4850
4951
@@ -100,7 +102,43 @@ class DatetimeAwareJSONDecoder(json.JSONDecoder):
100 return o102 return o
101103
102104
103def apply_series_overrides(105def _get_override_weight(
106 override_selector: Dict[str, str], selector_values: Dict[str, str]
107) -> int:
108 override_weight = 0
109 for selector, value in override_selector.items():
110 if (selector, value) not in selector_values.items():
111 return 0
112 override_weight += OVERRIDE_SELECTOR_WEIGHTS[selector]
113
114 return override_weight
115
116
117def _select_overrides(
118 entitlement: Dict[str, Any], series_name: str, cloud_type: str
119) -> Dict[int, Dict[str, Any]]:
120 overrides = {}
121
122 selector_values = {"series": series_name, "cloud": cloud_type}
123
124 series_overrides = entitlement.pop("series", {}).pop(series_name, {})
125 if series_overrides:
126 overrides[
127 OVERRIDE_SELECTOR_WEIGHTS["series_overrides"]
128 ] = series_overrides
129
130 general_overrides = entitlement.pop("overrides", [])
131 for override in general_overrides:
132 weight = _get_override_weight(
133 override.pop("selector"), selector_values
134 )
135 if weight:
136 overrides[weight] = override
137
138 return overrides
139
140
141def apply_contract_overrides(
104 orig_access: Dict[str, Any], series: str = None142 orig_access: Dict[str, Any], series: str = None
105) -> None:143) -> None:
106 """Apply series-specific overrides to an entitlement dict.144 """Apply series-specific overrides to an entitlement dict.
@@ -117,23 +155,30 @@ def apply_series_overrides(
117155
118 :param orig_access: Dict with original entitlement access details156 :param orig_access: Dict with original entitlement access details
119 """157 """
158 from uaclient.clouds.identity import get_cloud_type
159
120 if not all([isinstance(orig_access, dict), "entitlement" in orig_access]):160 if not all([isinstance(orig_access, dict), "entitlement" in orig_access]):
121 raise RuntimeError(161 raise RuntimeError(
122 'Expected entitlement access dict. Missing "entitlement" key:'162 'Expected entitlement access dict. Missing "entitlement" key:'
123 " {}".format(orig_access)163 " {}".format(orig_access)
124 )164 )
165
125 series_name = get_platform_info()["series"] if series is None else series166 series_name = get_platform_info()["series"] if series is None else series
167 cloud_type, _ = get_cloud_type()
126 orig_entitlement = orig_access.get("entitlement", {})168 orig_entitlement = orig_access.get("entitlement", {})
127 overrides = orig_entitlement.pop("series", {}).pop(series_name, {})169
128 for key, value in overrides.items():170 overrides = _select_overrides(orig_entitlement, series_name, cloud_type)
129 current = orig_access["entitlement"].get(key)171
130 if isinstance(current, dict):172 for _weight, overrides_to_apply in sorted(overrides.items()):
131 # If the key already exists and is a dict, update that dict using173 for key, value in overrides_to_apply.items():
132 # the override174 current = orig_access["entitlement"].get(key)
133 current.update(value)175 if isinstance(current, dict):
134 else:176 # If the key already exists and is a dict,
135 # Otherwise, replace it wholesale177 # update that dict using the override
136 orig_access["entitlement"][key] = value178 current.update(value)
179 else:
180 # Otherwise, replace it wholesale
181 orig_access["entitlement"][key] = value
137182
138183
139def del_file(path: str) -> None:184def del_file(path: str) -> None:
@@ -431,13 +476,16 @@ def prompt_choices(msg: str = "", valid_choices: List[str] = []) -> str:
431 return value476 return value
432477
433478
434def prompt_for_confirmation(msg: str = "", assume_yes: bool = False) -> bool:479def prompt_for_confirmation(
480 msg: str = "", assume_yes: bool = False, default: bool = False
481) -> bool:
435 """482 """
436 Display a confirmation prompt, returning a bool indicating the response483 Display a confirmation prompt, returning a bool indicating the response
437484
438 :param msg: String custom prompt text to emit from input call.485 :param msg: String custom prompt text to emit from input call.
439 :param assume_yes: Boolean set True to skip confirmation input and return486 :param assume_yes: Boolean set True to skip confirmation input and return
440 True.487 True.
488 :param default: Boolean to return when user doesn't enter any text
441489
442 This function will only prompt a single time, and defaults to "no" (i.e. it490 This function will only prompt a single time, and defaults to "no" (i.e. it
443 returns False).491 returns False).
@@ -446,8 +494,10 @@ def prompt_for_confirmation(msg: str = "", assume_yes: bool = False) -> bool:
446 return True494 return True
447 if not msg:495 if not msg:
448 msg = status.PROMPT_YES_NO496 msg = status.PROMPT_YES_NO
449 value = input(msg)497 value = input(msg).lower().strip()
450 if value.lower().strip() in ["y", "yes"]:498 if value == "":
499 return default
500 if value in ["y", "yes"]:
451 return True501 return True
452 return False502 return False
453503
@@ -756,14 +806,26 @@ def redact_sensitive_logs(
756 return redacted_log806 return redacted_log
757807
758808
759def should_reboot(installed_pkgs: Optional[Set[str]] = None) -> bool:809def should_reboot(
810 installed_pkgs: Optional[Set[str]] = None,
811 installed_pkgs_regex: Optional[Set[str]] = None,
812) -> bool:
760 """Check if the system needs to be rebooted.813 """Check if the system needs to be rebooted.
761814
762 :param installed_pkgs: If provided, verify if the any packages in815 :param installed_pkgs: If provided, verify if the any packages in
763 the list are present on /var/run/reboot-required.pkgs. If that816 the list are present on /var/run/reboot-required.pkgs. If that
764 param is provided, we will only return true if we have the817 param is provided, we will only return true if we have the
765 reboot-required marker file and any package in reboot-required.pkgs818 reboot-required marker file and any package in reboot-required.pkgs
766 file.819 file. When both installed_pkgs and installed_pkgs_regex are
820 provided, they act as an OR, so only one of the two lists must have
821 a match to return True.
822 :param installed_pkgs_regex: If provided, verify if the any regex in
823 the list matches any line in /var/run/reboot-required.pkgs. If that
824 param is provided, we will only return true if we have the
825 reboot-required marker file and any match in reboot-required.pkgs
826 file. When both installed_pkgs and installed_pkgs_regex are
827 provided, they act as an OR, so only one of the two lists must have
828 a match to return True.
767 """829 """
768830
769 # If the reboot marker file doesn't exist, we don't even831 # If the reboot marker file doesn't exist, we don't even
@@ -773,7 +835,7 @@ def should_reboot(installed_pkgs: Optional[Set[str]] = None) -> bool:
773835
774 # If there is no installed_pkgs to check, we will rely only836 # If there is no installed_pkgs to check, we will rely only
775 # on the existence of the reboot marker file837 # on the existence of the reboot marker file
776 if installed_pkgs is None:838 if installed_pkgs is None and installed_pkgs_regex is None:
777 return True839 return True
778840
779 try:841 try:
@@ -784,8 +846,18 @@ def should_reboot(installed_pkgs: Optional[Set[str]] = None) -> bool:
784 # If the file doesn't exist, we will default to the846 # If the file doesn't exist, we will default to the
785 # reboot marker file847 # reboot marker file
786 return True848 return True
787 else:849
788 return len(installed_pkgs.intersection(reboot_required_pkgs)) != 0850 if installed_pkgs is not None:
851 if len(installed_pkgs.intersection(reboot_required_pkgs)) != 0:
852 return True
853
854 if installed_pkgs_regex is not None:
855 for pkg_name in reboot_required_pkgs:
856 for pkg_regex in installed_pkgs_regex:
857 if re.search(pkg_regex, pkg_name):
858 return True
859
860 return False
789861
790862
791def is_installed(package_name: str) -> bool:863def is_installed(package_name: str) -> bool:
diff --git a/uaclient/version.py b/uaclient/version.py
index f65a60c..b99afa0 100644
--- a/uaclient/version.py
+++ b/uaclient/version.py
@@ -8,7 +8,7 @@ import os.path
88
9from uaclient import exceptions, util9from uaclient import exceptions, util
1010
11__VERSION__ = "27.7"11__VERSION__ = "27.8"
12PACKAGED_VERSION = "@@PACKAGED_VERSION@@"12PACKAGED_VERSION = "@@PACKAGED_VERSION@@"
13VERSION_TMPL = "{version}{feature_suffix}"13VERSION_TMPL = "{version}{feature_suffix}"
1414

Subscribers

People subscribed via source and target branches

to status/vote changes: