diff -Nru ubuntu-advantage-tools-27.7~20.04.1/debian/changelog ubuntu-advantage-tools-27.8~20.04.1/debian/changelog --- ubuntu-advantage-tools-27.7~20.04.1/debian/changelog 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/debian/changelog 2022-04-14 18:32:40.000000000 +0000 @@ -1,8 +1,29 @@ -ubuntu-advantage-tools (27.7~20.04.1) focal; urgency=medium +ubuntu-advantage-tools (27.8~20.04.1) focal; urgency=medium - * Backport new upstream release: (LP: #1964028) to focal + * Backport new upstream release: (LP: #1969125) to focal - -- Grant Orndorff Thu, 10 Mar 2022 12:17:34 -0500 + -- Lucas Moura Thu, 14 Apr 2022 15:32:40 -0300 + +ubuntu-advantage-tools (27.8~22.04.1) jammy; urgency=medium + + * New upstream release 27.8 (LP: #1969125) + - entitlements: apply overrides from the contract response + - fips: + + unhold fips packages when enabling fips-updates + + Automatically disable fips service before enabling fips-updates + + unhold more packages when enabling fips + - lib: fix upgrade script for unsupported releases (LP: #1968067) + - realtime: add support for realtime kernel beta service on Jammy + + -- Lucas Moura Wed, 13 Apr 2022 18:17:02 -0300 + +ubuntu-advantage-tools (27.7.1~22.04.1) jammy; urgency=medium + + * fips: + - make fips service incompatible with fips-updates + - unhold more packages when enabling fips + + -- Lucas Moura Thu, 31 Mar 2022 16:18:36 -0300 ubuntu-advantage-tools (27.7~22.04.1) jammy; urgency=medium diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/attached_commands.feature ubuntu-advantage-tools-27.8~20.04.1/features/attached_commands.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/attached_commands.feature 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/attached_commands.feature 2022-04-14 18:32:40.000000000 +0000 @@ -129,9 +129,9 @@ Examples: ubuntu release | release | valid_services | - | xenial | cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch, ros,\nros-updates. | - | bionic | cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch, ros,\nros-updates. | - | focal | cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, ros,\nros-updates, usg. | + | xenial | cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch,\nrealtime-kernel, ros, ros-updates. | + | bionic | cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch,\nrealtime-kernel, ros, ros-updates. | + | focal | cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, realtime-kernel,\nros, ros-updates, usg. | @series.xenial @series.bionic @@ -148,8 +148,8 @@ And stderr matches regexp: """ Cannot disable unknown service 'foobar'. - Try cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch, ros, - ros-updates. + Try cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch, + realtime-kernel, ros, ros-updates. """ And I verify that running `ua disable esm-infra` `as non-root` exits `1` And stderr matches regexp: @@ -187,8 +187,8 @@ And stderr matches regexp: """ Cannot disable unknown service 'foobar'. - Try cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, ros, - ros-updates, usg. + Try cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, realtime-kernel, + ros, ros-updates, usg. """ And I verify that running `ua disable esm-infra` `as non-root` exits `1` And stderr matches regexp: @@ -231,7 +231,7 @@ When I run `ua status --all` as non-root Then stdout matches regexp: """ - SERVICE AVAILABLE DESCRIPTION + SERVICE +AVAILABLE DESCRIPTION cc-eal + +Common Criteria EAL2 Provisioning Packages """ Then stdout matches regexp: @@ -241,6 +241,7 @@ fips + +NIST-certified core packages fips-updates + +NIST-certified core packages with priority security updates livepatch +yes +Canonical Livepatch service + realtime-kernel + +Beta-version Ubuntu Kernel with PREEMPT_RT patches ros + +Security Updates for the Robot Operating System ros-updates + +All Updates for the Robot Operating System """ @@ -280,10 +281,10 @@ """ Examples: ubuntu release - | release | esm-apps | cc-eal | cis | fips | fips-update | ros | cis_or_usg | - | xenial | yes | yes | yes | yes | yes | yes | cis | - | bionic | yes | yes | yes | yes | yes | yes | cis | - | focal | yes | no | yes | yes | yes | no | usg | + | release | esm-apps | cc-eal | cis | fips | fips-update | ros | cis_or_usg | realtime-kernel | + | xenial | yes | yes | yes | yes | yes | yes | cis | no | + | bionic | yes | yes | yes | yes | yes | yes | cis | no | + | focal | yes | no | yes | yes | yes | no | usg | no | @series.all @uses.config.machine_type.lxd.container @@ -361,8 +362,8 @@ And I run `ua status --all` with sudo Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION - cc-eal no + SERVICE +ENTITLED STATUS DESCRIPTION + cc-eal +no """ When I run `ua --version` as non-root Then I will see the uaclient version on stdout with features ` +disable_auto_attach +machine_token_overlay -other` @@ -403,8 +404,8 @@ And stderr matches regexp: """ Cannot disable unknown service 'foobar'. - Try cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch, ros, - ros-updates. + Try cc-eal, cis, esm-apps, esm-infra, fips, fips-updates, livepatch, + realtime-kernel, ros, ros-updates. """ When I run `ua status` with sudo Then stdout matches regexp: @@ -449,8 +450,8 @@ And stderr matches regexp: """ Cannot disable unknown service 'foobar'. - Try cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, ros, - ros-updates, usg. + Try cc-eal, esm-apps, esm-infra, fips, fips-updates, livepatch, realtime-kernel, + ros, ros-updates, usg. """ When I run `ua status` with sudo Then stdout matches regexp: @@ -558,6 +559,8 @@ \(https://ubuntu.com/security/certifications#fips\) - livepatch: Canonical Livepatch service \(https://ubuntu.com/security/livepatch\) + - realtime-kernel: Beta-version Ubuntu Kernel with PREEMPT_RT patches + \(https://ubuntu.com/realtime-kernel\) - ros-updates: All Updates for the Robot Operating System \(https://ubuntu.com/robotics/ros-esm\) - ros: Security Updates for the Robot Operating System @@ -657,6 +660,8 @@ \(https://ubuntu.com/security/certifications#fips\) - livepatch: Canonical Livepatch service \(https://ubuntu.com/security/livepatch\) + - realtime-kernel: Beta-version Ubuntu Kernel with PREEMPT_RT patches + \(https://ubuntu.com/realtime-kernel\) - ros-updates: All Updates for the Robot Operating System \(https://ubuntu.com/robotics/ros-esm\) - ros: Security Updates for the Robot Operating System diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/attached_enable.feature ubuntu-advantage-tools-27.8~20.04.1/features/attached_enable.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/attached_enable.feature 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/attached_enable.feature 2022-04-14 18:32:40.000000000 +0000 @@ -669,7 +669,7 @@ And stdout is a json matching the `ua_operation` schema And I will see the following on stdout: """ - {"_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": []} + {"_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": []} """ @slow @@ -693,6 +693,7 @@ Then I will see the following on stdout """ One moment, checking your subscription first + Disabling incompatible service: Livepatch Updating package lists Installing FIPS packages FIPS enabled @@ -761,21 +762,21 @@ And I run `ua status --all` as non-root Then stdout matches regexp """ - ros yes disabled Security Updates for the Robot Operating System + ros +yes disabled Security Updates for the Robot Operating System """ When I run `ua enable ros --assume-yes --beta` with sudo And I run `ua status --all` as non-root Then stdout matches regexp """ - ros yes enabled Security Updates for the Robot Operating System + ros +yes enabled Security Updates for the Robot Operating System """ And stdout matches regexp """ - esm-apps yes enabled UA Apps: Extended Security Maintenance \(ESM\) + esm-apps +yes enabled UA Apps: Extended Security Maintenance \(ESM\) """ And stdout matches regexp """ - esm-infra yes enabled UA Infra: Extended Security Maintenance \(ESM\) + esm-infra +yes enabled UA Infra: Extended Security Maintenance \(ESM\) """ When I verify that running `ua disable esm-apps` `with sudo` and stdin `N` exits `1` Then stdout matches regexp @@ -793,11 +794,11 @@ When I run `ua status --all` as non-root Then stdout matches regexp """ - ros yes disabled Security Updates for the Robot Operating System + ros +yes disabled Security Updates for the Robot Operating System """ And stdout matches regexp """ - esm-apps yes disabled UA Apps: Extended Security Maintenance \(ESM\) + esm-apps +yes disabled UA Apps: Extended Security Maintenance \(ESM\) """ When I verify that running `ua enable ros --beta` `with sudo` and stdin `N` exits `1` Then stdout matches regexp @@ -818,15 +819,15 @@ When I run `ua status --all` as non-root Then stdout matches regexp """ - ros yes enabled Security Updates for the Robot Operating System + ros +yes enabled Security Updates for the Robot Operating System """ And stdout matches regexp """ - esm-apps yes enabled UA Apps: Extended Security Maintenance \(ESM\) + esm-apps +yes enabled UA Apps: Extended Security Maintenance \(ESM\) """ And stdout matches regexp """ - esm-infra yes enabled UA Infra: Extended Security Maintenance \(ESM\) + esm-infra +yes enabled UA Infra: Extended Security Maintenance \(ESM\) """ When I run `apt-cache policy` as non-root Then apt-cache policy for the following url has permission `500` @@ -840,7 +841,7 @@ And I run `ua status --all` as non-root Then stdout matches regexp """ - ros-updates yes enabled All Updates for the Robot Operating System + ros-updates +yes enabled All Updates for the Robot Operating System """ When I run `apt-cache policy` as non-root Then apt-cache policy for the following url has permission `500` @@ -869,11 +870,11 @@ When I run `ua status --all` as non-root Then stdout matches regexp """ - ros-updates yes enabled All Updates for the Robot Operating System + ros-updates +yes enabled All Updates for the Robot Operating System """ And stdout matches regexp """ - ros yes enabled Security Updates for the Robot Operating System + ros +yes enabled Security Updates for the Robot Operating System """ When I run `ua disable ros-updates --assume-yes` with sudo When I run `ua disable ros --assume-yes` with sudo @@ -883,19 +884,19 @@ When I run `ua status --all` as non-root Then stdout matches regexp """ - ros-updates yes enabled All Updates for the Robot Operating System + ros-updates +yes enabled All Updates for the Robot Operating System """ And stdout matches regexp """ - ros yes enabled Security Updates for the Robot Operating System + ros +yes enabled Security Updates for the Robot Operating System """ And stdout matches regexp """ - esm-apps yes enabled UA Apps: Extended Security Maintenance \(ESM\) + esm-apps +yes enabled UA Apps: Extended Security Maintenance \(ESM\) """ And stdout matches regexp """ - esm-infra yes enabled UA Infra: Extended Security Maintenance \(ESM\) + esm-infra +yes enabled UA Infra: Extended Security Maintenance \(ESM\) """ When I run `ua detach` `with sudo` and stdin `y` Then stdout matches regexp: @@ -911,3 +912,88 @@ | release | ros-security-source | ros-updates-source | | xenial | https://esm.ubuntu.com/ros/ubuntu xenial-security/main | https://esm.ubuntu.com/ros-updates/ubuntu xenial-updates/main | | bionic | https://esm.ubuntu.com/ros/ubuntu bionic-security/main | https://esm.ubuntu.com/ros-updates/ubuntu bionic-updates/main | + + # Overall test for overrides; in the future, when many services + # have overrides, we can consider removing this + # FIPS is a good choice because we expect to have it + @series.focal + @uses.config.machine_type.aws.generic + Scenario: Cloud overrides for a generic aws Focal instance + Given a `focal` machine with ubuntu-advantage-tools installed + When I create the file `/tmp/machine-token-overlay.json` with the following: + """ + { + "machineTokenInfo": { + "contractInfo": { + "resourceEntitlements": [ + { + "type": "fips", + "entitled": true, + "affordances": { + "architectures": [ + "amd64", + "ppc64el", + "ppc64le", + "s390x", + "x86_64" + ], + "series": [ + "xenial", + "bionic", + "focal" + ] + }, + "directives": { + "additionalPackages": [ + "ubuntu-fips" + ], + "aptKey": "E23341B2A1467EDBF07057D6C1997C40EDE22758", + "aptURL": "https://esm.ubuntu.com/fips", + "suites": [ + "xenial", + "bionic", + "focal" + ] + }, + "obligations": { + "enableByDefault": false + }, + "overrides": [ + { + "selector": { + "series": "focal" + }, + "directives": { + "additionalPackages": [ + "some-package-focal" + ] + } + }, + { + "selector": { + "cloud": "aws" + }, + "directives": { + "additionalPackages": [ + "some-package-aws" + ] + } + } + ] + } + ] + } + } + } + """ + And I append the following on uaclient config: + """ + features: + machine_token_overlay: "/tmp/machine-token-overlay.json" + """ + And I attach `contract_token` with sudo + And I verify that running `ua enable fips --assume-yes` `with sudo` exits `1` + Then stderr matches regexp: + """ + Stderr: E: Unable to locate package some-package-aws + """ diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/attach_validtoken.feature ubuntu-advantage-tools-27.8~20.04.1/features/attach_validtoken.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/attach_validtoken.feature 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/attach_validtoken.feature 2022-04-14 18:32:40.000000000 +0000 @@ -11,7 +11,7 @@ And I run `ua status --all` as non-root Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes +n/a +Common Criteria EAL2 Provisioning Packages cis +yes +n/a +Security compliance and audit tools esm-apps +yes +n/a +UA Apps: Extended Security Maintenance \(ESM\) @@ -58,7 +58,7 @@ """ And stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ And stdout matches regexp: @@ -315,7 +315,7 @@ """ And stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ And stdout matches regexp: @@ -375,7 +375,7 @@ """ And stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ And stdout matches regexp: @@ -435,7 +435,7 @@ """ And stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ And stdout matches regexp: @@ -477,7 +477,7 @@ When I run `ua status` with sudo Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ And stdout matches regexp: diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/aws-ids.yaml ubuntu-advantage-tools-27.8~20.04.1/features/aws-ids.yaml --- ubuntu-advantage-tools-27.7~20.04.1/features/aws-ids.yaml 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/aws-ids.yaml 2022-04-14 18:32:40.000000000 +0000 @@ -3,3 +3,4 @@ focal: ami-0489b8bdbbf3a3b32 xenial: ami-011bcfe2bea365b6a xenial-fips: ami-077e4c339a098fc9f +focal-fips: ami-02782bf2569bf457c diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/azure-ids.yaml ubuntu-advantage-tools-27.8~20.04.1/features/azure-ids.yaml --- ubuntu-advantage-tools-27.7~20.04.1/features/azure-ids.yaml 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/azure-ids.yaml 2022-04-01 13:27:49.000000000 +0000 @@ -3,3 +3,4 @@ xenial: "Canonical:0001-com-ubuntu-pro-xenial:pro-16_04-lts" bionic-fips: "Canonical:0001-com-ubuntu-pro-bionic-fips:pro-fips-18_04" xenial-fips: "Canonical:0001-com-ubuntu-pro-xenial-fips:pro-fips-16_04-private" +focal-fips: "Canonical:0001-com-ubuntu-pro-focal-fips:pro-fips-20_04" diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/enable_fips_vm.feature ubuntu-advantage-tools-27.8~20.04.1/features/enable_fips_vm.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/enable_fips_vm.feature 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/enable_fips_vm.feature 2022-04-14 18:32:40.000000000 +0000 @@ -462,14 +462,11 @@ | focal | FIPS Updates | fips-updates |https://esm.ubuntu.com/fips-updates/ubuntu focal-updates/main | @slow - @series.xenial - @series.bionic + @series.lts @uses.config.machine_type.lxd.vm Scenario Outline: Attached enable fips-updates on fips enabled vm Given a `` machine with ubuntu-advantage-tools installed When I attach `contract_token` with sudo - And I run `ua disable livepatch` with sudo - 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] And I run `ua enable fips --assume-yes` with sudo Then stdout matches regexp: """ @@ -484,47 +481,61 @@ fips +yes enabled """ When I reboot the `` machine - And I run `ua enable fips-updates --assume-yes` with sudo + And I run `uname -r` as non-root Then stdout matches regexp: """ - Updating package lists - Installing FIPS Updates packages - FIPS Updates enabled - A reboot is required to complete install + fips """ - When I run `ua status --all` with sudo + When I verify that running `ua enable fips-updates --assume-yes` `with sudo` exits `0` Then stdout matches regexp: """ - fips +yes n/a - """ - And stdout matches regexp: + One moment, checking your subscription first + Disabling incompatible service: FIPS + Updating package lists + Installing FIPS Updates packages + FIPS Updates enabled + A reboot is required to complete install. """ - fips-updates +yes enabled + When I run `ua status --all` with sudo + Then stdout matches regexp: + """ + fips-updates +yes enabled + """ + And stdout matches regexp: + """ + fips +yes n/a + """ + When I reboot the `` machine + And I run `ua enable livepatch` with sudo + And I run `ua status --all` with sudo + Then stdout matches regexp: + """ + fips-updates +yes enabled + """ + And stdout matches regexp: + """ + fips +yes n/a + """ + And stdout matches regexp: + """ + livepatch +yes enabled + """ + When I run `uname -r` as non-root + Then stdout matches regexp: + """ + fips + """ + When I run `cat /proc/sys/crypto/fips_enabled` with sudo + Then I will see the following on stdout: """ - When I reboot the `` machine - Then I verify that running `apt update` `with sudo` exits `0` - And I verify that `ubuntu-fips` is installed from apt source `` - And I verify that `openssh-server` is installed from apt source `` - And I verify that `openssh-client` is installed from apt source `` - And I verify that `strongswan` is installed from apt source `` - And I verify that `openssh-server-hmac` is installed from apt source `` - And I verify that `openssh-client-hmac` is installed from apt source `` - And I verify that `strongswan-hmac` is installed from apt source `` - When I run `uname -r` as non-root - Then stdout matches regexp: - """ - fips + 1 """ - When I run `cat /proc/sys/crypto/fips_enabled` with sudo - Then I will see the following on stdout: - """ - 1 - """ Examples: ubuntu release - | release | fips-apt-source | - | xenial | https://esm.ubuntu.com/fips-updates/ubuntu xenial-updates/main | - | bionic | https://esm.ubuntu.com/fips-updates/ubuntu bionic-updates/main | + | release | + | xenial | + | bionic | + | focal | @slow @series.xenial diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/realtime_kernel.feature ubuntu-advantage-tools-27.8~20.04.1/features/realtime_kernel.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/realtime_kernel.feature 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/realtime_kernel.feature 2022-04-14 18:32:40.000000000 +0000 @@ -0,0 +1,128 @@ +@uses.config.contract_token +Feature: Enable command behaviour when attached to an UA subscription + + @series.jammy + @uses.config.machine_type.lxd.container + Scenario Outline: Enable Real-Time Kernel service in a container + Given a `` machine with ubuntu-advantage-tools installed + When I attach `contract_token` with sudo + Then I verify that running `ua enable realtime-kernel` `as non-root` exits `1` + And I will see the following on stderr: + """ + This command must be run as root (try using sudo). + """ + Then I verify that running `ua enable realtime-kernel --beta` `with sudo` exits `1` + Then I will see the following on stdout: + """ + One moment, checking your subscription first + Cannot install Real-Time Kernel on a container. + """ + Examples: ubuntu release + | release | + | jammy | + + @series.lts + @uses.config.machine_type.lxd.vm + Scenario Outline: Enable Real-Time Kernel service on unsupported release + Given a `` machine with ubuntu-advantage-tools installed + When I attach `contract_token` with sudo + Then I verify that running `ua enable realtime-kernel` `as non-root` exits `1` + And I will see the following on stderr: + """ + This command must be run as root (try using sudo). + """ + Then I verify that running `ua enable realtime-kernel --beta` `with sudo` exits `1` + Then I will see the following on stdout: + """ + One moment, checking your subscription first + Real-Time Kernel is not available for Ubuntu (). + """ + Examples: ubuntu release + | release | version | full_name | + | xenial | 16.04 LTS | Xenial Xerus | + | bionic | 18.04 LTS | Bionic Beaver | + | focal | 20.04 LTS | Focal Fossa | + | jammy | 22.04 | Jammy Jellyfish | + + @series.jammy + @uses.config.machine_type.gcp.generic + Scenario Outline: Enable Real-Time Kernel service + Given a `` machine with ubuntu-advantage-tools installed + When I create the file `/home/ubuntu/machine-token-overlay.json` with the following: + """ + { + "machineTokenInfo": { + "contractInfo": { + "resourceEntitlements": [ + { + "type": "realtime-kernel", + "affordances": { + "series": ["jammy"] + } + } + ] + } + } + } + """ + And I append the following on uaclient config: + """ + features: + machine_token_overlay: "/home/ubuntu/machine-token-overlay.json" + """ + When I attach `contract_token` with sudo + And I run `ua disable livepatch --assume-yes` with sudo + Then I verify that running `ua enable realtime-kernel` `as non-root` exits `1` + And I will see the following on stderr: + """ + This command must be run as root (try using sudo). + """ + Then I verify that running `ua enable realtime-kernel` `with sudo` exits `1` + And stderr matches regexp: + """ + Cannot enable unknown service 'realtime-kernel'. + """ + When I run `ua enable realtime-kernel --beta` `with sudo` and stdin `y` + Then stdout matches regexp: + """ + One moment, checking your subscription first + The real-time kernel is a beta version of the 22.04 Ubuntu kernel with the + PREEMPT_RT patchset integrated for x86_64 and ARM64. + + .*You will not be able to revert to your original kernel after enabling real-time..* + + Do you want to continue\? \[ default = Yes \]: \(Y/n\) Updating package lists + Installing Real-Time Kernel packages + Real-Time Kernel enabled + A reboot is required to complete install. + """ + When I run `apt-cache policy linux-realtime` as non-root + Then stdout does not match regexp: + """ + .*Installed: \(none\) + """ + And stdout matches regexp: + """ + \s* 500 https://esm.ubuntu.com/realtime/ubuntu /main amd64 Packages + """ + When I verify that running `ua enable realtime-kernel --beta` `with sudo` exits `1` + Then stdout matches regexp + """ + One moment, checking your subscription first + Real-Time Kernel is already enabled. + See: sudo ua status + """ + When I reboot the `` machine + When I run `uname -r` as non-root + Then stdout matches regexp: + """ + realtime + """ + When I run `ua disable realtime-kernel` `with sudo` and stdin `y` + Then stdout matches regexp: + """ + This will disable the Real-Time Kernel entitlement but the Real-Time Kernel will remain installed. + """ + Examples: ubuntu release + | release | + | jammy | diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/staging_commands.feature ubuntu-advantage-tools-27.8~20.04.1/features/staging_commands.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/staging_commands.feature 2021-10-01 15:23:59.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/staging_commands.feature 2022-04-14 18:32:40.000000000 +0000 @@ -9,7 +9,7 @@ And I run `ua status --all` as non-root Then stdout matches regexp """ - esm-apps yes enabled UA Apps: Extended Security Maintenance \(ESM\) + esm-apps +yes enabled UA Apps: Extended Security Maintenance \(ESM\) """ And I verify that running `apt update` `with sudo` exits `0` When I run `apt-cache policy` as non-root diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/ubuntu_pro.feature ubuntu-advantage-tools-27.8~20.04.1/features/ubuntu_pro.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/ubuntu_pro.feature 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/ubuntu_pro.feature 2022-04-14 18:32:40.000000000 +0000 @@ -25,7 +25,7 @@ When I run `ua auto-attach` with sudo Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ Then stdout matches regexp: @@ -96,7 +96,7 @@ When I run `ua auto-attach` with sudo Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ Then stdout matches regexp: @@ -167,7 +167,7 @@ When I run `ua auto-attach` with sudo Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ Then stdout matches regexp: @@ -228,7 +228,7 @@ And I run `ua status --wait` as non-root Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ Then stdout matches regexp: @@ -246,7 +246,7 @@ When I run `ua status --all` as non-root Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ Then stdout matches regexp: @@ -362,7 +362,7 @@ And I run `ua status` as non-root Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ Then stdout matches regexp: @@ -380,7 +380,7 @@ When I run `ua status --all` as non-root Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ Then stdout matches regexp: @@ -496,7 +496,7 @@ And I run `ua status` as non-root Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ Then stdout matches regexp: @@ -514,7 +514,7 @@ When I run `ua status --all` as non-root Then stdout matches regexp: """ - SERVICE ENTITLED STATUS DESCRIPTION + SERVICE +ENTITLED STATUS DESCRIPTION cc-eal +yes + +Common Criteria EAL2 Provisioning Packages """ Then stdout matches regexp: diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/ubuntu_pro_fips.feature ubuntu-advantage-tools-27.8~20.04.1/features/ubuntu_pro_fips.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/ubuntu_pro_fips.feature 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/ubuntu_pro_fips.feature 2022-04-14 18:32:40.000000000 +0000 @@ -26,12 +26,6 @@ """ And I verify that running `apt update` `with sudo` exits `0` And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1` - And I verify that `openssh-server` is installed from apt source `` - And I verify that `openssh-client` is installed from apt source `` - And I verify that `strongswan` is installed from apt source `` - And I verify that `openssh-server-hmac` is installed from apt source `` - And I verify that `openssh-client-hmac` is installed from apt source `` - And I verify that `strongswan-hmac` is installed from apt source `` When I run `uname -r` as non-root Then stdout matches regexp: """ @@ -79,6 +73,10 @@ """ https://esm.ubuntu.com/apps/ubuntu -apps-security/main amd64 Packages """ + And apt-cache policy for the following url has permission `1001` + """ + amd64 Packages + """ And I verify that running `apt update` `with sudo` exits `0` When I run `apt install -y /-infra-security` with sudo, retrying exit [100] And I run `apt-cache policy ` as non-root @@ -99,15 +97,84 @@ \s*\*\*\* .* 500 \s*500 https://esm.ubuntu.com/apps/ubuntu -apps-security/main amd64 Packages """ + When I run `ua enable fips-updates --assume-yes` with sudo + Then I will see the following on stdout: + """ + One moment, checking your subscription first + Disabling incompatible service: FIPS + Updating package lists + Installing FIPS Updates packages + FIPS Updates enabled + A reboot is required to complete install. + """ + When I run `ua status` with sudo + Then stdout matches regexp: + """ + fips +yes +n/a +NIST-certified core packages + fips-updates +yes +enabled +NIST-certified core packages with priority security updates + """ + When I reboot the `` machine + And I run `uname -r` as non-root + Then stdout matches regexp: + """ + + """ + When I run `apt-cache policy ubuntu-azure-fips` as non-root + Then stdout does not match regexp: + """ + .*Installed: \(none\) + """ + When I run `cat /proc/sys/crypto/fips_enabled` with sudo + Then I will see the following on stdout: + """ + 1 + """ Examples: ubuntu release | release | infra-pkg | apps-pkg | fips-apt-source | fips-kernel-version | | xenial | libkrad0 | jq | https://esm.ubuntu.com/fips/ubuntu xenial/main | fips | | bionic | libkrad0 | bundler | https://esm.ubuntu.com/fips/ubuntu bionic/main | azure-fips | + | focal | hello | 389-ds | https://esm.ubuntu.com/fips/ubuntu focal/main | azure-fips | - @series.lts - @uses.config.machine_type.aws.pro.fips - Scenario Outline: Check fips is enabled correctly on Ubuntu pro fips AWS machine + @series.focal + @uses.config.machine_type.azure.pro.fips + Scenario Outline: Check fips packages are correctly installed on Azure Focal machine + Given a `` machine with ubuntu-advantage-tools installed + When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following: + """ + contract_url: 'https://contracts.canonical.com' + data_dir: /var/lib/ubuntu-advantage + log_level: debug + log_file: /var/log/ubuntu-advantage.log + features: + allow_xenial_fips_on_cloud: true + """ + And I run `ua auto-attach` with sudo + And I run `ua status --wait` as non-root + And I run `ua status` as non-root + Then stdout matches regexp: + """ + esm-apps +yes +enabled +UA Apps: Extended Security Maintenance \(ESM\) + esm-infra +yes +enabled +UA Infra: Extended Security Maintenance \(ESM\) + fips +yes +enabled +NIST-certified core packages + fips-updates +yes +disabled +NIST-certified core packages with priority security updates + livepatch +yes +n/a +Canonical Livepatch service + """ + And I verify that running `apt update` `with sudo` exits `0` + And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1` + And I verify that `openssh-server` is installed from apt source `` + And I verify that `openssh-client` is installed from apt source `` + And I verify that `strongswan` is installed from apt source `` + And I verify that `strongswan-hmac` is installed from apt source `` + + Examples: ubuntu release + | release | fips-apt-source | + | focal | https://esm.ubuntu.com/fips/ubuntu focal/main | + + @series.xenial + @series.bionic + @uses.config.machine_type.azure.pro.fips + Scenario Outline: Check fips packages are correctly installed on Azure Bionic & Xenial machines Given a `` machine with ubuntu-advantage-tools installed When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following: """ @@ -115,6 +182,8 @@ data_dir: /var/lib/ubuntu-advantage log_level: debug log_file: /var/log/ubuntu-advantage.log + features: + allow_xenial_fips_on_cloud: true """ And I run `ua auto-attach` with sudo And I run `ua status --wait` as non-root @@ -135,6 +204,36 @@ And I verify that `openssh-server-hmac` is installed from apt source `` And I verify that `openssh-client-hmac` is installed from apt source `` And I verify that `strongswan-hmac` is installed from apt source `` + + Examples: ubuntu release + | release | fips-apt-source | + | xenial | https://esm.ubuntu.com/fips/ubuntu xenial/main | + | bionic | https://esm.ubuntu.com/fips/ubuntu bionic/main | + + @series.lts + @uses.config.machine_type.aws.pro.fips + Scenario Outline: Check fips is enabled correctly on Ubuntu pro fips AWS machine + Given a `` machine with ubuntu-advantage-tools installed + When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following: + """ + contract_url: 'https://contracts.canonical.com' + data_dir: /var/lib/ubuntu-advantage + log_level: debug + log_file: /var/log/ubuntu-advantage.log + """ + And I run `ua auto-attach` with sudo + And I run `ua status --wait` as non-root + And I run `ua status` as non-root + Then stdout matches regexp: + """ + esm-apps +yes +enabled +UA Apps: Extended Security Maintenance \(ESM\) + esm-infra +yes +enabled +UA Infra: Extended Security Maintenance \(ESM\) + fips +yes +enabled +NIST-certified core packages + fips-updates +yes +disabled +NIST-certified core packages with priority security updates + livepatch +yes +n/a +Canonical Livepatch service + """ + And I verify that running `apt update` `with sudo` exits `0` + And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1` When I run `uname -r` as non-root Then stdout matches regexp: """ @@ -182,6 +281,10 @@ """ https://esm.ubuntu.com/apps/ubuntu -apps-security/main amd64 Packages """ + And apt-cache policy for the following url has permission `1001` + """ + amd64 Packages + """ And I verify that running `apt update` `with sudo` exits `0` When I run `apt install -y /-infra-security` with sudo, retrying exit [100] And I run `apt-cache policy ` as non-root @@ -202,9 +305,167 @@ \s*\*\*\* .* 500 \s*500 https://esm.ubuntu.com/apps/ubuntu -apps-security/main amd64 Packages """ + When I run `ua enable fips-updates --assume-yes` with sudo + Then I will see the following on stdout: + """ + One moment, checking your subscription first + Disabling incompatible service: FIPS + Updating package lists + Installing FIPS Updates packages + FIPS Updates enabled + A reboot is required to complete install. + """ + When I run `ua status` with sudo + Then stdout matches regexp: + """ + fips +yes +n/a +NIST-certified core packages + fips-updates +yes +enabled +NIST-certified core packages with priority security updates + """ + When I reboot the `` machine + And I run `uname -r` as non-root + Then stdout matches regexp: + """ + + """ + When I run `apt-cache policy ubuntu-aws-fips` as non-root + Then stdout does not match regexp: + """ + .*Installed: \(none\) + """ + When I run `cat /proc/sys/crypto/fips_enabled` with sudo + Then I will see the following on stdout: + """ + 1 + """ Examples: ubuntu release | release | infra-pkg | apps-pkg | fips-apt-source | fips-kernel-version | | xenial | libkrad0 | jq | https://esm.ubuntu.com/fips/ubuntu xenial/main | fips | | bionic | libkrad0 | bundler | https://esm.ubuntu.com/fips/ubuntu bionic/main | aws-fips | + | focal | hello | 389-ds | https://esm.ubuntu.com/fips/ubuntu focal/main | aws-fips | + + @series.focal + @uses.config.machine_type.aws.pro.fips + Scenario Outline: Check fips packages are correctly installed on AWS Focal machine + Given a `` machine with ubuntu-advantage-tools installed + When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following: + """ + contract_url: 'https://contracts.canonical.com' + data_dir: /var/lib/ubuntu-advantage + log_level: debug + log_file: /var/log/ubuntu-advantage.log + features: + allow_xenial_fips_on_cloud: true + """ + And I run `ua auto-attach` with sudo + And I run `ua status --wait` as non-root + And I run `ua status` as non-root + Then stdout matches regexp: + """ + esm-apps +yes +enabled +UA Apps: Extended Security Maintenance \(ESM\) + esm-infra +yes +enabled +UA Infra: Extended Security Maintenance \(ESM\) + fips +yes +enabled +NIST-certified core packages + fips-updates +yes +disabled +NIST-certified core packages with priority security updates + livepatch +yes +n/a +Canonical Livepatch service + """ + And I verify that running `apt update` `with sudo` exits `0` + And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1` + And I verify that `openssh-server` is installed from apt source `` + And I verify that `openssh-client` is installed from apt source `` + And I verify that `strongswan` is installed from apt source `` + And I verify that `strongswan-hmac` is installed from apt source `` + Examples: ubuntu release + | release | fips-apt-source | + | focal | https://esm.ubuntu.com/fips/ubuntu focal/main | + + @series.xenial + @series.bionic + @uses.config.machine_type.aws.pro.fips + Scenario Outline: Check fips packages are correctly installed on AWS Bionic & Xenial machines + Given a `` machine with ubuntu-advantage-tools installed + When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following: + """ + contract_url: 'https://contracts.canonical.com' + data_dir: /var/lib/ubuntu-advantage + log_level: debug + log_file: /var/log/ubuntu-advantage.log + features: + allow_xenial_fips_on_cloud: true + """ + And I run `ua auto-attach` with sudo + And I run `ua status --wait` as non-root + And I run `ua status` as non-root + Then stdout matches regexp: + """ + esm-apps +yes +enabled +UA Apps: Extended Security Maintenance \(ESM\) + esm-infra +yes +enabled +UA Infra: Extended Security Maintenance \(ESM\) + fips +yes +enabled +NIST-certified core packages + fips-updates +yes +disabled +NIST-certified core packages with priority security updates + livepatch +yes +n/a +Canonical Livepatch service + """ + And I verify that running `apt update` `with sudo` exits `0` + And I verify that running `grep Traceback /var/log/ubuntu-advantage.log` `with sudo` exits `1` + And I verify that `openssh-server` is installed from apt source `` + And I verify that `openssh-client` is installed from apt source `` + And I verify that `strongswan` is installed from apt source `` + And I verify that `openssh-server-hmac` is installed from apt source `` + And I verify that `openssh-client-hmac` is installed from apt source `` + And I verify that `strongswan-hmac` is installed from apt source `` + + Examples: ubuntu release + | release | fips-apt-source | + | xenial | https://esm.ubuntu.com/fips/ubuntu xenial/main | + | bionic | https://esm.ubuntu.com/fips/ubuntu bionic/main | + + @series.focal + @uses.config.machine_type.azure.pro.fips + @uses.config.machine_type.aws.pro.fips + Scenario Outline: Check fips-updates can be enable in a focal PRO FIPS machine + Given a `` machine with ubuntu-advantage-tools installed + When I create the file `/etc/ubuntu-advantage/uaclient.conf` with the following: + """ + contract_url: 'https://contracts.canonical.com' + data_dir: /var/lib/ubuntu-advantage + log_level: debug + log_file: /var/log/ubuntu-advantage.log + """ + And I run `ua auto-attach` with sudo + And I run `ua status --wait` as non-root + And I run `ua status` as non-root + Then stdout matches regexp: + """ + fips +yes +enabled +NIST-certified core packages + fips-updates +yes +disabled +NIST-certified core packages with priority security updates + """ + When I run `ua enable fips-updates --assume-yes` with sudo + Then stdout matches regexp: + """ + One moment, checking your subscription first + Disabling incompatible service: FIPS + Updating package lists + Installing FIPS Updates packages + FIPS Updates enabled + A reboot is required to complete install. + """ + When I run `ua status` with sudo + Then stdout matches regexp: + """ + fips +yes +n/a +NIST-certified core packages + fips-updates +yes +enabled +NIST-certified core packages with priority security updates + """ + When I reboot the `` machine + And I run `uname -r` as non-root + Then stdout matches regexp: + """ + fips + """ + When I run `cat /proc/sys/crypto/fips_enabled` with sudo + Then I will see the following on stdout: + """ + 1 + """ + + Examples: ubuntu release + | release | + | focal | diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/ubuntu_upgrade.feature ubuntu-advantage-tools-27.8~20.04.1/features/ubuntu_upgrade.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/ubuntu_upgrade.feature 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/ubuntu_upgrade.feature 2022-04-14 18:32:40.000000000 +0000 @@ -17,7 +17,6 @@ [Sources] AllowThirdParty=yes """ - And I run `sed -i 's/Prompt=lts/Prompt=normal/' /etc/update-manager/release-upgrades` with sudo And I run `do-release-upgrade --frontend DistUpgradeViewNonInteractive` `with sudo` and stdin `y\n` And I reboot the `` machine And I run `lsb_release -cs` as non-root @@ -42,7 +41,7 @@ Examples: ubuntu release | release | next_release | devel_release | - | focal | impish | | + | focal | jammy | --devel-release | | impish | jammy | --devel-release | @slow diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/unattached_status.feature ubuntu-advantage-tools-27.8~20.04.1/features/unattached_status.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/unattached_status.feature 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/unattached_status.feature 2022-04-14 18:32:40.000000000 +0000 @@ -47,13 +47,13 @@ When I run `ua status` as non-root Then stdout matches regexp: """ - SERVICE AVAILABLE DESCRIPTION - cc-eal +Common Criteria EAL2 Provisioning Packages + SERVICE +AVAILABLE DESCRIPTION + cc-eal + +Common Criteria EAL2 Provisioning Packages ?( + +Security compliance and audit tools)? - ?esm-infra +UA Infra: Extended Security Maintenance \(ESM\) - fips +NIST-certified core packages - fips-updates +NIST-certified core packages with priority security updates - livepatch +Canonical Livepatch service + ?esm-infra + +UA Infra: Extended Security Maintenance \(ESM\) + fips + +NIST-certified core packages + fips-updates + +NIST-certified core packages with priority security updates + livepatch + +Canonical Livepatch service ?( + +Security compliance and audit tools)? This machine is not attached to a UA subscription. @@ -62,16 +62,17 @@ When I run `ua status --all` as non-root Then stdout matches regexp: """ - SERVICE AVAILABLE DESCRIPTION - cc-eal +Common Criteria EAL2 Provisioning Packages + SERVICE +AVAILABLE DESCRIPTION + cc-eal + +Common Criteria EAL2 Provisioning Packages ?( + +Security compliance and audit tools)? - ?esm-apps +UA Apps: Extended Security Maintenance \(ESM\) - esm-infra +UA Infra: Extended Security Maintenance \(ESM\) - fips +NIST-certified core packages - fips-updates +NIST-certified core packages with priority security updates - livepatch +Canonical Livepatch service - ros +Security Updates for the Robot Operating System - ros-updates +All Updates for the Robot Operating System + ?esm-apps + +UA Apps: Extended Security Maintenance \(ESM\) + esm-infra + +UA Infra: Extended Security Maintenance \(ESM\) + fips + +NIST-certified core packages + fips-updates + +NIST-certified core packages with priority security updates + livepatch + +Canonical Livepatch service + realtime-kernel + +Beta-version Ubuntu Kernel with PREEMPT_RT patches + ros + +Security Updates for the Robot Operating System + ros-updates + +All Updates for the Robot Operating System ?( + +Security compliance and audit tools)? This machine is not attached to a UA subscription. @@ -80,13 +81,13 @@ When I run `ua status` with sudo Then stdout matches regexp: """ - SERVICE AVAILABLE DESCRIPTION - cc-eal +Common Criteria EAL2 Provisioning Packages + SERVICE +AVAILABLE DESCRIPTION + cc-eal + +Common Criteria EAL2 Provisioning Packages ?( + +Security compliance and audit tools)? - ?esm-infra +UA Infra: Extended Security Maintenance \(ESM\) - fips +NIST-certified core packages - fips-updates +NIST-certified core packages with priority security updates - livepatch +Canonical Livepatch service + ?esm-infra + +UA Infra: Extended Security Maintenance \(ESM\) + fips + +NIST-certified core packages + fips-updates + +NIST-certified core packages with priority security updates + livepatch + +Canonical Livepatch service ?( + +Security compliance and audit tools)? This machine is not attached to a UA subscription. @@ -95,16 +96,17 @@ When I run `ua status --all` with sudo Then stdout matches regexp: """ - SERVICE AVAILABLE DESCRIPTION - cc-eal +Common Criteria EAL2 Provisioning Packages + SERVICE +AVAILABLE DESCRIPTION + cc-eal + +Common Criteria EAL2 Provisioning Packages ?( + +Security compliance and audit tools)? - ?esm-apps +UA Apps: Extended Security Maintenance \(ESM\) - esm-infra +UA Infra: Extended Security Maintenance \(ESM\) - fips +NIST-certified core packages - fips-updates +NIST-certified core packages with priority security updates - livepatch +Canonical Livepatch service - ros +Security Updates for the Robot Operating System - ros-updates +All Updates for the Robot Operating System + ?esm-apps + +UA Apps: Extended Security Maintenance \(ESM\) + esm-infra + +UA Infra: Extended Security Maintenance \(ESM\) + fips + +NIST-certified core packages + fips-updates + +NIST-certified core packages with priority security updates + livepatch + +Canonical Livepatch service + realtime-kernel + +Beta-version Ubuntu Kernel with PREEMPT_RT patches + ros + +Security Updates for the Robot Operating System + ros-updates + +All Updates for the Robot Operating System ?( + +Security compliance and audit tools)? This machine is not attached to a UA subscription. @@ -118,16 +120,17 @@ And I run `ua status` as non-root Then stdout matches regexp: """ - SERVICE AVAILABLE DESCRIPTION - cc-eal +Common Criteria EAL2 Provisioning Packages + SERVICE +AVAILABLE DESCRIPTION + cc-eal + +Common Criteria EAL2 Provisioning Packages ?( + +Security compliance and audit tools)? - ?esm-apps +UA Apps: Extended Security Maintenance \(ESM\) - esm-infra +UA Infra: Extended Security Maintenance \(ESM\) - fips +NIST-certified core packages - fips-updates +NIST-certified core packages with priority security updates - livepatch +Canonical Livepatch service - ros +Security Updates for the Robot Operating System - ros-updates +All Updates for the Robot Operating System + ?esm-apps + +UA Apps: Extended Security Maintenance \(ESM\) + esm-infra + +UA Infra: Extended Security Maintenance \(ESM\) + fips + +NIST-certified core packages + fips-updates + +NIST-certified core packages with priority security updates + livepatch + +Canonical Livepatch service + realtime-kernel + +Beta-version Ubuntu Kernel with PREEMPT_RT patches + ros + +Security Updates for the Robot Operating System + ros-updates + +All Updates for the Robot Operating System ?( + +Security compliance and audit tools)? This machine is not attached to a UA subscription. @@ -135,44 +138,44 @@ """ Examples: ubuntu release - | release | esm-apps | cc-eal | cis | cis-available | fips | esm-infra | ros | livepatch | usg | - | xenial | yes | yes | cis | yes | yes | yes | yes | yes | | - | bionic | yes | yes | cis | yes | yes | yes | yes | yes | | - | focal | yes | no | | yes | yes | yes | no | yes | usg | - | impish | no | no | cis | no | no | no | no | no | | - | jammy | no | no | cis | no | no | no | no | no | | + | release | esm-apps | cc-eal | cis | cis-available | fips | esm-infra | ros | livepatch | usg | realtime-kernel | + | xenial | yes | yes | cis | yes | yes | yes | yes | yes | | no | + | bionic | yes | yes | cis | yes | yes | yes | yes | yes | | no | + | focal | yes | no | | yes | yes | yes | no | yes | usg | no | + | impish | no | no | cis | no | no | no | no | no | | no | + | jammy | no | no | cis | no | no | no | no | no | | yes | @series.all @uses.config.machine_type.lxd.container @uses.config.contract_token - @uses.config.contract_token_staging_expired Scenario Outline: Simulate status in a ubuntu machine Given a `` machine with ubuntu-advantage-tools installed When I do a preflight check for `contract_token` without the all flag Then stdout matches regexp: """ - SERVICE AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION - cc-eal +yes +no +Common Criteria EAL2 Provisioning Packages + SERVICE +AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION + cc-eal + +yes +no +Common Criteria EAL2 Provisioning Packages ?( + +yes +no +Security compliance and audit tools)? - ?esm-infra +yes +yes +UA Infra: Extended Security Maintenance \(ESM\) - fips +yes +no +NIST-certified core packages - fips-updates +yes +no +NIST-certified core packages with priority security updates - livepatch +yes +yes +Canonical Livepatch service + ?esm-infra + +yes +yes +UA Infra: Extended Security Maintenance \(ESM\) + fips + +yes +no +NIST-certified core packages + fips-updates + +yes +no +NIST-certified core packages with priority security updates + livepatch + +yes +yes +Canonical Livepatch service ?( + +yes +no +Security compliance and audit tools)? """ When I do a preflight check for `contract_token` with the all flag Then stdout matches regexp: """ - SERVICE AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION - cc-eal +yes +no +Common Criteria EAL2 Provisioning Packages + SERVICE +AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION + cc-eal + +yes +no +Common Criteria EAL2 Provisioning Packages ?( + +yes +no +Security compliance and audit tools)? - ?esm-apps +yes +yes +UA Apps: Extended Security Maintenance \(ESM\) - esm-infra +yes +yes +UA Infra: Extended Security Maintenance \(ESM\) - fips +yes +no +NIST-certified core packages - fips-updates +yes +no +NIST-certified core packages with priority security updates - livepatch +yes +yes +Canonical Livepatch service - ros +yes +no +Security Updates for the Robot Operating System - ros-updates +yes +no +All Updates for the Robot Operating System + ?esm-apps + +yes +yes +UA Apps: Extended Security Maintenance \(ESM\) + esm-infra + +yes +yes +UA Infra: Extended Security Maintenance \(ESM\) + fips + +yes +no +NIST-certified core packages + fips-updates + +yes +no +NIST-certified core packages with priority security updates + livepatch + +yes +yes +Canonical Livepatch service + realtime-kernel + +yes +no +Beta-version Ubuntu Kernel with PREEMPT_RT patches + ros + +yes +no +Security Updates for the Robot Operating System + ros-updates + +yes +no +All Updates for the Robot Operating System ?( + +yes +no +Security compliance and audit tools)? """ When I do a preflight check for `contract_token` formatted as json @@ -199,6 +202,20 @@ services: [] warnings: [] """ + Examples: ubuntu release + | release | esm-apps | cc-eal | cis | cis-available | fips | esm-infra | ros | livepatch | usg | realtime-kernel | + | xenial | yes | yes | cis | yes | yes | yes | yes | yes | | no | + | bionic | yes | yes | cis | yes | yes | yes | yes | yes | | no | + | focal | yes | no | | yes | yes | yes | no | yes | usg | no | + | impish | no | no | cis | no | no | no | no | no | | no | + | jammy | no | no | cis | no | no | no | no | no | | yes | + + + @series.all + @uses.config.machine_type.lxd.container + @uses.config.contract_token_staging_expired + Scenario Outline: Simulate status with expired token in a ubuntu machine + Given a `` machine with ubuntu-advantage-tools installed When I run `sed -i 's/contracts.can/contracts.staging.can/' /etc/ubuntu-advantage/uaclient.conf` with sudo And I verify that a preflight check for `contract_token_staging_expired` formatted as json exits 1 Then stdout is a json matching the `ua_status` schema @@ -223,13 +240,13 @@ This token is not valid. Contract \".*\" expired on .* - SERVICE AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION - cc-eal +yes +no +Common Criteria EAL2 Provisioning Packages + SERVICE +AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION + cc-eal + +yes +no +Common Criteria EAL2 Provisioning Packages ?( + +yes +no +Security compliance and audit tools)? - ?esm-infra +yes +yes +UA Infra: Extended Security Maintenance \(ESM\) - fips +yes +no +NIST-certified core packages - fips-updates +yes +no +NIST-certified core packages with priority security updates - livepatch +yes +yes +Canonical Livepatch service + ?esm-infra + +yes +yes +UA Infra: Extended Security Maintenance \(ESM\) + fips + +yes +no +NIST-certified core packages + fips-updates + +yes +no +NIST-certified core packages with priority security updates + livepatch + +yes +yes +Canonical Livepatch service ?( + +yes +no +Security compliance and audit tools)? """ @@ -239,4 +256,4 @@ | bionic | yes | yes | cis | yes | yes | yes | yes | yes | | | focal | yes | no | | yes | yes | yes | no | yes | usg | | impish | no | no | cis | no | no | no | no | no | | - | jammy | no | no | cis | no | no | no | no | no | | + | jammy | no | no | cis | no | no | yes | no | no | | diff -Nru ubuntu-advantage-tools-27.7~20.04.1/features/_version.feature ubuntu-advantage-tools-27.8~20.04.1/features/_version.feature --- ubuntu-advantage-tools-27.7~20.04.1/features/_version.feature 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/features/_version.feature 2022-04-14 18:32:40.000000000 +0000 @@ -15,7 +15,7 @@ Scenario Outline: Check ua version Given a `` machine with ubuntu-advantage-tools installed When I run `dpkg-query --showformat='${Version}' --show ubuntu-advantage-tools` with sudo - Then stdout matches regexp: + Then I will see the following on stdout """ {UACLIENT_BEHAVE_CHECK_VERSION} """ diff -Nru ubuntu-advantage-tools-27.7~20.04.1/help_data.yaml ubuntu-advantage-tools-27.8~20.04.1/help_data.yaml --- ubuntu-advantage-tools-27.7~20.04.1/help_data.yaml 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/help_data.yaml 2022-04-14 18:32:40.000000000 +0000 @@ -61,6 +61,16 @@ more about Ubuntu Kernel Livepatch service at https://ubuntu.com/security/livepatch +realtime-kernel: + help: | + The real-time kernel is a beta version of the 22.04 Ubuntu kernel with the + PREEMPT_RT patchset integrated for x86_64 and ARM64. It services extreme + latency-dependent use cases and provides deterministic response times to + service events. By meeting stringent preemption specifications, the + real-time kernel is suitable for telco applications and embedded devices + in industrial automation and robotics. To enroll in the beta program, visit + https://ubuntu.com/realtime-kernel + ros: help: | ros provides access to a private PPA which includes security-related Binary files /tmp/tmpcmzj7239/z7SpWPLnno/ubuntu-advantage-tools-27.7~20.04.1/keyrings/ubuntu-advantage-realtime-kernel.gpg and /tmp/tmpcmzj7239/kh_cqI972o/ubuntu-advantage-tools-27.8~20.04.1/keyrings/ubuntu-advantage-realtime-kernel.gpg differ diff -Nru ubuntu-advantage-tools-27.7~20.04.1/lib/upgrade_lts_contract.py ubuntu-advantage-tools-27.8~20.04.1/lib/upgrade_lts_contract.py --- ubuntu-advantage-tools-27.7~20.04.1/lib/upgrade_lts_contract.py 2021-10-01 15:23:59.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/lib/upgrade_lts_contract.py 2022-04-14 18:32:40.000000000 +0000 @@ -34,21 +34,27 @@ "16.04": "xenial", "18.04": "bionic", "20.04": "focal", - "20.10": "groovy", + "21.10": "impish", + "22.04": "jammy", } current_codename_to_past_codename = { "xenial": "trusty", "bionic": "xenial", "focal": "bionic", - "groovy": "focal", + "impish": "focal", + # We are considering the past release for Jammy to be Focal + # because we don't have any services available on Impish. + # Therefore, it is safer for us to try to process contract deltas + # using Focal + "jammy": "focal", } def process_contract_delta_after_apt_lock() -> None: logging.debug("Check whether to upgrade-lts-contract") if not UAConfig().is_attached: - logging.debug("Skiping upgrade-lts-contract. Machine is unattached") + logging.debug("Skipping upgrade-lts-contract. Machine is unattached") return out, _err = subp(["lsof", "/var/lib/apt/lists/lock"], rcs=[0, 1]) msg = "Starting upgrade-lts-contract." @@ -58,7 +64,15 @@ logging.debug(msg) current_version = parse_os_release()["VERSION_ID"] - current_release = version_to_codename[current_version] + current_release = version_to_codename.get(current_version) + + if current_release is None: + msg = "Unable to get release codename for version: {}".format( + current_version + ) + print(msg) + logging.warning(msg) + sys.exit(1) if current_release == "trusty": msg = "Unable to execute upgrade-lts-contract.py on trusty" @@ -66,7 +80,13 @@ logging.warning(msg) sys.exit(1) - past_release = current_codename_to_past_codename[current_release] + past_release = current_codename_to_past_codename.get(current_release) + if past_release is None: + msg = "Could not find past release for: {}".format(current_release) + print(msg) + logging.warning(msg) + sys.exit(1) + past_entitlements = UAConfig(series=past_release).entitlements new_entitlements = UAConfig(series=current_release).entitlements diff -Nru ubuntu-advantage-tools-27.7~20.04.1/tools/refresh-keyrings.sh ubuntu-advantage-tools-27.8~20.04.1/tools/refresh-keyrings.sh --- ubuntu-advantage-tools-27.7~20.04.1/tools/refresh-keyrings.sh 2021-10-01 15:23:59.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/tools/refresh-keyrings.sh 2022-04-14 18:32:40.000000000 +0000 @@ -28,6 +28,7 @@ FIPS_KEY_ID="E23341B2A1467EDBF07057D6C1997C40EDE22758" CIS_KEY_ID="81CF06E53F2C513A" ROS_KEY_ID="853874C8B0F10896" +REALTIME_KEY_ID="F6D1E58F4DCD9F91" generate_keyrings() { KEYRING_DIR="$1" @@ -50,6 +51,8 @@ service_name="cis";; $ROS_KEY_ID) service_name="ros";; + $REALTIME_KEY_ID) + service_name="realtime-kernel";; *) echo "Unhandled key id provided: " $key exit 1; @@ -70,6 +73,6 @@ } -generate_keyrings $TARGET_DIR $EAL_KEY_ID $ESM_INFRA_KEY_ID $ESM_APPS_KEY_ID $FIPS_KEY_ID $CIS_KEY_ID $ROS_KEY_ID +generate_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 rm -rf $tmp_dir diff -Nru ubuntu-advantage-tools-27.7~20.04.1/tox.ini ubuntu-advantage-tools-27.8~20.04.1/tox.ini --- ubuntu-advantage-tools-27.7~20.04.1/tox.ini 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/tox.ini 2022-04-14 18:32:40.000000000 +0000 @@ -60,6 +60,7 @@ behave-vm-16.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.xenial,series.all,series.lts" --tags="~upgrade" behave-vm-18.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.bionic,series.all,series.lts" --tags="~upgrade" behave-vm-20.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.focal,series.all,series.lts" --tags="~upgrade" + behave-vm-22.04: behave -v {posargs} --tags="uses.config.machine_type.lxd.vm" --tags="series.jammy,series.all,series.lts" --tags="~upgrade" behave-upgrade-16.04: behave -v {posargs} --tags="upgrade" --tags="series.xenial,series.all" behave-upgrade-18.04: behave -v {posargs} --tags="upgrade" --tags="series.bionic,series.all" behave-upgrade-20.04: behave -v {posargs} --tags="upgrade" --tags="series.focal,series.all" @@ -72,6 +73,7 @@ behave-awspro-20.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro" --tags="series.focal,series.lts,series.all" behave-awspro-fips-16.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro.fips" --tags="series.xenial,series.lts,series.all" behave-awspro-fips-18.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro.fips" --tags="series.bionic,series.lts,series.all" + behave-awspro-fips-20.04: behave -v {posargs} --tags="uses.config.machine_type.aws.pro.fips" --tags="series.focal,series.lts,series.all" behave-azuregeneric-16.04: behave -v {posargs} --tags="uses.config.machine_type.azure.generic" --tags="series.xenial,series.lts,series.all" --tags="~upgrade" behave-azuregeneric-18.04: behave -v {posargs} --tags="uses.config.machine_type.azure.generic" --tags="series.bionic,series.lts,series.all" --tags="~upgrade" 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 @@ behave-azurepro-20.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro" --tags="series.focal,series.lts,series.all" behave-azurepro-fips-16.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro.fips" --tags="series.xenial,series.lts,series.all" behave-azurepro-fips-18.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro.fips" --tags="series.bionic,series.lts,series.all" + behave-azurepro-fips-20.04: behave -v {posargs} --tags="uses.config.machine_type.azure.pro.fips" --tags="series.focal,series.lts,series.all" behave-gcpgeneric-16.04: behave -v {posargs} --tags="uses.config.machine_type.gcp.generic" --tags="series.xenial,series.lts,series.all" --tags="~upgrade" behave-gcpgeneric-18.04: behave -v {posargs} --tags="uses.config.machine_type.gcp.generic" --tags="series.bionic,series.lts,series.all" --tags="~upgrade" behave-gcpgeneric-20.04: behave -v {posargs} --tags="uses.config.machine_type.gcp.generic" --tags="series.focal,series.lts,series.all" --tags="~upgrade" diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/clouds/identity.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/clouds/identity.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/clouds/identity.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/clouds/identity.py 2022-04-01 13:27:49.000000000 +0000 @@ -1,5 +1,6 @@ import logging from enum import Enum +from functools import lru_cache from typing import Dict, Optional, Tuple, Type # noqa: F401 from uaclient import clouds, exceptions, util @@ -36,6 +37,7 @@ return None +@lru_cache(maxsize=None) @apply_config_settings_override("cloud_type") def get_cloud_type() -> Tuple[Optional[str], Optional[NoCloudTypeReason]]: if util.which("cloud-id"): diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/clouds/tests/test_identity.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/clouds/tests/test_identity.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/clouds/tests/test_identity.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/clouds/tests/test_identity.py 2022-04-01 13:27:49.000000000 +0000 @@ -40,7 +40,7 @@ @mock.patch(M_PATH + "util.subp", return_value=("somecloud\n", "")) def test_use_cloud_id_when_available(self, m_subp, m_which): """Use cloud-id utility to discover cloud type.""" - assert ("somecloud", None) == get_cloud_type() + assert ("somecloud", None) == get_cloud_type.__wrapped__() assert [mock.call("cloud-id")] == m_which.call_args_list @mock.patch(M_PATH + "util.which", return_value="/usr/bin/cloud-id") @@ -49,7 +49,10 @@ side_effect=exceptions.ProcessExecutionError("cloud-id"), ) def test_error_when_cloud_id_fails(self, m_subp, m_which): - assert (None, NoCloudTypeReason.CLOUD_ID_ERROR) == get_cloud_type() + assert ( + None, + NoCloudTypeReason.CLOUD_ID_ERROR, + ) == get_cloud_type.__wrapped__() @pytest.mark.parametrize( "settings_overrides", @@ -80,7 +83,7 @@ expected_value = "test" m_load_file.return_value = settings_overrides - assert get_cloud_type() == (expected_value, None) + assert get_cloud_type.__wrapped__() == (expected_value, None) @mock.patch(M_PATH + "get_cloud_type") diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/config.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/config.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/config.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/config.py 2022-04-14 18:32:40.000000000 +0000 @@ -357,7 +357,7 @@ entitlement_cfg["resourceToken"] = tokens_by_name[ entitlement_name ] - util.apply_series_overrides(entitlement_cfg, self.series) + util.apply_contract_overrides(entitlement_cfg, self.series) self._entitlements[entitlement_name] = entitlement_cfg return self._entitlements diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/contract.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/contract.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/contract.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/contract.py 2022-04-14 18:32:40.000000000 +0000 @@ -347,7 +347,7 @@ from uaclient.entitlements import entitlement_factory if series_overrides: - util.apply_series_overrides(new_access) + util.apply_contract_overrides(new_access) deltas = util.get_dict_deltas(orig_access, new_access) ret = False diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/base.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/base.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/base.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/base.py 2022-04-14 18:32:40.000000000 +0000 @@ -209,7 +209,8 @@ populated CanEnableFailure reason. This may expand to include other types of reasons in the future. """ - msg_ops = self.messaging.get("pre_enable", []) + + msg_ops = self.messaging.get("pre_can_enable", []) if not util.handle_message_operations(msg_ops): return False, None @@ -237,6 +238,10 @@ # every other reason means we can't continue return False, fail + msg_ops = self.messaging.get("pre_enable", []) + if not util.handle_message_operations(msg_ops): + return False, None + ret = self._perform_enable(silent=silent) if not ret: return False, None @@ -449,7 +454,7 @@ path_to_value="features.block_disable_on_enable", ) for service in self.blocking_incompatible_services(): - ent = service.entitlement(self.cfg) + ent = service.entitlement(self.cfg, assume_yes=True) user_msg = messages.INCOMPATIBLE_SERVICE.format( service_being_enabled=self.title, @@ -474,7 +479,7 @@ ) event.info(disable_msg) - ret = ent.disable() + ret = ent.disable(silent=True) if not ret: return ret, None @@ -664,7 +669,7 @@ event.info(info_msg=msg.msg, file_type=sys.stderr) return False, msg - ent = ent_cls(self.cfg) + ent = ent_cls(cfg=self.cfg, assume_yes=True) is_service_enabled = ( ent.application_status()[0] == status.ApplicationStatus.ENABLED @@ -710,13 +715,16 @@ """Check if system needs to be rebooted.""" return util.should_reboot() - def _check_for_reboot_msg(self, operation: str) -> None: + def _check_for_reboot_msg( + self, operation: str, silent: bool = False + ) -> None: """Check if user should be alerted that a reboot must be performed. @param operation: The operation being executed. + @param silent: Boolean set True to silence print/log of messages """ - if self._check_for_reboot(): - print( + if self._check_for_reboot() and not silent: + event.info( messages.ENABLE_REBOOT_REQUIRED_TMPL.format( operation=operation ) @@ -763,7 +771,9 @@ if not util.handle_message_operations(msg_ops): return False, None - self._check_for_reboot_msg(operation="disable operation") + self._check_for_reboot_msg( + operation="disable operation", silent=silent + ) return True, None def contract_status(self) -> ContractStatus: @@ -836,7 +846,7 @@ transition_to_unentitled = bool(delta_entitlement == util.DROPPED_KEY) if not transition_to_unentitled: if delta_entitlement: - util.apply_series_overrides(deltas) + util.apply_contract_overrides(deltas) delta_entitlement = deltas["entitlement"] if orig_access and "entitled" in delta_entitlement: transition_to_unentitled = delta_entitlement["entitled"] in ( diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/cis.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/cis.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/cis.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/cis.py 2022-04-14 18:32:40.000000000 +0000 @@ -29,7 +29,7 @@ ] } # type: MessagingOperationsDict if "usg" in self.valid_names: - messages["pre_enable"] = [ + messages["pre_can_enable"] = [ "From Ubuntu 20.04 and onwards 'ua enable cis' has been", "replaced by 'ua enable usg'. See more information at:", USG_DOCS_URL, diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/fips.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/fips.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/fips.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/fips.py 2022-04-14 18:32:40.000000000 +0000 @@ -87,6 +87,27 @@ help_doc_url = "https://ubuntu.com/security/certifications#fips" + fips_pro_package_holds = [ + "fips-initramfs", + "libssl1.1", + "libssl1.1-hmac", + "libssl1.0.0", + "libssl1.0.0-hmac", + "libssl1.0.0", + "libssl1.0.0-hmac", + "linux-fips", + "openssh-client", + "openssh-client-hmac", + "openssh-server", + "openssh-server-hmac", + "openssl", + "strongswan", + "strongswan-hmac", + "libgcrypt20", + "libgcrypt20-hmac", + "fips-initramfs-generic", + ] + @property def conditional_packages(self): """ @@ -155,19 +176,23 @@ ) ) - def _check_for_reboot_msg(self, operation: str) -> None: + def _check_for_reboot_msg( + self, operation: str, silent: bool = False + ) -> None: """Check if user should be alerted that a reboot must be performed. @param operation: The operation being executed. + @param silent: Boolean set True to silence print/log of messages """ reboot_required = util.should_reboot() event.needs_reboot(reboot_required) if reboot_required: - event.info( - messages.ENABLE_REBOOT_REQUIRED_TMPL.format( - operation=operation + if not silent: + event.info( + messages.ENABLE_REBOOT_REQUIRED_TMPL.format( + operation=operation + ) ) - ) if operation == "install": self.cfg.add_notice( "", messages.FIPS_SYSTEM_REBOOT_REQUIRED.msg @@ -361,6 +386,27 @@ return False + def setup_apt_config(self, silent: bool = False) -> None: + """Setup apt config based on the resourceToken and directives. + + FIPS-specifically handle apt-mark unhold + + :raise UserFacingError: on failure to setup any aspect of this apt + configuration + """ + cmd = ["apt-mark", "showholds"] + holds = apt.run_apt_command(cmd, " ".join(cmd) + " failed.") + unholds = [] + for hold in holds.splitlines(): + if hold in self.fips_pro_package_holds: + unholds.append(hold) + if unholds: + unhold_cmd = ["apt-mark", "unhold"] + unholds + holds = apt.run_apt_command( + unhold_cmd, " ".join(unhold_cmd) + " failed." + ) + super().setup_apt_config(silent=silent) + class FIPSEntitlement(FIPSCommonEntitlement): @@ -369,27 +415,10 @@ description = "NIST-certified core packages" origin = "UbuntuFIPS" - fips_pro_package_holds = [ - "fips-initramfs", - "libssl1.1", - "libssl1.1-hmac", - "libssl1.0.0", - "libssl1.0.0-hmac", - "libssl1.0.0", - "libssl1.0.0-hmac", - "linux-fips", - "openssh-client", - "openssh-client-hmac", - "openssh-server", - "openssh-server-hmac", - "openssl", - "strongswan", - "strongswan-hmac", - ] - @property def incompatible_services(self) -> Tuple[IncompatibleService, ...]: from uaclient.entitlements.livepatch import LivepatchEntitlement + from uaclient.entitlements.realtime import RealtimeKernelEntitlement return ( IncompatibleService( @@ -398,6 +427,9 @@ IncompatibleService( FIPSUpdatesEntitlement, messages.FIPS_UPDATES_INVALIDATES_FIPS ), + IncompatibleService( + RealtimeKernelEntitlement, messages.REALTIME_FIPS_INCOMPATIBLE + ), ) @property @@ -464,27 +496,6 @@ ], } - def setup_apt_config(self, silent: bool = False) -> None: - """Setup apt config based on the resourceToken and directives. - - FIPS-specifically handle apt-mark unhold - - :raise UserFacingError: on failure to setup any aspect of this apt - configuration - """ - cmd = ["apt-mark", "showholds"] - holds = apt.run_apt_command(cmd, " ".join(cmd) + " failed.") - unholds = [] - for hold in holds.splitlines(): - if hold in self.fips_pro_package_holds: - unholds.append(hold) - if unholds: - unhold_cmd = ["apt-mark", "unhold"] + unholds - holds = apt.run_apt_command( - unhold_cmd, " ".join(unhold_cmd) + " failed." - ) - super().setup_apt_config(silent=silent) - def _perform_enable(self, silent: bool = False) -> bool: cloud_type, error = get_cloud_type() if cloud_type is None and error == NoCloudTypeReason.CLOUD_ID_ERROR: @@ -507,6 +518,20 @@ description = "NIST-certified core packages with priority security updates" @property + def incompatible_services(self) -> Tuple[IncompatibleService, ...]: + from uaclient.entitlements.realtime import RealtimeKernelEntitlement + + return ( + IncompatibleService( + FIPSEntitlement, messages.FIPS_INVALIDATES_FIPS_UPDATES + ), + IncompatibleService( + RealtimeKernelEntitlement, + messages.REALTIME_FIPS_UPDATES_INCOMPATIBLE, + ), + ) + + @property def messaging(self,) -> MessagingOperationsDict: post_enable = None # type: Optional[MessagingOperations] if util.is_container(): diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/__init__.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/__init__.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/__init__.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/__init__.py 2022-04-14 18:32:40.000000000 +0000 @@ -7,6 +7,7 @@ from uaclient.entitlements.cis import CISEntitlement from uaclient.entitlements.esm import ESMAppsEntitlement, ESMInfraEntitlement from uaclient.entitlements.livepatch import LivepatchEntitlement +from uaclient.entitlements.realtime import RealtimeKernelEntitlement from uaclient.entitlements.ros import ROSEntitlement, ROSUpdatesEntitlement from uaclient.exceptions import EntitlementNotFoundError from uaclient.util import is_config_value_true @@ -19,6 +20,7 @@ fips.FIPSEntitlement, fips.FIPSUpdatesEntitlement, LivepatchEntitlement, + RealtimeKernelEntitlement, ROSEntitlement, ROSUpdatesEntitlement, ] # type: List[Type[UAEntitlement]] diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/livepatch.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/livepatch.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/livepatch.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/livepatch.py 2022-04-14 18:32:40.000000000 +0000 @@ -109,11 +109,16 @@ @property def incompatible_services(self) -> Tuple[IncompatibleService, ...]: from uaclient.entitlements.fips import FIPSEntitlement + from uaclient.entitlements.realtime import RealtimeKernelEntitlement return ( IncompatibleService( FIPSEntitlement, messages.LIVEPATCH_INVALIDATES_FIPS ), + IncompatibleService( + RealtimeKernelEntitlement, + messages.REALTIME_LIVEPATCH_INCOMPATIBLE, + ), ) @property diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/realtime.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/realtime.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/realtime.py 1970-01-01 00:00:00.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/realtime.py 2022-04-14 18:32:40.000000000 +0000 @@ -0,0 +1,84 @@ +from typing import Tuple + +from uaclient import event_logger, messages, util +from uaclient.entitlements import repo +from uaclient.entitlements.base import IncompatibleService +from uaclient.types import MessagingOperationsDict, StaticAffordance + +event = event_logger.get_event_logger() + +REALTIME_KERNEL_DOCS_URL = "https://ubuntu.com/realtime-kernel" + + +class RealtimeKernelEntitlement(repo.RepoEntitlement): + name = "realtime-kernel" + title = "Real-Time Kernel" + description = "Beta-version Ubuntu Kernel with PREEMPT_RT patches" + help_doc_url = REALTIME_KERNEL_DOCS_URL + repo_key_file = "ubuntu-advantage-realtime-kernel.gpg" + is_beta = True + apt_noninteractive = True + + def _check_for_reboot(self) -> bool: + """Check if system needs to be rebooted.""" + reboot_required = util.should_reboot( + installed_pkgs=set(self.packages), + installed_pkgs_regex=set(["linux-.*-realtime"]), + ) + event.needs_reboot(reboot_required) + return reboot_required + + @property + def incompatible_services(self) -> Tuple[IncompatibleService, ...]: + from uaclient.entitlements.fips import ( + FIPSEntitlement, + FIPSUpdatesEntitlement, + ) + from uaclient.entitlements.livepatch import LivepatchEntitlement + + return ( + IncompatibleService( + FIPSEntitlement, messages.REALTIME_FIPS_INCOMPATIBLE + ), + IncompatibleService( + FIPSUpdatesEntitlement, + messages.REALTIME_FIPS_UPDATES_INCOMPATIBLE, + ), + IncompatibleService( + LivepatchEntitlement, messages.REALTIME_LIVEPATCH_INCOMPATIBLE + ), + ) + + @property + def static_affordances(self) -> Tuple[StaticAffordance, ...]: + return ( + ( + messages.REALTIME_ERROR_INSTALL_ON_CONTAINER, + lambda: util.is_container(), + False, + ), + ) + + @property + def messaging(self,) -> MessagingOperationsDict: + return { + "pre_enable": [ + ( + util.prompt_for_confirmation, + { + "msg": messages.REALTIME_BETA_PROMPT, + "assume_yes": self.assume_yes, + "default": True, + }, + ) + ], + "pre_disable": [ + ( + util.prompt_for_confirmation, + { + "msg": messages.REALTIME_PRE_DISABLE_PROMPT, + "assume_yes": self.assume_yes, + }, + ) + ], + } diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/tests/test_cc.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/tests/test_cc.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/tests/test_cc.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/tests/test_cc.py 2022-04-01 13:27:49.000000000 +0000 @@ -110,8 +110,10 @@ @mock.patch("uaclient.util.should_reboot") @mock.patch("uaclient.util.subp") @mock.patch("uaclient.util.get_platform_info") + @mock.patch("uaclient.util.apply_contract_overrides") def test_enable_configures_apt_sources_and_auth_files( self, + _m_contract_overrides, m_platform_info, m_subp, m_should_reboot, diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/tests/test_fips.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/tests/test_fips.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/tests/test_fips.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/tests/test_fips.py 2022-04-14 18:32:40.000000000 +0000 @@ -21,6 +21,7 @@ FIPSEntitlement, FIPSUpdatesEntitlement, ) +from uaclient.status import CanEnableFailureReason M_PATH = "uaclient.entitlements.fips." M_LIVEPATCH_PATH = "uaclient.entitlements.livepatch.LivepatchEntitlement." @@ -302,9 +303,11 @@ stack.enter_context( mock.patch.object(type(entitlement), "packages", m_packages) ) + stack.enter_context( + mock.patch("uaclient.util.is_container", return_value=False) + ) m_can_enable.return_value = (True, None) - assert (True, None) == entitlement.enable() repo_url = "http://{}".format(entitlement.name.upper()) @@ -364,27 +367,20 @@ ) ) - if isinstance(entitlement, FIPSEntitlement): - subp_calls = [ - mock.call( - ["apt-mark", "showholds"], - capture=True, - retry_sleeps=apt.APT_RETRIES, - env={}, - ) - ] - else: - subp_calls = [] - subp_calls.extend( - [ - mock.call( - ["apt-get", "update"], - capture=True, - retry_sleeps=apt.APT_RETRIES, - env={}, - ) - ] - ) + subp_calls = [ + mock.call( + ["apt-mark", "showholds"], + capture=True, + retry_sleeps=apt.APT_RETRIES, + env={}, + ), + mock.call( + ["apt-get", "update"], + capture=True, + retry_sleeps=apt.APT_RETRIES, + env={}, + ), + ] subp_calls += install_cmd assert [mock.call()] == m_can_enable.call_args_list @@ -1092,6 +1088,10 @@ "openssh-server\nlibssl1.1-hmac\nasdf\n", ["openssh-server", "libssl1.1-hmac"], ), + ( + "libgcrypt20\nlibgcrypt20-hmac\nwow\n", + ["libgcrypt20", "libgcrypt20-hmac"], + ), ), ) @mock.patch(M_REPOPATH + "RepoEntitlement.setup_apt_config") @@ -1107,19 +1107,12 @@ """Unmark only fips-specific package holds if present.""" run_apt_command.return_value = held_packages entitlement.setup_apt_config(silent=False) - if isinstance(entitlement, FIPSUpdatesEntitlement): - expected_calls = [] - else: - expected_calls = [ - mock.call( - ["apt-mark", "showholds"], "apt-mark showholds failed." - ) - ] - if unhold_packages: - cmd = ["apt-mark", "unhold"] + unhold_packages - expected_calls.append( - mock.call(cmd, " ".join(cmd) + " failed.") - ) + expected_calls = [ + mock.call(["apt-mark", "showholds"], "apt-mark showholds failed.") + ] + if unhold_packages: + cmd = ["apt-mark", "unhold"] + unhold_packages + expected_calls.append(mock.call(cmd, " ".join(cmd) + " failed.")) assert expected_calls == run_apt_command.call_args_list assert [mock.call(silent=False)] == setup_apt_config.call_args_list @@ -1287,3 +1280,35 @@ else: assert not m_read_cache.call_count assert not m_write_cache.call_count + + +class TestFIPSUpdatesEntitlementCanEnable: + @mock.patch("uaclient.util.is_config_value_true", return_value=False) + def test_can_enable_false_if_fips_enabled( + self, m_is_config_value_true, capsys, entitlement_factory + ): + """When entitlement is disabled, can_enable returns True.""" + entitlement = entitlement_factory(FIPSUpdatesEntitlement) + with mock.patch.object( + entitlement, + "applicability_status", + return_value=(status.ApplicabilityStatus.APPLICABLE, ""), + ): + with mock.patch.object( + entitlement, + "application_status", + return_value=(status.ApplicationStatus.DISABLED, ""), + ): + with mock.patch( + M_PATH + "FIPSEntitlement.application_status" + ) as m_fips_status: + m_fips_status.return_value = ( + status.ApplicationStatus.ENABLED, + None, + ) + actual_ret, reason = entitlement.can_enable() + assert actual_ret is False + assert ( + reason.reason + == CanEnableFailureReason.INCOMPATIBLE_SERVICE + ) diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/tests/test_livepatch.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/tests/test_livepatch.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/tests/test_livepatch.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/tests/test_livepatch.py 2022-04-14 18:32:40.000000000 +0000 @@ -617,6 +617,7 @@ @pytest.mark.parametrize("apt_update_success", (True, False)) @mock.patch("uaclient.util.get_platform_info") @mock.patch("uaclient.util.subp") + @mock.patch("uaclient.util.apply_contract_overrides") @mock.patch("uaclient.apt.run_apt_install_command") @mock.patch("uaclient.apt.run_apt_update_command") @mock.patch("uaclient.util.which", return_value=False) @@ -631,6 +632,7 @@ m_which, m_run_apt_update, m_run_apt_install, + _m_contract_overrides, m_subp, _m_get_platform_info, m_livepatch_proxy, @@ -678,6 +680,7 @@ @mock.patch("uaclient.util.get_platform_info") @mock.patch("uaclient.util.subp", return_value=("snapd", "")) + @mock.patch("uaclient.util.apply_contract_overrides") @mock.patch( "uaclient.util.which", side_effect=lambda cmd: cmd == "/usr/bin/snap" ) @@ -690,6 +693,7 @@ m_can_enable, m_app_status, m_which, + _m_contract_overrides, m_subp, _m_get_platform_info, m_livepatch_proxy, @@ -759,6 +763,7 @@ @mock.patch("uaclient.apt.get_installed_packages", return_value=["snapd"]) @mock.patch("uaclient.util.get_platform_info") @mock.patch("uaclient.util.subp") + @mock.patch("uaclient.util.apply_contract_overrides") @mock.patch("uaclient.util.which", side_effect=[True, True]) @mock.patch(M_PATH + "LivepatchEntitlement.application_status") @mock.patch( @@ -769,6 +774,7 @@ m_can_enable, m_app_status, m_which, + _m_contract_overrides, m_subp, _m_get_platform_info, _m_get_installed_packages, @@ -808,6 +814,7 @@ @mock.patch("uaclient.apt.get_installed_packages", return_value=["snapd"]) @mock.patch("uaclient.util.get_platform_info") @mock.patch("uaclient.util.subp") + @mock.patch("uaclient.util.apply_contract_overrides") @mock.patch("uaclient.util.which", side_effect=[True, True]) @mock.patch(M_PATH + "LivepatchEntitlement.application_status") @mock.patch( @@ -818,6 +825,7 @@ m_can_enable, m_app_status, m_which, + _m_contract_overrides, m_subp, _m_get_platform_info, _m_get_installed_packages, diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/tests/test_repo.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/tests/test_repo.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/entitlements/tests/test_repo.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/entitlements/tests/test_repo.py 2022-04-14 18:32:40.000000000 +0000 @@ -385,23 +385,25 @@ class TestRepoEnable: @pytest.mark.parametrize( - "pre_enable_msg, output, can_enable_call_count", + "pre_enable_msg, output, perform_enable_call_count", ( (["msg1", (lambda: False, {}), "msg2"], "msg1\n", 0), (["msg1", (lambda: True, {}), "msg2"], "msg1\nmsg2\n", 1), ), ) @mock.patch.object( - RepoTestEntitlement, - "can_enable", - return_value=(False, status.CanEnableFailure(None)), + RepoTestEntitlement, "_perform_enable", return_value=False + ) + @mock.patch.object( + RepoTestEntitlement, "can_enable", return_value=(True, None) ) def test_enable_can_exit_on_pre_enable_messaging_hooks( self, - m_can_enable, + _m_can_enable, + m_perform_enable, pre_enable_msg, output, - can_enable_call_count, + perform_enable_call_count, entitlement, capsys, ): @@ -414,7 +416,7 @@ entitlement.enable() stdout, _ = capsys.readouterr() assert output == stdout - assert can_enable_call_count == m_can_enable.call_count + assert perform_enable_call_count == m_perform_enable.call_count @pytest.mark.parametrize( "pre_disable_msg,post_disable_msg,output,retval", @@ -734,8 +736,10 @@ @mock.patch(M_PATH + "apt.remove_apt_list_files") @mock.patch(M_PATH + "apt.run_apt_command") @mock.patch(M_PATH + "util.get_platform_info") + @mock.patch(M_PATH + "util.apply_contract_overrides") def test_repo_pin_priority_int_removes_apt_preferences( self, + _m_contract_overrides, m_get_platform, _m_run_apt_command, _m_remove_apt_list_files, @@ -862,8 +866,10 @@ @mock.patch("uaclient.apt.setup_apt_proxy") @mock.patch(M_PATH + "apt.add_auth_apt_repo") @mock.patch(M_PATH + "apt.run_apt_install_command") + @mock.patch(M_PATH + "util.apply_contract_overrides") def test_install_prerequisite_packages( self, + _m_contract_overrides, m_run_apt_install_command, m_add_auth_repo, _m_setup_apt_proxy, @@ -908,8 +914,10 @@ @mock.patch(M_PATH + "apt.add_auth_apt_repo") @mock.patch(M_PATH + "apt.run_apt_command") @mock.patch(M_PATH + "util.get_platform_info") + @mock.patch(M_PATH + "util.apply_contract_overrides") def test_setup_with_repo_pin_priority_never_removes_apt_preferences_file( self, + _m_contract_overrides, m_get_platform_info, m_run_apt_command, m_add_auth_repo, @@ -940,8 +948,10 @@ @mock.patch(M_PATH + "apt.run_apt_update_command") @mock.patch(M_PATH + "apt.add_ppa_pinning") @mock.patch(M_PATH + "util.get_platform_info") + @mock.patch(M_PATH + "util.apply_contract_overrides") def test_setup_with_repo_pin_priority_int_adds_a_pins_repo_apt_preference( self, + _m_apply_overrides, m_get_platform_info, m_add_ppa_pinning, m_run_apt_update_command, diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/messages.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/messages.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/messages.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/messages.py 2022-04-14 18:32:40.000000000 +0000 @@ -22,6 +22,7 @@ OKGREEN = "\033[92m" DISABLEGREY = "\033[37m" FAIL = "\033[91m" + BOLD = "\033[1m" ENDC = "\033[0m" @@ -661,6 +662,12 @@ " FIPS Updates installs security patches that aren't officially" " certified.", ) +FIPS_INVALIDATES_FIPS_UPDATES = NamedMessage( + "fips-invalidates-fips-updates", + "FIPS Updates cannot be enabled if FIPS is enabled." + " FIPS Updates installs security patches that aren't officially" + " certified.", +) LIVEPATCH_INVALIDATES_FIPS = NamedMessage( "livepatch-invalidates-fips", "Livepatch cannot be enabled while running the official FIPS" @@ -668,6 +675,45 @@ " with additional bug fixes and security updates, you can use" " the FIPS Updates service with Livepatch.", ) +REALTIME_FIPS_INCOMPATIBLE = NamedMessage( + "realtime-fips-incompatible", + "Realtime and FIPS require different kernels, so you cannot enable" + " both at the same time.", +) +REALTIME_FIPS_UPDATES_INCOMPATIBLE = NamedMessage( + "realtime-fips-updates-incompatible", + "Realtime and FIPS Updates require different kernels, so you cannot enable" + " both at the same time.", +) +REALTIME_LIVEPATCH_INCOMPATIBLE = NamedMessage( + "realtime-livepatch-incompatible", + "Livepatch is not currently supported for the real-time kernel.", +) +REALTIME_BETA_FLAG_REQUIRED = NamedMessage( + "beta-flag-required", + "Use `ua enable realtime-kernel --beta` to acknowledge the real-time" + " kernel is currently in beta and comes with no support.", +) +REALTIME_BETA_PROMPT = """\ +The real-time kernel is a beta version of the 22.04 Ubuntu kernel with the +PREEMPT_RT patchset integrated for x86_64 and ARM64. + +{bold}You will not be able to revert to your original kernel after enabling\ + real-time.{end_bold} + +Do you want to continue? [ default = Yes ]: (Y/n) """.format( + bold=TxtColor.BOLD, end_bold=TxtColor.ENDC +) +REALTIME_PRE_DISABLE_PROMPT = """\ +This will disable the Real-Time Kernel entitlement but the Real-Time Kernel\ + will remain installed. +Are you sure? (y/N) """ + +REALTIME_ERROR_INSTALL_ON_CONTAINER = NamedMessage( + "realtime-error-install-on-container", + "Cannot install Real-Time Kernel on a container.", +) + LOG_CONNECTIVITY_ERROR_TMPL = CONNECTIVITY_ERROR.msg + " {error}" LOG_CONNECTIVITY_ERROR_WITH_URL_TMPL = ( diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/status.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/status.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/status.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/status.py 2022-04-14 18:32:40.000000000 +0000 @@ -225,17 +225,17 @@ BASE_UA_URL ) -STATUS_UNATTACHED_TMPL = "{name: <14}{available: <11}{description}" +STATUS_UNATTACHED_TMPL = "{name: <17}{available: <11}{description}" STATUS_SIMULATED_TMPL = """\ -{name: <14}{available: <11}{entitled: <11}{auto_enabled: <14}{description}""" +{name: <17}{available: <11}{entitled: <11}{auto_enabled: <14}{description}""" -STATUS_HEADER = "SERVICE ENTITLED STATUS DESCRIPTION" +STATUS_HEADER = "SERVICE ENTITLED STATUS DESCRIPTION" # The widths listed below for entitled and status are actually 9 characters # less than reality because we colorize the values in entitled and status # columns. Colorizing has an opening and closing set of unprintable characters # that factor into formats len() calculations -STATUS_TMPL = "{name: <14}{entitled: <19}{status: <19}{description}" +STATUS_TMPL = "{name: <17}{entitled: <19}{status: <19}{description}" def colorize(string: str) -> str: diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/tests/test_cli_attach.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/tests/test_cli_attach.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/tests/test_cli_attach.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/tests/test_cli_attach.py 2022-04-14 18:32:40.000000000 +0000 @@ -532,14 +532,14 @@ assert expected == json.loads(fake_stdout.getvalue()) @mock.patch("uaclient.contract.process_entitlement_delta") - @mock.patch("uaclient.util.apply_series_overrides") + @mock.patch("uaclient.util.apply_contract_overrides") @mock.patch("uaclient.contract.UAContractClient.request_url") @mock.patch("uaclient.jobs.update_messaging.update_apt_and_motd_messages") def test_attach_when_one_service_fails_to_enable( self, _m_update_messages, m_request_url, - _m_apply_series_overrides, + _m_apply_contract_overrides, m_process_entitlement_delta, _m_getuid, FakeConfig, diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/tests/test_cli_collect_logs.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/tests/test_cli_collect_logs.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/tests/test_cli_collect_logs.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/tests/test_cli_collect_logs.py 2022-04-14 18:32:40.000000000 +0000 @@ -124,8 +124,8 @@ ), ] - assert m_copy.call_count == 14 - assert redact.call_count == 14 + assert m_copy.call_count == 15 + assert redact.call_count == 15 class TestParser: diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/tests/test_cli_status.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/tests/test_cli_status.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/tests/test_cli_status.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/tests/test_cli_status.py 2022-04-14 18:32:40.000000000 +0000 @@ -24,6 +24,7 @@ {"name": "esm-infra", "available": False}, {"name": "esm-apps", "available": True}, {"name": "fips-updates", "available": False}, + {"name": "realtime-kernel", "available": False}, {"name": "ros", "available": False}, {"name": "ros-updates", "available": False}, ] @@ -68,41 +69,34 @@ } SIMULATED_STATUS = """\ -SERVICE AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION -esm-infra no yes yes UA Infra: Extended Security\ - Maintenance (ESM) -fips no no no NIST-certified core packages -fips-updates no no no NIST-certified core packages\ - with priority security updates -livepatch yes yes no Canonical Livepatch service -""" +SERVICE AVAILABLE ENTITLED AUTO_ENABLED DESCRIPTION +esm-infra no yes yes UA Infra: Extended Security Maintenance (ESM) +fips no no no NIST-certified core packages +fips-updates no no no NIST-certified core packages with priority security updates +livepatch yes yes no Canonical Livepatch service +""" # noqa: E501 UNATTACHED_STATUS = """\ -SERVICE AVAILABLE DESCRIPTION -esm-infra no UA Infra: Extended Security Maintenance (ESM) -fips no NIST-certified core packages -fips-updates no NIST-certified core packages with priority\ - security updates -livepatch yes Canonical Livepatch service +SERVICE AVAILABLE DESCRIPTION +esm-infra no UA Infra: Extended Security Maintenance (ESM) +fips no NIST-certified core packages +fips-updates no NIST-certified core packages with priority security updates +livepatch yes Canonical Livepatch service This machine is not attached to a UA subscription. See https://ubuntu.com/advantage -""" +""" # noqa: E501 ATTACHED_STATUS = """\ -SERVICE ENTITLED STATUS DESCRIPTION -esm-apps no {dash} UA Apps: Extended Security Maintenance\ - (ESM) -esm-infra no {dash} UA Infra: Extended Security Maintenance\ - (ESM) -fips no {dash} NIST-certified core packages -fips-updates no {dash} NIST-certified core packages with\ - priority security updates -livepatch no {dash} Canonical Livepatch service -ros no {dash} Security Updates for the Robot\ - Operating System -ros-updates no {dash} All Updates for the Robot Operating\ - System +SERVICE ENTITLED STATUS DESCRIPTION +esm-apps no {dash} UA Apps: Extended Security Maintenance (ESM) +esm-infra no {dash} UA Infra: Extended Security Maintenance (ESM) +fips no {dash} NIST-certified core packages +fips-updates no {dash} NIST-certified core packages with priority security updates +livepatch no {dash} Canonical Livepatch service +realtime-kernel no {dash} Beta-version Ubuntu Kernel with PREEMPT_RT patches +ros no {dash} Security Updates for the Robot Operating System +ros-updates no {dash} All Updates for the Robot Operating System {notices} Enable services with: ua enable @@ -110,17 +104,15 @@ Subscription: test_contract Valid until: 2040-05-08 19:02:26+00:00 Technical support level: n/a -""" +""" # noqa: E501 # Omit beta services from status ATTACHED_STATUS_NOBETA = """\ -SERVICE ENTITLED STATUS DESCRIPTION -esm-infra no {dash} UA Infra: Extended Security Maintenance\ - (ESM) -fips no {dash} NIST-certified core packages -fips-updates no {dash} NIST-certified core packages with\ - priority security updates -livepatch no {dash} Canonical Livepatch service +SERVICE ENTITLED STATUS DESCRIPTION +esm-infra no {dash} UA Infra: Extended Security Maintenance (ESM) +fips no {dash} NIST-certified core packages +fips-updates no {dash} NIST-certified core packages with priority security updates +livepatch no {dash} Canonical Livepatch service {notices} Enable services with: ua enable @@ -128,9 +120,9 @@ Subscription: test_contract Valid until: 2040-05-08 19:02:26+00:00 Technical support level: n/a -""" +""" # noqa: E501 -BETA_SVC_NAMES = ["esm-apps", "ros", "ros-updates"] +BETA_SVC_NAMES = ["esm-apps", "realtime-kernel", "ros", "ros-updates"] SERVICES_JSON_ALL = [ { @@ -186,6 +178,16 @@ "blocked_by": [], }, { + "description": "TODO", + "description_override": None, + "entitled": "no", + "name": "realtime-kernel", + "status": "—", + "status_details": "", + "available": "yes", + "blocked_by": [], + }, + { "description": "Security Updates for the Robot Operating System", "description_override": None, "entitled": "no", @@ -739,6 +741,14 @@ { "auto_enabled": "no", "available": "no", + "description": "Beta-version Ubuntu Kernel with PREEMPT_RT" + " patches", + "entitled": "no", + "name": "realtime-kernel", + }, + { + "auto_enabled": "no", + "available": "no", "description": "Security Updates for the Robot Operating" " System", "entitled": "no", @@ -754,7 +764,7 @@ ] if not use_all: - expected_services = expected_services[1:-2] + expected_services = expected_services[1:-3] expected = { "_doc": "Content provided in json response is currently considered" diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/tests/test_upgrade_lts_contract.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/tests/test_upgrade_lts_contract.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/tests/test_upgrade_lts_contract.py 2021-11-09 16:01:46.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/tests/test_upgrade_lts_contract.py 2022-04-14 18:32:40.000000000 +0000 @@ -16,7 +16,7 @@ def test_unattached_noops(self, m_is_attached, capsys, caplog_text): expected_logs = [ "Check whether to upgrade-lts-contract", - "Skiping upgrade-lts-contract. Machine is unattached", + "Skipping upgrade-lts-contract. Machine is unattached", ] process_contract_delta_after_apt_lock() @@ -52,6 +52,72 @@ assert 1 == execinfo.value.code assert 1 == m_is_attached.call_count + assert 1 == m_parse_os.call_count + assert 1 == m_subp.call_count + out, _err = capsys.readouterr() + assert out == "\n".join(expected_msgs) + "\n" + debug_logs = caplog_text() + for log in expected_msgs + expected_logs: + assert log in debug_logs + + @mock.patch( + "uaclient.config.UAConfig.is_attached", + new_callable=mock.PropertyMock, + return_value=True, + ) + @mock.patch("lib.upgrade_lts_contract.parse_os_release") + @mock.patch("lib.upgrade_lts_contract.subp") + def test_upgrade_cancel_when_current_version_not_supported( + self, m_subp, m_parse_os, m_is_attached, capsys, caplog_text + ): + m_parse_os.return_value = {"VERSION_ID": "NOT-SUPPORTED"} + m_subp.return_value = ("", "") + + expected_msgs = [ + "Starting upgrade-lts-contract.", + "Unable to get release codename for version: NOT-SUPPORTED", + ] + expected_logs = ["Check whether to upgrade-lts-contract"] + with pytest.raises(SystemExit) as execinfo: + process_contract_delta_after_apt_lock() + + assert 1 == execinfo.value.code + assert 1 == m_is_attached.call_count + assert 1 == m_parse_os.call_count + assert 1 == m_subp.call_count + out, _err = capsys.readouterr() + assert out == "\n".join(expected_msgs) + "\n" + debug_logs = caplog_text() + for log in expected_msgs + expected_logs: + assert log in debug_logs + + @mock.patch( + "uaclient.config.UAConfig.is_attached", + new_callable=mock.PropertyMock, + return_value=True, + ) + @mock.patch("lib.upgrade_lts_contract.parse_os_release") + @mock.patch("lib.upgrade_lts_contract.subp") + def test_upgrade_cancel_when_past_version_not_supported( + self, m_subp, m_parse_os, m_is_attached, capsys, caplog_text + ): + m_parse_os.return_value = {"VERSION_ID": "20.10"} + m_subp.return_value = ("", "") + + expected_msgs = [ + "Starting upgrade-lts-contract.", + "Could not find past release for: groovy", + ] + expected_logs = ["Check whether to upgrade-lts-contract"] + with pytest.raises(SystemExit) as execinfo: + with mock.patch( + "lib.upgrade_lts_contract.version_to_codename", + {"20.10": "groovy"}, + ): + process_contract_delta_after_apt_lock() + + assert 1 == execinfo.value.code + assert 1 == m_is_attached.call_count assert 1 == m_parse_os.call_count assert 1 == m_subp.call_count out, _err = capsys.readouterr() diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/tests/test_util.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/tests/test_util.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/tests/test_util.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/tests/test_util.py 2022-04-14 18:32:40.000000000 +0000 @@ -474,57 +474,244 @@ assert expected == util.get_platform_info.__wrapped__() -class TestApplySeriesOverrides: +class TestApplyContractOverrides: + @pytest.mark.parametrize( + "override_selector,expected_weight", + ( + ({"selector1": "valueX", "selector2": "valueZ"}, 0), + ({"selector1": "valueA", "selector2": "valueZ"}, 0), + ({"selector1": "valueX", "selector2": "valueB"}, 0), + ({"selector1": "valueA"}, 1), + ({"selector2": "valueB"}, 2), + ({"selector1": "valueA", "selector2": "valueB"}, 3), + ), + ) + def test_get_override_weight(self, override_selector, expected_weight): + selector_values = {"selector1": "valueA", "selector2": "valueB"} + selector_weights = {"selector1": 1, "selector2": 2} + with mock.patch( + "uaclient.util.OVERRIDE_SELECTOR_WEIGHTS", selector_weights + ): + assert expected_weight == util._get_override_weight( + override_selector, selector_values + ) + def test_error_on_non_entitlement_dict(self): """Raise a runtime error when seeing invalid dict type.""" with pytest.raises(RuntimeError) as exc: - util.apply_series_overrides({"some": "dict"}) + util.apply_contract_overrides({"some": "dict"}) error = ( 'Expected entitlement access dict. Missing "entitlement" key:' " {'some': 'dict'}" ) assert error == str(exc.value) + @pytest.mark.parametrize("include_overrides", (True, False)) @mock.patch( - "uaclient.util.get_platform_info", return_value={"series": "xenial"} + "uaclient.util.get_platform_info", return_value={"series": "ubuntuX"} ) - def test_mutates_orig_access_dict(self, _): - """Mutate orig_access dict when called.""" + @mock.patch( + "uaclient.clouds.identity.get_cloud_type", return_value=(None, "") + ) + def test_return_same_dict_when_no_overrides_match( + self, _m_cloud_type, _m_platform_info, include_overrides + ): orig_access = { "entitlement": { - "a": {"a1": "av1", "a2": {"aa2": "aav2"}}, - "b": "b1", - "c": "c1", + "affordances": {"some_affordance": ["ubuntuX"]}, + "directives": {"some_directive": ["ubuntuX"]}, + "obligations": {"some_obligation": False}, + } + } + # exactly the same + expected = { + "entitlement": { + "affordances": {"some_affordance": ["ubuntuX"]}, + "directives": {"some_directive": ["ubuntuX"]}, + "obligations": {"some_obligation": False}, + } + } + if include_overrides: + orig_access["entitlement"].update( + { + "series": { + "dontMatch": { + "affordances": { + "some_affordance": ["ubuntuX-series-overriden"] + } + } + }, + "overrides": [ + { + "selector": {"series": "dontMatch"}, + "affordances": { + "some_affordance": ["ubuntuX-series-overriden"] + }, + }, + { + "selector": {"cloud": "dontMatch"}, + "affordances": { + "some_affordance": ["ubuntuX-cloud-overriden"] + }, + }, + ], + } + ) + + util.apply_contract_overrides(orig_access) + assert expected == orig_access + + @mock.patch( + "uaclient.util.get_platform_info", return_value={"series": "ubuntuX"} + ) + def test_missing_keys_are_included(self, _m_platform_info): + orig_access = { + "entitlement": { + "series": {"ubuntuX": {"directives": {"suites": ["ubuntuX"]}}} + } + } + expected = {"entitlement": {"directives": {"suites": ["ubuntuX"]}}} + + util.apply_contract_overrides(orig_access) + + assert expected == orig_access + + @pytest.mark.parametrize( + "series_selector,cloud_selector,series_cloud_selector,expected_value", + ( + # apply_overrides_when_only_series_match + ("no-match", "no-match", "no-match", "old_series_overriden"), + # series selector is applied over old series override + ("ubuntuX", "no-match", "no-match", "series_overriden"), + # cloud selector is applied over series override + ("no-match", "cloudX", "no-match", "cloud_overriden"), + # cloud selector is applied over series selector + ("ubuntuX", "cloudX", "no-match", "cloud_overriden"), + # cloud and series together are applied over others + ("ubuntuX", "cloudX", "cloudX", "both_overriden"), + ), + ) + @mock.patch( + "uaclient.util.get_platform_info", return_value={"series": "ubuntuX"} + ) + @mock.patch( + "uaclient.clouds.identity.get_cloud_type", + return_value=("cloudX", None), + ) + def test_applies_contract_overrides_respecting_weight( + self, + _m_cloud_type, + _m_platform_info, + series_selector, + cloud_selector, + series_cloud_selector, + expected_value, + ): + """Apply the expected overrides to orig_access dict when called.""" + orig_access = { + "entitlement": { + "affordances": {"some_affordance": ["original_affordance"]}, "series": { - "trusty": {"a": "t1"}, - "xenial": {"a": {"a2": {"aa2": "xxv2"}}, "b": "bx1"}, + "ubuntuX": { + "affordances": { + "some_affordance": ["old_series_overriden"] + } + } }, + "overrides": [ + { + "selector": {"series": series_selector}, + "affordances": { + "some_affordance": ["series_overriden"] + }, + }, + { + "selector": {"cloud": cloud_selector}, + "affordances": { + "some_affordance": ["cloud_overriden"] + }, + }, + { + "selector": { + "series": series_selector, + "cloud": series_cloud_selector, + }, + "affordances": {"some_affordance": ["both_overriden"]}, + }, + ], } } + expected = { "entitlement": { - "a": {"a1": "av1", "a2": {"aa2": "xxv2"}}, - "b": "bx1", - "c": "c1", + "affordances": {"some_affordance": [expected_value]} } } - util.apply_series_overrides(orig_access) + + util.apply_contract_overrides(orig_access) assert orig_access == expected @mock.patch( - "uaclient.util.get_platform_info", return_value={"series": "xenial"} + "uaclient.util.get_platform_info", return_value={"series": "ubuntuX"} + ) + @mock.patch( + "uaclient.clouds.identity.get_cloud_type", + return_value=("cloudX", None), ) - def test_missing_keys_are_handled(self, _): + def test_different_overrides_applied_together( + self, _m_cloud_type, _m_platform_info + ): + """Apply different overrides from different matching selectors.""" orig_access = { "entitlement": { - "series": {"xenial": {"directives": {"suites": ["xenial"]}}} + "affordances": {"some_affordance": ["original_affordance"]}, + "directives": {"some_directive": ["original_directive"]}, + "obligations": {"some_obligation": False}, + "series": { + "ubuntuX": { + "affordances": { + "new_affordance": ["new_affordance_value"] + } + } + }, + "overrides": [ + { + "selector": {"series": "ubuntuX"}, + "affordances": { + "some_affordance": ["series_overriden"] + }, + }, + { + "selector": {"cloud": "cloudX"}, + "directives": {"some_directive": ["cloud_overriden"]}, + }, + { + "selector": {"series": "ubuntuX", "cloud": "cloudX"}, + "obligations": { + "new_obligation": True, + "some_obligation": True, + }, + }, + ], } } - expected = {"entitlement": {"directives": {"suites": ["xenial"]}}} - util.apply_series_overrides(orig_access) + expected = { + "entitlement": { + "affordances": { + "new_affordance": ["new_affordance_value"], + "some_affordance": ["series_overriden"], + }, + "directives": {"some_directive": ["cloud_overriden"]}, + "obligations": { + "new_obligation": True, + "some_obligation": True, + }, + } + } - assert expected == orig_access + util.apply_contract_overrides(orig_access) + assert orig_access == expected class TestGetMachineId: @@ -1263,13 +1450,18 @@ assert 1 == m_load_file.call_count @pytest.mark.parametrize( - "installed_pkgs,reboot_required_pkgs,expected_ret", + "installed_pkgs,installed_pkgs_regex,reboot_required_pkgs," + "expected_ret", ( - (set(["a", "b", "c"]), "", False), - (set(["a", "b", "c"]), "a", True), - (set(["a", "b", "c"]), "a\ne", True), - (set(["a", "b", "c"]), "d\ne", False), - (None, "a\ne", True), + (set(["a", "b", "c"]), None, "", False), + (set(["a", "b", "c"]), None, "a", True), + (set(["a", "b", "c"]), None, "a\ne", True), + (set(["a", "b", "c"]), None, "d\ne", False), + (set(["a", "b", "c"]), set(["t.."]), "a\ne", True), + (set(["a", "b", "c"]), set(["t.."]), "one\ntwo", True), + (None, set(["^t..$"]), "one\ntwo", True), + (None, set(["^t..$"]), "one\nthree", False), + (None, None, "a\ne", True), ), ) @mock.patch("os.path.exists") @@ -1279,11 +1471,13 @@ m_load_file, m_path, installed_pkgs, + installed_pkgs_regex, reboot_required_pkgs, expected_ret, ): m_path.return_value = True m_load_file.return_value = reboot_required_pkgs assert expected_ret == util.should_reboot( - installed_pkgs=installed_pkgs + installed_pkgs=installed_pkgs, + installed_pkgs_regex=installed_pkgs_regex, ) diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/util.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/util.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/util.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/util.py 2022-04-14 18:32:40.000000000 +0000 @@ -44,6 +44,8 @@ PROXY_VALIDATION_SNAP_HTTP_URL = "http://api.snapcraft.io" PROXY_VALIDATION_SNAP_HTTPS_URL = "https://api.snapcraft.io" +OVERRIDE_SELECTOR_WEIGHTS = {"series_overrides": 1, "series": 2, "cloud": 3} + event = event_logger.get_event_logger() @@ -100,7 +102,43 @@ return o -def apply_series_overrides( +def _get_override_weight( + override_selector: Dict[str, str], selector_values: Dict[str, str] +) -> int: + override_weight = 0 + for selector, value in override_selector.items(): + if (selector, value) not in selector_values.items(): + return 0 + override_weight += OVERRIDE_SELECTOR_WEIGHTS[selector] + + return override_weight + + +def _select_overrides( + entitlement: Dict[str, Any], series_name: str, cloud_type: str +) -> Dict[int, Dict[str, Any]]: + overrides = {} + + selector_values = {"series": series_name, "cloud": cloud_type} + + series_overrides = entitlement.pop("series", {}).pop(series_name, {}) + if series_overrides: + overrides[ + OVERRIDE_SELECTOR_WEIGHTS["series_overrides"] + ] = series_overrides + + general_overrides = entitlement.pop("overrides", []) + for override in general_overrides: + weight = _get_override_weight( + override.pop("selector"), selector_values + ) + if weight: + overrides[weight] = override + + return overrides + + +def apply_contract_overrides( orig_access: Dict[str, Any], series: str = None ) -> None: """Apply series-specific overrides to an entitlement dict. @@ -117,23 +155,30 @@ :param orig_access: Dict with original entitlement access details """ + from uaclient.clouds.identity import get_cloud_type + if not all([isinstance(orig_access, dict), "entitlement" in orig_access]): raise RuntimeError( 'Expected entitlement access dict. Missing "entitlement" key:' " {}".format(orig_access) ) + series_name = get_platform_info()["series"] if series is None else series + cloud_type, _ = get_cloud_type() orig_entitlement = orig_access.get("entitlement", {}) - overrides = orig_entitlement.pop("series", {}).pop(series_name, {}) - for key, value in overrides.items(): - current = orig_access["entitlement"].get(key) - if isinstance(current, dict): - # If the key already exists and is a dict, update that dict using - # the override - current.update(value) - else: - # Otherwise, replace it wholesale - orig_access["entitlement"][key] = value + + overrides = _select_overrides(orig_entitlement, series_name, cloud_type) + + for _weight, overrides_to_apply in sorted(overrides.items()): + for key, value in overrides_to_apply.items(): + current = orig_access["entitlement"].get(key) + if isinstance(current, dict): + # If the key already exists and is a dict, + # update that dict using the override + current.update(value) + else: + # Otherwise, replace it wholesale + orig_access["entitlement"][key] = value def del_file(path: str) -> None: @@ -431,13 +476,16 @@ return value -def prompt_for_confirmation(msg: str = "", assume_yes: bool = False) -> bool: +def prompt_for_confirmation( + msg: str = "", assume_yes: bool = False, default: bool = False +) -> bool: """ Display a confirmation prompt, returning a bool indicating the response :param msg: String custom prompt text to emit from input call. :param assume_yes: Boolean set True to skip confirmation input and return True. + :param default: Boolean to return when user doesn't enter any text This function will only prompt a single time, and defaults to "no" (i.e. it returns False). @@ -446,8 +494,10 @@ return True if not msg: msg = status.PROMPT_YES_NO - value = input(msg) - if value.lower().strip() in ["y", "yes"]: + value = input(msg).lower().strip() + if value == "": + return default + if value in ["y", "yes"]: return True return False @@ -756,14 +806,26 @@ return redacted_log -def should_reboot(installed_pkgs: Optional[Set[str]] = None) -> bool: +def should_reboot( + installed_pkgs: Optional[Set[str]] = None, + installed_pkgs_regex: Optional[Set[str]] = None, +) -> bool: """Check if the system needs to be rebooted. - :param installed_pkgs: If provided, verify if the any packages in - the list are present on /var/run/reboot-required.pkgs. If that - param is provided, we will only return true if we have the - reboot-required marker file and any package in reboot-required.pkgs - file. + :param installed_pkgs: If provided, verify if the any packages in + the list are present on /var/run/reboot-required.pkgs. If that + param is provided, we will only return true if we have the + reboot-required marker file and any package in reboot-required.pkgs + file. When both installed_pkgs and installed_pkgs_regex are + provided, they act as an OR, so only one of the two lists must have + a match to return True. + :param installed_pkgs_regex: If provided, verify if the any regex in + the list matches any line in /var/run/reboot-required.pkgs. If that + param is provided, we will only return true if we have the + reboot-required marker file and any match in reboot-required.pkgs + file. When both installed_pkgs and installed_pkgs_regex are + provided, they act as an OR, so only one of the two lists must have + a match to return True. """ # If the reboot marker file doesn't exist, we don't even @@ -773,7 +835,7 @@ # If there is no installed_pkgs to check, we will rely only # on the existence of the reboot marker file - if installed_pkgs is None: + if installed_pkgs is None and installed_pkgs_regex is None: return True try: @@ -784,8 +846,18 @@ # If the file doesn't exist, we will default to the # reboot marker file return True - else: - return len(installed_pkgs.intersection(reboot_required_pkgs)) != 0 + + if installed_pkgs is not None: + if len(installed_pkgs.intersection(reboot_required_pkgs)) != 0: + return True + + if installed_pkgs_regex is not None: + for pkg_name in reboot_required_pkgs: + for pkg_regex in installed_pkgs_regex: + if re.search(pkg_regex, pkg_name): + return True + + return False def is_installed(package_name: str) -> bool: diff -Nru ubuntu-advantage-tools-27.7~20.04.1/uaclient/version.py ubuntu-advantage-tools-27.8~20.04.1/uaclient/version.py --- ubuntu-advantage-tools-27.7~20.04.1/uaclient/version.py 2022-03-10 17:17:34.000000000 +0000 +++ ubuntu-advantage-tools-27.8~20.04.1/uaclient/version.py 2022-04-14 18:32:40.000000000 +0000 @@ -8,7 +8,7 @@ from uaclient import exceptions, util -__VERSION__ = "27.7" +__VERSION__ = "27.8" PACKAGED_VERSION = "@@PACKAGED_VERSION@@" VERSION_TMPL = "{version}{feature_suffix}"