diff options
| -rw-r--r-- | cloudinit/config/cc_apt_configure.py | 4 | ||||
| -rw-r--r-- | cloudinit/config/cc_ubuntu_drivers.py | 10 | ||||
| -rw-r--r-- | cloudinit/config/tests/test_ubuntu_drivers.py | 18 | ||||
| -rw-r--r-- | tests/unittests/test_handler/test_handler_apt_source_v3.py | 11 | 
4 files changed, 37 insertions, 6 deletions
| diff --git a/cloudinit/config/cc_apt_configure.py b/cloudinit/config/cc_apt_configure.py index 919d1995..f01e2aaf 100644 --- a/cloudinit/config/cc_apt_configure.py +++ b/cloudinit/config/cc_apt_configure.py @@ -332,6 +332,8 @@ def apply_apt(cfg, cloud, target):  def debconf_set_selections(selections, target=None): +    if not selections.endswith(b'\n'): +        selections += b'\n'      util.subp(['debconf-set-selections'], data=selections, target=target,                capture=True) @@ -374,7 +376,7 @@ def apply_debconf_selections(cfg, target=None):      selections = '\n'.join(          [selsets[key] for key in sorted(selsets.keys())]) -    debconf_set_selections(selections.encode() + b"\n", target=target) +    debconf_set_selections(selections.encode(), target=target)      # get a complete list of packages listed in input      pkgs_cfgd = set() diff --git a/cloudinit/config/cc_ubuntu_drivers.py b/cloudinit/config/cc_ubuntu_drivers.py index 91feb603..4da34ee0 100644 --- a/cloudinit/config/cc_ubuntu_drivers.py +++ b/cloudinit/config/cc_ubuntu_drivers.py @@ -4,6 +4,7 @@  from textwrap import dedent +from cloudinit.config import cc_apt_configure  from cloudinit.config.schema import (      get_schema_doc, validate_cloudconfig_schema)  from cloudinit import log as logging @@ -92,6 +93,15 @@ def install_drivers(cfg, pkg_install_func):      LOG.debug("Installing NVIDIA drivers (%s=%s, version=%s)",                cfgpath, nv_acc, version_cfg if version_cfg else 'latest') +    # Setting NVIDIA latelink confirms acceptance of EULA for the package +    # linux-restricted-modules +    # Reference code defining debconf variable is here +    # https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/ +    # linux-restricted-modules/+git/eoan/tree/debian/templates/ +    # nvidia.templates.in +    selections = b'linux-restricted-modules linux/nvidia/latelink boolean true' +    cc_apt_configure.debconf_set_selections(selections) +      try:          util.subp(['ubuntu-drivers', 'install', '--gpgpu', driver_arg])      except util.ProcessExecutionError as exc: diff --git a/cloudinit/config/tests/test_ubuntu_drivers.py b/cloudinit/config/tests/test_ubuntu_drivers.py index efba4ce7..6a763bd9 100644 --- a/cloudinit/config/tests/test_ubuntu_drivers.py +++ b/cloudinit/config/tests/test_ubuntu_drivers.py @@ -28,9 +28,11 @@ class TestUbuntuDrivers(CiTestCase):                  {'drivers': {'nvidia': {'license-accepted': "TRUE"}}},                  schema=drivers.schema, strict=True) +    @mock.patch(MPATH + "cc_apt_configure.debconf_set_selections")      @mock.patch(MPATH + "util.subp", return_value=('', ''))      @mock.patch(MPATH + "util.which", return_value=False) -    def _assert_happy_path_taken(self, config, m_which, m_subp): +    def _assert_happy_path_taken( +            self, config, m_which, m_subp, m_debconf_set_selections):          """Positive path test through handle. Package should be installed."""          myCloud = mock.MagicMock()          drivers.handle('ubuntu_drivers', config, myCloud, None, None) @@ -38,6 +40,8 @@ class TestUbuntuDrivers(CiTestCase):                           myCloud.distro.install_packages.call_args_list)          self.assertEqual([mock.call(self.install_gpgpu)],                           m_subp.call_args_list) +        m_debconf_set_selections.assert_called_with( +            b'linux-restricted-modules linux/nvidia/latelink boolean true')      def test_handle_does_package_install(self):          self._assert_happy_path_taken(self.cfg_accepted) @@ -48,10 +52,11 @@ class TestUbuntuDrivers(CiTestCase):              new_config['drivers']['nvidia']['license-accepted'] = true_value              self._assert_happy_path_taken(new_config) +    @mock.patch(MPATH + "cc_apt_configure.debconf_set_selections")      @mock.patch(MPATH + "util.subp", side_effect=ProcessExecutionError(          stdout='No drivers found for installation.\n', exit_code=1))      @mock.patch(MPATH + "util.which", return_value=False) -    def test_handle_raises_error_if_no_drivers_found(self, m_which, m_subp): +    def test_handle_raises_error_if_no_drivers_found(self, m_which, m_subp, _):          """If ubuntu-drivers doesn't install any drivers, raise an error."""          myCloud = mock.MagicMock()          with self.assertRaises(Exception): @@ -108,9 +113,10 @@ class TestUbuntuDrivers(CiTestCase):                        myLog.debug.call_args_list[0][0][0])          self.assertEqual(0, m_install_drivers.call_count) +    @mock.patch(MPATH + "cc_apt_configure.debconf_set_selections")      @mock.patch(MPATH + "util.subp", return_value=('', ''))      @mock.patch(MPATH + "util.which", return_value=True) -    def test_install_drivers_no_install_if_present(self, m_which, m_subp): +    def test_install_drivers_no_install_if_present(self, m_which, m_subp, _):          """If 'ubuntu-drivers' is present, no package install should occur."""          pkg_install = mock.MagicMock()          drivers.install_drivers(self.cfg_accepted['drivers'], @@ -128,11 +134,12 @@ class TestUbuntuDrivers(CiTestCase):              drivers.install_drivers("mystring", pkg_install_func=pkg_install)          self.assertEqual(0, pkg_install.call_count) +    @mock.patch(MPATH + "cc_apt_configure.debconf_set_selections")      @mock.patch(MPATH + "util.subp", side_effect=ProcessExecutionError(          stderr=OLD_UBUNTU_DRIVERS_ERROR_STDERR, exit_code=2))      @mock.patch(MPATH + "util.which", return_value=False)      def test_install_drivers_handles_old_ubuntu_drivers_gracefully( -            self, m_which, m_subp): +            self, m_which, m_subp, _):          """Older ubuntu-drivers versions should emit message and raise error"""          myCloud = mock.MagicMock()          with self.assertRaises(Exception): @@ -153,9 +160,10 @@ class TestUbuntuDriversWithVersion(TestUbuntuDrivers):          'drivers': {'nvidia': {'license-accepted': True, 'version': '123'}}}      install_gpgpu = ['ubuntu-drivers', 'install', '--gpgpu', 'nvidia:123'] +    @mock.patch(MPATH + "cc_apt_configure.debconf_set_selections")      @mock.patch(MPATH + "util.subp", return_value=('', ''))      @mock.patch(MPATH + "util.which", return_value=False) -    def test_version_none_uses_latest(self, m_which, m_subp): +    def test_version_none_uses_latest(self, m_which, m_subp, _):          myCloud = mock.MagicMock()          version_none_cfg = {              'drivers': {'nvidia': {'license-accepted': True, 'version': None}}} diff --git a/tests/unittests/test_handler/test_handler_apt_source_v3.py b/tests/unittests/test_handler/test_handler_apt_source_v3.py index 90fe6eed..2f21b6dc 100644 --- a/tests/unittests/test_handler/test_handler_apt_source_v3.py +++ b/tests/unittests/test_handler/test_handler_apt_source_v3.py @@ -998,6 +998,17 @@ deb http://ubuntu.com/ubuntu/ xenial-proposed main""")  class TestDebconfSelections(TestCase): +    @mock.patch("cloudinit.config.cc_apt_configure.util.subp") +    def test_set_sel_appends_newline_if_absent(self, m_subp): +        """Automatically append a newline to debconf-set-selections config.""" +        selections = b'some/setting boolean true' +        cc_apt_configure.debconf_set_selections(selections=selections) +        cc_apt_configure.debconf_set_selections(selections=selections + b'\n') +        m_call = mock.call( +            ['debconf-set-selections'], data=selections + b'\n', capture=True, +            target=None) +        self.assertEqual([m_call, m_call], m_subp.call_args_list) +      @mock.patch("cloudinit.config.cc_apt_configure.debconf_set_selections")      def test_no_set_sel_if_none_to_set(self, m_set_sel):          cc_apt_configure.apply_debconf_selections({'foo': 'bar'}) | 
