Linux lhjmq-records 5.15.0-118-generic #128-Ubuntu SMP Fri Jul 5 09:28:59 UTC 2024 x86_64
Your IP : 3.145.108.87
# This file is part of cloud-init. See LICENSE file for license information.
"""Ubuntu Drivers: Interact with third party drivers in Ubuntu."""
import os
from textwrap import dedent
from cloudinit.cloud import Cloud
from cloudinit.distros import Distro
try:
import debconf
HAS_DEBCONF = True
except ImportError:
debconf = None
HAS_DEBCONF = False
from logging import Logger
from cloudinit import log as logging
from cloudinit import subp, temp_utils, type_utils, util
from cloudinit.config import Config
from cloudinit.config.schema import MetaSchema, get_meta_doc
from cloudinit.settings import PER_INSTANCE
LOG = logging.getLogger(__name__)
distros = ["ubuntu"]
meta: MetaSchema = {
"id": "cc_ubuntu_drivers",
"name": "Ubuntu Drivers",
"title": "Interact with third party drivers in Ubuntu.",
"description": dedent(
"""\
This module interacts with the 'ubuntu-drivers' command to install
third party driver packages."""
),
"distros": distros,
"examples": [
dedent(
"""\
drivers:
nvidia:
license-accepted: true
"""
)
],
"frequency": PER_INSTANCE,
"activate_by_schema_keys": ["drivers"],
}
__doc__ = get_meta_doc(meta)
OLD_UBUNTU_DRIVERS_STDERR_NEEDLE = (
"ubuntu-drivers: error: argument <command>: invalid choice: 'install'"
)
# Use a debconf template to configure a global debconf variable
# (linux/nvidia/latelink) setting this to "true" allows the
# 'linux-restricted-modules' deb to accept the NVIDIA EULA and the package
# will automatically link the drivers to the running kernel.
NVIDIA_DEBCONF_CONTENT = """\
Template: linux/nvidia/latelink
Type: boolean
Default: true
Description: Late-link NVIDIA kernel modules?
Enable this to link the NVIDIA kernel modules in cloud-init and
make them available for use.
"""
X_LOADTEMPLATEFILE = "X_LOADTEMPLATEFILE"
def install_drivers(cfg, pkg_install_func, distro: Distro):
if not isinstance(cfg, dict):
raise TypeError(
"'drivers' config expected dict, found '%s': %s"
% (type_utils.obj_name(cfg), cfg)
)
cfgpath = "nvidia/license-accepted"
# Call translate_bool to ensure that we treat string values like "yes" as
# acceptance and _don't_ treat string values like "nah" as acceptance
# because they're True-ish
nv_acc = util.translate_bool(util.get_cfg_by_path(cfg, cfgpath))
if not nv_acc:
LOG.debug("Not installing NVIDIA drivers. %s=%s", cfgpath, nv_acc)
return
if not subp.which("ubuntu-drivers"):
LOG.debug(
"'ubuntu-drivers' command not available. "
"Installing ubuntu-drivers-common"
)
pkg_install_func(["ubuntu-drivers-common"])
driver_arg = "nvidia"
version_cfg = util.get_cfg_by_path(cfg, "nvidia/version")
if version_cfg:
driver_arg += ":{}".format(version_cfg)
LOG.debug(
"Installing and activating NVIDIA drivers (%s=%s, version=%s)",
cfgpath,
nv_acc,
version_cfg if version_cfg else "latest",
)
# Register and set debconf selection linux/nvidia/latelink = true
tdir = temp_utils.mkdtemp(dir=distro.get_tmp_exec_path(), needs_exe=True)
debconf_file = os.path.join(tdir, "nvidia.template")
try:
util.write_file(debconf_file, NVIDIA_DEBCONF_CONTENT)
with debconf.DebconfCommunicator("cloud-init") as dc:
dc.command(X_LOADTEMPLATEFILE, debconf_file)
except Exception as e:
util.logexc(
LOG, "Failed to register NVIDIA debconf template: %s", str(e)
)
raise
finally:
if os.path.isdir(tdir):
util.del_dir(tdir)
try:
subp.subp(["ubuntu-drivers", "install", "--gpgpu", driver_arg])
except subp.ProcessExecutionError as exc:
if OLD_UBUNTU_DRIVERS_STDERR_NEEDLE in exc.stderr:
LOG.warning(
"the available version of ubuntu-drivers is"
" too old to perform requested driver installation"
)
elif "No drivers found for installation." in exc.stdout:
LOG.warning("ubuntu-drivers found no drivers for installation")
raise
def handle(
name: str, cfg: Config, cloud: Cloud, log: Logger, args: list
) -> None:
if "drivers" not in cfg:
log.debug("Skipping module named %s, no 'drivers' key in config", name)
return
if not HAS_DEBCONF:
log.warning(
"Skipping module named %s, 'python3-debconf' is not installed",
name,
)
return
install_drivers(
cfg["drivers"], cloud.distro.install_packages, cloud.distro
)
|