~robert-ancell/update-manager/ua-focal

« back to all changes in this revision

Viewing changes to ubuntu-security-status

  • Committer: Robert Ancell
  • Author(s): Brian Murray
  • Date: 2022-09-20 22:40:37 UTC
  • Revision ID: robert.ancell@canonical.com-20220920224037-512kg5jws1o49br6
ubuntu-security-status: use ubuntu-advantage-tools to determine whether or
not livepatch or esm are enabled and if the system is attached. Thanks to
Chad Smith for the patch. (LP: #1938043)

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
import apt
4
4
import argparse
5
5
import distro_info
 
6
import json
6
7
import os
7
8
import sys
8
9
import gettext
17
18
 
18
19
# TODO make DEBUG an environmental variable
19
20
DEBUG = False
 
21
UA_STATUS_FILE = "/var/lib/ubuntu-advantage/status.json"
20
22
 
21
23
 
22
24
class PatchStats:
81
83
    return pkgs
82
84
 
83
85
 
84
 
def livepatch_is_enabled():
85
 
    """ Check to see if livepatch is enabled on the system"""
 
86
def get_ua_status():
 
87
    """Return dict of active ua status information from ubuntu-advantage-tools
 
88
 
 
89
    Prefer to obtain status information from cache on disk to avoid costly
 
90
    roundtrips to contracts.canonical.com to check on available services.
 
91
 
 
92
    Fallback to call ua status --format=json.
 
93
 
 
94
    If there are errors running: ua status --format=json or if the status on
 
95
    disk is unparseable, return an empty dict.
 
96
    """
 
97
    if os.path.exists(UA_STATUS_FILE):
 
98
        with open(UA_STATUS_FILE, "r") as stream:
 
99
            status = stream.read()
 
100
    else:
 
101
        try:
 
102
            status = subprocess.check_output(
 
103
                ['ua', 'status', '--format=json']
 
104
            ).decode()
 
105
        except subprocess.CalledProcessError as e:
 
106
            print_debug('failed to run ua status: %s' % e)
 
107
            return {}
86
108
    try:
87
 
        c_livepatch = subprocess.run(["/snap/bin/canonical-livepatch",
88
 
                                      "status"],
89
 
                                     stdout=subprocess.PIPE,
90
 
                                     stderr=subprocess.PIPE)
91
 
    # it can't be enabled if it isn't installed
92
 
    except FileNotFoundError:
93
 
        return False
94
 
    if c_livepatch.returncode == 0:
95
 
        return True
96
 
    elif c_livepatch.returncode == 1:
97
 
        return False
98
 
 
99
 
 
100
 
def esm_is_enabled():
101
 
    """ Check to see if esm is an available source"""
102
 
    acp = subprocess.Popen(["apt-cache", "policy"],
103
 
                           stdout=subprocess.PIPE, stderr=subprocess.PIPE)
104
 
    grep = subprocess.run(["grep", "-F", "-q", "https://%s" % esm_site],
105
 
                          stdin=acp.stdout, stdout=subprocess.PIPE)
106
 
    if grep.returncode == 0:
107
 
        return True
108
 
    elif grep.returncode == -1:
109
 
        return False
 
109
        return json.loads(status)
 
110
    except json.decoder.JSONDecodeError as e:
 
111
        print_debug('failed to parse JSON from ua status output: %s' % e)
 
112
        return {}
 
113
 
 
114
 
 
115
def is_ua_service_enabled(service_name: str) -> bool:
 
116
    """Check to see if named esm service is enabled.
 
117
 
 
118
    :return: True if UA status reports service as enabled.
 
119
    """
 
120
    status = get_ua_status()
 
121
    for service in status.get("services", []):
 
122
        if service["name"] == service_name:
 
123
            # Machines unattached to UA will not provide service 'status' key.
 
124
            return service.get("status") == "enabled"
 
125
    return False
110
126
 
111
127
 
112
128
def trim_archive(archive):
353
369
                                   "%s-apps-security" % codename,
354
370
                                   "main")
355
371
 
356
 
    livepatch_enabled = livepatch_is_enabled()
357
 
    esm_enabled = esm_is_enabled()
358
 
    is_esm_infra_used = (suite_esm_main in all_origins) or \
359
 
                        (suite_esm_main_security in all_origins)
360
 
    is_esm_apps_used = (suite_esm_universe in all_origins) or \
361
 
                       (suite_esm_universe_security in all_origins)
 
372
    livepatch_enabled = is_ua_service_enabled("livepatch")
 
373
    esm_enabled = is_ua_service_enabled("esm-infra")
 
374
    ua_attached = get_ua_status().get("attached", False)
362
375
 
363
376
    # Now do the final loop through
364
377
    for pkg in cache:
561
574
                           len(pkgstats.pkgs_um)))
562
575
            if livepatch_enabled:
563
576
                print("\nEnable ESM Apps with: ua enable esm-apps")
564
 
    if lts and not livepatch_enabled:
 
577
    if lts and not ua_attached:
565
578
        print("\nThis machine is not attached to an Ubuntu Advantage "
566
579
              "subscription.\nSee https://ubuntu.com/advantage")