Merge ~chad.smith/cloud-init:bug/1840080-ubuntu-drivers-emit-latelink-v2 into cloud-init:master

Proposed by Chad Smith on 2019-08-20
Status: Merged
Approved by: Dan Watkins on 2019-08-22
Approved revision: 2eb8eee7281a84a832f865a7ddd0edabe534e987
Merge reported by: Server Team CI bot
Merged at revision: not available
Proposed branch: ~chad.smith/cloud-init:bug/1840080-ubuntu-drivers-emit-latelink-v2
Merge into: cloud-init:master
Diff against target: 310 lines (+130/-36)
3 files modified
cloudinit/config/cc_ubuntu_drivers.py (+48/-10)
cloudinit/config/tests/test_ubuntu_drivers.py (+80/-25)
cloudinit/tests/helpers.py (+2/-1)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve on 2019-08-22
cloud-init Commiters 2019-08-20 Pending
Review via email: mp+371546@code.launchpad.net

Commit message

ubuntu-drivers: call db_x_loadtemplatefile to accept NVIDIA EULA

Emit a script allowing cloud-init to set linux/nvidia/latelink
debconf selection to true. This avoids having to call
debconf-set-selections and allows cloud-init to pre-confgure
linux-restricted-modules to link NVIDIA drivers to the running kernel.

Cloud-init loads this debconf template and sets the value to true in the
debconf database by sourcing debconf's /usr/share/debconf/confmodule and
uses db_x_loadtemplatefile to register cloud-init's setting for
linux/nvidia/latelink.

LP: #1840080

To post a comment you must log in.

FAILED: Continuous integration, rev:044f9d692ebca82186b9159a69e75816ad99f998
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1060/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1060//rebuild

review: Needs Fixing (continuous-integration)
Ryan Harper (raharper) wrote :

some inline comments/suggestions.

Chad Smith (chad.smith) :

FAILED: Continuous integration, rev:71fcd42be6330033bcb731080053a885786f2130
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1061/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1061//rebuild

review: Needs Fixing (continuous-integration)

PASSED: Continuous integration, rev:48733aa42ac30013db4ce3daa7643ee941b51b63
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1062/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1062//rebuild

review: Approve (continuous-integration)

FAILED: Continuous integration, rev:cdd846983dc8d3dca53d3c37d69c0c967787a7ae
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1063/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    FAILED: Ubuntu LTS: Integration

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1063//rebuild

review: Needs Fixing (continuous-integration)
Chad Smith (chad.smith) wrote :

Just validated on Eoan that this package properly sets up linux/nvidia/latelink true via debconf-get-selections.

The ubuntu-drivers-common package fixes has not yet published to Eoan. So, end-to-end validation will not be possible until an updated ubuntu-drivers-common and linux-modules-nvidia* is published.

As it is, this behavior paves the way for the ubuntu-drivers-common/linux-modules-nvidia package features.

# cloud-init properly registers and sets linux/nvidia/latelink : true
ubuntu@ip-172-31-30-68:~$ sudo debconf-get-selections | egrep 'cloud-init|late'
cloud-init linux/nvidia/latelink boolean true
cloud-init cloud-init/datasources multiselect NoCloud, ConfigDrive, OpenNebula, DigitalOcean, Azure, AltCloud, OVF, MAAS, GCE, OpenStack, CloudSigma, SmartOS, Bigstep, Scaleway, AliYun, Ec2, CloudStack, Hetzner, IBMCloud, None

# ubuntu-drivers-common was installed, but no linux-modules-nvidia-* yet
dpkg -l | egrep 'cloud-init|nvidia|ubuntu-drivers'
ii cloud-init 19.2-21-gcdd84698-1~bddeb all Init scripts for cloud instances
ii cloud-initramfs-copymods 0.44ubuntu1 all copy initramfs modules into root filesystem for later use
ii cloud-initramfs-dyn-netconf 0.44ubuntu1 all write a network interface file in /run for BOOTIF
ii libnvidia-cfg1-430:amd64 430.40-0ubuntu2 amd64 NVIDIA binary OpenGL/GLX configuration library
ii libnvidia-compute-430:amd64 430.40-0ubuntu2 amd64 NVIDIA libcompute package
ii nvidia-compute-utils-430 430.40-0ubuntu2 amd64 NVIDIA compute utilities
ii nvidia-headless-no-dkms-430 430.40-0ubuntu2 amd64 NVIDIA headless metapackage - no DKMS
ii nvidia-kernel-source-430 430.40-0ubuntu2 amd64 NVIDIA kernel source package
ii ubuntu-drivers-common 1:0.7.5 amd64 Detect and install additional Ubuntu driver packages

### If we manually install linux-modules-nvidia-430-generic, latelink appears set true
ubuntu@ip-172-31-16-66:~$ sudo debconf-get-selections | grep late
cloud-init linux/nvidia/latelink boolean true
linux-modules-nvidia-430-5.2.0-13-generic linux/nvidia/latelink booleantrue

# from dpkg -l on eoan-proposed
ii linux-modules-nvidia-430-5.2.0-13-generic 5.2.0-13.14 amd64 Linux kernel nvidia modules for version 5.2.0-13

Ryan Harper (raharper) wrote :

Implementation looks great. One suggestion on the template description.

PASSED: Continuous integration, rev:cdd846983dc8d3dca53d3c37d69c0c967787a7ae
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1064/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1064//rebuild

review: Approve (continuous-integration)

FAILED: Continuous integration, rev:8da37261c56c583b1631cbae9910a100c7894c6e
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1065/
Executed test runs:
    SUCCESS: Checkout
    FAILED: Unit & Style Tests

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1065//rebuild

review: Needs Fixing (continuous-integration)

PASSED: Continuous integration, rev:19dbf5e1449cfa59b9f8fbfb056d182516543eb1
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1066/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1066//rebuild

review: Approve (continuous-integration)

Autolanding: FAILED
More details in the following jenkins job:
https://jenkins.ubuntu.com/server/job/cloud-init-autoland-test/294/
Executed test runs:
    FAILED: Checkout

review: Needs Fixing (continuous-integration)

Autolanding: FAILED
More details in the following jenkins job:
https://jenkins.ubuntu.com/server/job/cloud-init-autoland-test/295/
Executed test runs:
    FAILED: Checkout

review: Needs Fixing (continuous-integration)

Autolanding: FAILED
More details in the following jenkins job:
https://jenkins.ubuntu.com/server/job/cloud-init-autoland-test/296/
Executed test runs:
    FAILED: Checkout

review: Needs Fixing (continuous-integration)
review: Approve (continuous-integration)

Autolanding: FAILED
Unapproved changes made after approval.
https://jenkins.ubuntu.com/server/job/cloud-init-autoland-test/297/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    IN_PROGRESS: Declarative: Post Actions

review: Needs Fixing (continuous-integration)
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/cloudinit/config/cc_ubuntu_drivers.py b/cloudinit/config/cc_ubuntu_drivers.py
index 4da34ee..297451d 100644
--- a/cloudinit/config/cc_ubuntu_drivers.py
+++ b/cloudinit/config/cc_ubuntu_drivers.py
@@ -2,13 +2,14 @@
22
3"""Ubuntu Drivers: Interact with third party drivers in Ubuntu."""3"""Ubuntu Drivers: Interact with third party drivers in Ubuntu."""
44
5import os
5from textwrap import dedent6from textwrap import dedent
67
7from cloudinit.config import cc_apt_configure
8from cloudinit.config.schema import (8from cloudinit.config.schema import (
9 get_schema_doc, validate_cloudconfig_schema)9 get_schema_doc, validate_cloudconfig_schema)
10from cloudinit import log as logging10from cloudinit import log as logging
11from cloudinit.settings import PER_INSTANCE11from cloudinit.settings import PER_INSTANCE
12from cloudinit import temp_utils
12from cloudinit import type_utils13from cloudinit import type_utils
13from cloudinit import util14from cloudinit import util
1415
@@ -65,6 +66,33 @@ OLD_UBUNTU_DRIVERS_STDERR_NEEDLE = (
65__doc__ = get_schema_doc(schema) # Supplement python help()66__doc__ = get_schema_doc(schema) # Supplement python help()
6667
6768
69# Use a debconf template to configure a global debconf variable
70# (linux/nvidia/latelink) setting this to "true" allows the
71# 'linux-restricted-modules' deb to accept the NVIDIA EULA and the package
72# will automatically link the drivers to the running kernel.
73
74# EOL_XENIAL: can then drop this script and use python3-debconf which is only
75# available in Bionic and later. Can't use python3-debconf currently as it
76# isn't in Xenial and doesn't yet support X_LOADTEMPLATEFILE debconf command.
77
78NVIDIA_DEBCONF_CONTENT = """\
79Template: linux/nvidia/latelink
80Type: boolean
81Default: true
82Description: Late-link NVIDIA kernel modules?
83 Enable this to link the NVIDIA kernel modules in cloud-init and
84 make them available for use.
85"""
86
87NVIDIA_DRIVER_LATELINK_DEBCONF_SCRIPT = """\
88#!/bin/sh
89# Allow cloud-init to trigger EULA acceptance via registering a debconf
90# template to set linux/nvidia/latelink true
91. /usr/share/debconf/confmodule
92db_x_loadtemplatefile "$1" cloud-init
93"""
94
95
68def install_drivers(cfg, pkg_install_func):96def install_drivers(cfg, pkg_install_func):
69 if not isinstance(cfg, dict):97 if not isinstance(cfg, dict):
70 raise TypeError(98 raise TypeError(
@@ -90,17 +118,27 @@ def install_drivers(cfg, pkg_install_func):
90 if version_cfg:118 if version_cfg:
91 driver_arg += ':{}'.format(version_cfg)119 driver_arg += ':{}'.format(version_cfg)
92120
93 LOG.debug("Installing NVIDIA drivers (%s=%s, version=%s)",121 LOG.debug("Installing and activating NVIDIA drivers (%s=%s, version=%s)",
94 cfgpath, nv_acc, version_cfg if version_cfg else 'latest')122 cfgpath, nv_acc, version_cfg if version_cfg else 'latest')
95123
96 # Setting NVIDIA latelink confirms acceptance of EULA for the package124 # Register and set debconf selection linux/nvidia/latelink = true
97 # linux-restricted-modules125 tdir = temp_utils.mkdtemp(needs_exe=True)
98 # Reference code defining debconf variable is here126 debconf_file = os.path.join(tdir, 'nvidia.template')
99 # https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/127 debconf_script = os.path.join(tdir, 'nvidia-debconf.sh')
100 # linux-restricted-modules/+git/eoan/tree/debian/templates/128 try:
101 # nvidia.templates.in129 util.write_file(debconf_file, NVIDIA_DEBCONF_CONTENT)
102 selections = b'linux-restricted-modules linux/nvidia/latelink boolean true'130 util.write_file(
103 cc_apt_configure.debconf_set_selections(selections)131 debconf_script,
132 util.encode_text(NVIDIA_DRIVER_LATELINK_DEBCONF_SCRIPT),
133 mode=0o755)
134 util.subp([debconf_script, debconf_file])
135 except Exception as e:
136 util.logexc(
137 LOG, "Failed to register NVIDIA debconf template: %s", str(e))
138 raise
139 finally:
140 if os.path.isdir(tdir):
141 util.del_dir(tdir)
104142
105 try:143 try:
106 util.subp(['ubuntu-drivers', 'install', '--gpgpu', driver_arg])144 util.subp(['ubuntu-drivers', 'install', '--gpgpu', driver_arg])
diff --git a/cloudinit/config/tests/test_ubuntu_drivers.py b/cloudinit/config/tests/test_ubuntu_drivers.py
index 6a763bd..4695269 100644
--- a/cloudinit/config/tests/test_ubuntu_drivers.py
+++ b/cloudinit/config/tests/test_ubuntu_drivers.py
@@ -1,6 +1,7 @@
1# This file is part of cloud-init. See LICENSE file for license information.1# This file is part of cloud-init. See LICENSE file for license information.
22
3import copy3import copy
4import os
45
5from cloudinit.tests.helpers import CiTestCase, skipUnlessJsonSchema, mock6from cloudinit.tests.helpers import CiTestCase, skipUnlessJsonSchema, mock
6from cloudinit.config.schema import (7from cloudinit.config.schema import (
@@ -9,11 +10,27 @@ from cloudinit.config import cc_ubuntu_drivers as drivers
9from cloudinit.util import ProcessExecutionError10from cloudinit.util import ProcessExecutionError
1011
11MPATH = "cloudinit.config.cc_ubuntu_drivers."12MPATH = "cloudinit.config.cc_ubuntu_drivers."
13M_TMP_PATH = MPATH + "temp_utils.mkdtemp"
12OLD_UBUNTU_DRIVERS_ERROR_STDERR = (14OLD_UBUNTU_DRIVERS_ERROR_STDERR = (
13 "ubuntu-drivers: error: argument <command>: invalid choice: 'install' "15 "ubuntu-drivers: error: argument <command>: invalid choice: 'install' "
14 "(choose from 'list', 'autoinstall', 'devices', 'debug')\n")16 "(choose from 'list', 'autoinstall', 'devices', 'debug')\n")
1517
1618
19class AnyTempScriptAndDebconfFile(object):
20
21 def __init__(self, tmp_dir, debconf_file):
22 self.tmp_dir = tmp_dir
23 self.debconf_file = debconf_file
24
25 def __eq__(self, cmd):
26 if not len(cmd) == 2:
27 return False
28 script, debconf_file = cmd
29 if bool(script.startswith(self.tmp_dir) and script.endswith('.sh')):
30 return debconf_file == self.debconf_file
31 return False
32
33
17class TestUbuntuDrivers(CiTestCase):34class TestUbuntuDrivers(CiTestCase):
18 cfg_accepted = {'drivers': {'nvidia': {'license-accepted': True}}}35 cfg_accepted = {'drivers': {'nvidia': {'license-accepted': True}}}
19 install_gpgpu = ['ubuntu-drivers', 'install', '--gpgpu', 'nvidia']36 install_gpgpu = ['ubuntu-drivers', 'install', '--gpgpu', 'nvidia']
@@ -28,20 +45,23 @@ class TestUbuntuDrivers(CiTestCase):
28 {'drivers': {'nvidia': {'license-accepted': "TRUE"}}},45 {'drivers': {'nvidia': {'license-accepted': "TRUE"}}},
29 schema=drivers.schema, strict=True)46 schema=drivers.schema, strict=True)
3047
31 @mock.patch(MPATH + "cc_apt_configure.debconf_set_selections")48 @mock.patch(M_TMP_PATH)
32 @mock.patch(MPATH + "util.subp", return_value=('', ''))49 @mock.patch(MPATH + "util.subp", return_value=('', ''))
33 @mock.patch(MPATH + "util.which", return_value=False)50 @mock.patch(MPATH + "util.which", return_value=False)
34 def _assert_happy_path_taken(51 def _assert_happy_path_taken(
35 self, config, m_which, m_subp, m_debconf_set_selections):52 self, config, m_which, m_subp, m_tmp):
36 """Positive path test through handle. Package should be installed."""53 """Positive path test through handle. Package should be installed."""
54 tdir = self.tmp_dir()
55 debconf_file = os.path.join(tdir, 'nvidia.template')
56 m_tmp.return_value = tdir
37 myCloud = mock.MagicMock()57 myCloud = mock.MagicMock()
38 drivers.handle('ubuntu_drivers', config, myCloud, None, None)58 drivers.handle('ubuntu_drivers', config, myCloud, None, None)
39 self.assertEqual([mock.call(['ubuntu-drivers-common'])],59 self.assertEqual([mock.call(['ubuntu-drivers-common'])],
40 myCloud.distro.install_packages.call_args_list)60 myCloud.distro.install_packages.call_args_list)
41 self.assertEqual([mock.call(self.install_gpgpu)],61 self.assertEqual(
42 m_subp.call_args_list)62 [mock.call(AnyTempScriptAndDebconfFile(tdir, debconf_file)),
43 m_debconf_set_selections.assert_called_with(63 mock.call(self.install_gpgpu)],
44 b'linux-restricted-modules linux/nvidia/latelink boolean true')64 m_subp.call_args_list)
4565
46 def test_handle_does_package_install(self):66 def test_handle_does_package_install(self):
47 self._assert_happy_path_taken(self.cfg_accepted)67 self._assert_happy_path_taken(self.cfg_accepted)
@@ -52,20 +72,33 @@ class TestUbuntuDrivers(CiTestCase):
52 new_config['drivers']['nvidia']['license-accepted'] = true_value72 new_config['drivers']['nvidia']['license-accepted'] = true_value
53 self._assert_happy_path_taken(new_config)73 self._assert_happy_path_taken(new_config)
5474
55 @mock.patch(MPATH + "cc_apt_configure.debconf_set_selections")75 @mock.patch(M_TMP_PATH)
56 @mock.patch(MPATH + "util.subp", side_effect=ProcessExecutionError(76 @mock.patch(MPATH + "util.subp")
57 stdout='No drivers found for installation.\n', exit_code=1))
58 @mock.patch(MPATH + "util.which", return_value=False)77 @mock.patch(MPATH + "util.which", return_value=False)
59 def test_handle_raises_error_if_no_drivers_found(self, m_which, m_subp, _):78 def test_handle_raises_error_if_no_drivers_found(
79 self, m_which, m_subp, m_tmp):
60 """If ubuntu-drivers doesn't install any drivers, raise an error."""80 """If ubuntu-drivers doesn't install any drivers, raise an error."""
81 tdir = self.tmp_dir()
82 debconf_file = os.path.join(tdir, 'nvidia.template')
83 m_tmp.return_value = tdir
61 myCloud = mock.MagicMock()84 myCloud = mock.MagicMock()
85
86 def fake_subp(cmd):
87 if cmd[0].startswith(tdir):
88 return
89 raise ProcessExecutionError(
90 stdout='No drivers found for installation.\n', exit_code=1)
91 m_subp.side_effect = fake_subp
92
62 with self.assertRaises(Exception):93 with self.assertRaises(Exception):
63 drivers.handle(94 drivers.handle(
64 'ubuntu_drivers', self.cfg_accepted, myCloud, None, None)95 'ubuntu_drivers', self.cfg_accepted, myCloud, None, None)
65 self.assertEqual([mock.call(['ubuntu-drivers-common'])],96 self.assertEqual([mock.call(['ubuntu-drivers-common'])],
66 myCloud.distro.install_packages.call_args_list)97 myCloud.distro.install_packages.call_args_list)
67 self.assertEqual([mock.call(self.install_gpgpu)],98 self.assertEqual(
68 m_subp.call_args_list)99 [mock.call(AnyTempScriptAndDebconfFile(tdir, debconf_file)),
100 mock.call(self.install_gpgpu)],
101 m_subp.call_args_list)
69 self.assertIn('ubuntu-drivers found no drivers for installation',102 self.assertIn('ubuntu-drivers found no drivers for installation',
70 self.logs.getvalue())103 self.logs.getvalue())
71104
@@ -113,19 +146,25 @@ class TestUbuntuDrivers(CiTestCase):
113 myLog.debug.call_args_list[0][0][0])146 myLog.debug.call_args_list[0][0][0])
114 self.assertEqual(0, m_install_drivers.call_count)147 self.assertEqual(0, m_install_drivers.call_count)
115148
116 @mock.patch(MPATH + "cc_apt_configure.debconf_set_selections")149 @mock.patch(M_TMP_PATH)
117 @mock.patch(MPATH + "util.subp", return_value=('', ''))150 @mock.patch(MPATH + "util.subp", return_value=('', ''))
118 @mock.patch(MPATH + "util.which", return_value=True)151 @mock.patch(MPATH + "util.which", return_value=True)
119 def test_install_drivers_no_install_if_present(self, m_which, m_subp, _):152 def test_install_drivers_no_install_if_present(
153 self, m_which, m_subp, m_tmp):
120 """If 'ubuntu-drivers' is present, no package install should occur."""154 """If 'ubuntu-drivers' is present, no package install should occur."""
155 tdir = self.tmp_dir()
156 debconf_file = os.path.join(tdir, 'nvidia.template')
157 m_tmp.return_value = tdir
121 pkg_install = mock.MagicMock()158 pkg_install = mock.MagicMock()
122 drivers.install_drivers(self.cfg_accepted['drivers'],159 drivers.install_drivers(self.cfg_accepted['drivers'],
123 pkg_install_func=pkg_install)160 pkg_install_func=pkg_install)
124 self.assertEqual(0, pkg_install.call_count)161 self.assertEqual(0, pkg_install.call_count)
125 self.assertEqual([mock.call('ubuntu-drivers')],162 self.assertEqual([mock.call('ubuntu-drivers')],
126 m_which.call_args_list)163 m_which.call_args_list)
127 self.assertEqual([mock.call(self.install_gpgpu)],164 self.assertEqual(
128 m_subp.call_args_list)165 [mock.call(AnyTempScriptAndDebconfFile(tdir, debconf_file)),
166 mock.call(self.install_gpgpu)],
167 m_subp.call_args_list)
129168
130 def test_install_drivers_rejects_invalid_config(self):169 def test_install_drivers_rejects_invalid_config(self):
131 """install_drivers should raise TypeError if not given a config dict"""170 """install_drivers should raise TypeError if not given a config dict"""
@@ -134,21 +173,33 @@ class TestUbuntuDrivers(CiTestCase):
134 drivers.install_drivers("mystring", pkg_install_func=pkg_install)173 drivers.install_drivers("mystring", pkg_install_func=pkg_install)
135 self.assertEqual(0, pkg_install.call_count)174 self.assertEqual(0, pkg_install.call_count)
136175
137 @mock.patch(MPATH + "cc_apt_configure.debconf_set_selections")176 @mock.patch(M_TMP_PATH)
138 @mock.patch(MPATH + "util.subp", side_effect=ProcessExecutionError(177 @mock.patch(MPATH + "util.subp")
139 stderr=OLD_UBUNTU_DRIVERS_ERROR_STDERR, exit_code=2))
140 @mock.patch(MPATH + "util.which", return_value=False)178 @mock.patch(MPATH + "util.which", return_value=False)
141 def test_install_drivers_handles_old_ubuntu_drivers_gracefully(179 def test_install_drivers_handles_old_ubuntu_drivers_gracefully(
142 self, m_which, m_subp, _):180 self, m_which, m_subp, m_tmp):
143 """Older ubuntu-drivers versions should emit message and raise error"""181 """Older ubuntu-drivers versions should emit message and raise error"""
182 tdir = self.tmp_dir()
183 debconf_file = os.path.join(tdir, 'nvidia.template')
184 m_tmp.return_value = tdir
144 myCloud = mock.MagicMock()185 myCloud = mock.MagicMock()
186
187 def fake_subp(cmd):
188 if cmd[0].startswith(tdir):
189 return
190 raise ProcessExecutionError(
191 stderr=OLD_UBUNTU_DRIVERS_ERROR_STDERR, exit_code=2)
192 m_subp.side_effect = fake_subp
193
145 with self.assertRaises(Exception):194 with self.assertRaises(Exception):
146 drivers.handle(195 drivers.handle(
147 'ubuntu_drivers', self.cfg_accepted, myCloud, None, None)196 'ubuntu_drivers', self.cfg_accepted, myCloud, None, None)
148 self.assertEqual([mock.call(['ubuntu-drivers-common'])],197 self.assertEqual([mock.call(['ubuntu-drivers-common'])],
149 myCloud.distro.install_packages.call_args_list)198 myCloud.distro.install_packages.call_args_list)
150 self.assertEqual([mock.call(self.install_gpgpu)],199 self.assertEqual(
151 m_subp.call_args_list)200 [mock.call(AnyTempScriptAndDebconfFile(tdir, debconf_file)),
201 mock.call(self.install_gpgpu)],
202 m_subp.call_args_list)
152 self.assertIn('WARNING: the available version of ubuntu-drivers is'203 self.assertIn('WARNING: the available version of ubuntu-drivers is'
153 ' too old to perform requested driver installation',204 ' too old to perform requested driver installation',
154 self.logs.getvalue())205 self.logs.getvalue())
@@ -160,17 +211,21 @@ class TestUbuntuDriversWithVersion(TestUbuntuDrivers):
160 'drivers': {'nvidia': {'license-accepted': True, 'version': '123'}}}211 'drivers': {'nvidia': {'license-accepted': True, 'version': '123'}}}
161 install_gpgpu = ['ubuntu-drivers', 'install', '--gpgpu', 'nvidia:123']212 install_gpgpu = ['ubuntu-drivers', 'install', '--gpgpu', 'nvidia:123']
162213
163 @mock.patch(MPATH + "cc_apt_configure.debconf_set_selections")214 @mock.patch(M_TMP_PATH)
164 @mock.patch(MPATH + "util.subp", return_value=('', ''))215 @mock.patch(MPATH + "util.subp", return_value=('', ''))
165 @mock.patch(MPATH + "util.which", return_value=False)216 @mock.patch(MPATH + "util.which", return_value=False)
166 def test_version_none_uses_latest(self, m_which, m_subp, _):217 def test_version_none_uses_latest(self, m_which, m_subp, m_tmp):
218 tdir = self.tmp_dir()
219 debconf_file = os.path.join(tdir, 'nvidia.template')
220 m_tmp.return_value = tdir
167 myCloud = mock.MagicMock()221 myCloud = mock.MagicMock()
168 version_none_cfg = {222 version_none_cfg = {
169 'drivers': {'nvidia': {'license-accepted': True, 'version': None}}}223 'drivers': {'nvidia': {'license-accepted': True, 'version': None}}}
170 drivers.handle(224 drivers.handle(
171 'ubuntu_drivers', version_none_cfg, myCloud, None, None)225 'ubuntu_drivers', version_none_cfg, myCloud, None, None)
172 self.assertEqual(226 self.assertEqual(
173 [mock.call(['ubuntu-drivers', 'install', '--gpgpu', 'nvidia'])],227 [mock.call(AnyTempScriptAndDebconfFile(tdir, debconf_file)),
228 mock.call(['ubuntu-drivers', 'install', '--gpgpu', 'nvidia'])],
174 m_subp.call_args_list)229 m_subp.call_args_list)
175230
176 def test_specifying_a_version_doesnt_override_license_acceptance(self):231 def test_specifying_a_version_doesnt_override_license_acceptance(self):
diff --git a/cloudinit/tests/helpers.py b/cloudinit/tests/helpers.py
index f41180f..23fddd0 100644
--- a/cloudinit/tests/helpers.py
+++ b/cloudinit/tests/helpers.py
@@ -198,7 +198,8 @@ class CiTestCase(TestCase):
198 prefix="ci-%s." % self.__class__.__name__)198 prefix="ci-%s." % self.__class__.__name__)
199 else:199 else:
200 tmpd = tempfile.mkdtemp(dir=dir)200 tmpd = tempfile.mkdtemp(dir=dir)
201 self.addCleanup(functools.partial(shutil.rmtree, tmpd))201 self.addCleanup(
202 functools.partial(shutil.rmtree, tmpd, ignore_errors=True))
202 return tmpd203 return tmpd
203204
204 def tmp_path(self, path, dir=None):205 def tmp_path(self, path, dir=None):

Subscribers

People subscribed via source and target branches