# This file is part of cloud-init. See LICENSE file for license information. """ test_handler_apt_configure_sources_list Test templating of sources list """ import logging import os import shutil import tempfile from unittest import mock from cloudinit import subp, templater, util from cloudinit.config import cc_apt_configure from cloudinit.distros.debian import Distro from tests.unittests import helpers as t_help from tests.unittests.util import get_cloud LOG = logging.getLogger(__name__) YAML_TEXT_CUSTOM_SL = """ apt_mirror: http://archive.ubuntu.com/ubuntu/ apt_custom_sources_list: | ## template:jinja ## Note, this file is written by cloud-init on first boot of an instance ## modifications made here will not survive a re-bundle. ## if you wish to make changes you can: ## a.) add 'apt_preserve_sources_list: true' to /etc/cloud/cloud.cfg ## or do the same in user-data ## b.) add sources in /etc/apt/sources.list.d ## c.) make changes to template file /etc/cloud/templates/sources.list.tmpl # See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to # newer versions of the distribution. deb {{mirror}} {{codename}} main restricted deb-src {{mirror}} {{codename}} main restricted # FIND_SOMETHING_SPECIAL """ EXPECTED_CONVERTED_CONTENT = """## Note, this file is written by cloud-init on first boot of an instance ## modifications made here will not survive a re-bundle. ## if you wish to make changes you can: ## a.) add 'apt_preserve_sources_list: true' to /etc/cloud/cloud.cfg ## or do the same in user-data ## b.) add sources in /etc/apt/sources.list.d ## c.) make changes to template file /etc/cloud/templates/sources.list.tmpl # See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to # newer versions of the distribution. deb http://archive.ubuntu.com/ubuntu/ fakerelease main restricted deb-src http://archive.ubuntu.com/ubuntu/ fakerelease main restricted # FIND_SOMETHING_SPECIAL """ class TestAptSourceConfigSourceList(t_help.FilesystemMockingTestCase): """TestAptSourceConfigSourceList Main Class to test sources list rendering """ def setUp(self): super(TestAptSourceConfigSourceList, self).setUp() self.subp = subp.subp self.new_root = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, self.new_root) rpatcher = mock.patch("cloudinit.util.lsb_release") get_rel = rpatcher.start() get_rel.return_value = {"codename": "fakerelease"} self.addCleanup(rpatcher.stop) apatcher = mock.patch("cloudinit.util.get_dpkg_architecture") get_arch = apatcher.start() get_arch.return_value = "amd64" self.addCleanup(apatcher.stop) def apt_source_list(self, distro, mirror, mirrorcheck=None): """apt_source_list Test rendering of a source.list from template for a given distro """ if mirrorcheck is None: mirrorcheck = mirror if isinstance(mirror, list): cfg = {"apt_mirror_search": mirror} else: cfg = {"apt_mirror": mirror} mycloud = get_cloud(distro) with mock.patch.object(util, "write_file") as mockwf: with mock.patch.object( util, "load_file", return_value="faketmpl" ) as mocklf: with mock.patch.object( os.path, "isfile", return_value=True ) as mockisfile: with mock.patch.object( templater, "render_string", return_value="fake" ) as mockrnd: with mock.patch.object(util, "rename"): cc_apt_configure.handle( "test", cfg, mycloud, LOG, None ) mockisfile.assert_any_call( "/etc/cloud/templates/sources.list.%s.tmpl" % distro ) mocklf.assert_any_call( "/etc/cloud/templates/sources.list.%s.tmpl" % distro ) mockrnd.assert_called_once_with( "faketmpl", { "RELEASE": "fakerelease", "PRIMARY": mirrorcheck, "MIRROR": mirrorcheck, "SECURITY": mirrorcheck, "codename": "fakerelease", "primary": mirrorcheck, "mirror": mirrorcheck, "security": mirrorcheck, }, ) mockwf.assert_called_once_with( "/etc/apt/sources.list", "fake", mode=0o644 ) def test_apt_v1_source_list_debian(self): """Test rendering of a source.list from template for debian""" self.apt_source_list("debian", "http://httpredir.debian.org/debian") def test_apt_v1_source_list_ubuntu(self): """Test rendering of a source.list from template for ubuntu""" self.apt_source_list("ubuntu", "http://archive.ubuntu.com/ubuntu/") @staticmethod def myresolve(name): """Fake util.is_resolvable for mirrorfail tests""" if name == "does.not.exist": print("Faking FAIL for '%s'" % name) return False else: print("Faking SUCCESS for '%s'" % name) return True def test_apt_v1_srcl_debian_mirrorfail(self): """Test rendering of a source.list from template for debian""" with mock.patch.object( util, "is_resolvable", side_effect=self.myresolve ) as mockresolve: self.apt_source_list( "debian", [ "http://does.not.exist", "http://httpredir.debian.org/debian", ], "http://httpredir.debian.org/debian", ) mockresolve.assert_any_call("does.not.exist") mockresolve.assert_any_call("httpredir.debian.org") def test_apt_v1_srcl_ubuntu_mirrorfail(self): """Test rendering of a source.list from template for ubuntu""" with mock.patch.object( util, "is_resolvable", side_effect=self.myresolve ) as mockresolve: self.apt_source_list( "ubuntu", ["http://does.not.exist", "http://archive.ubuntu.com/ubuntu/"], "http://archive.ubuntu.com/ubuntu/", ) mockresolve.assert_any_call("does.not.exist") mockresolve.assert_any_call("archive.ubuntu.com") def test_apt_v1_srcl_custom(self): """Test rendering from a custom source.list template""" cfg = util.load_yaml(YAML_TEXT_CUSTOM_SL) mycloud = get_cloud() # the second mock restores the original subp with mock.patch.object(util, "write_file") as mockwrite: with mock.patch.object(subp, "subp", self.subp): with mock.patch.object( Distro, "get_primary_arch", return_value="amd64" ): cc_apt_configure.handle( "notimportant", cfg, mycloud, LOG, None ) mockwrite.assert_called_once_with( "/etc/apt/sources.list", EXPECTED_CONVERTED_CONTENT, mode=420 ) # vi: ts=4 expandtab