diff options
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | cloudinit/config/cc_apt_configure.py | 52 | ||||
-rw-r--r-- | cloudinit/gpg.py | 74 | ||||
-rw-r--r-- | cloudinit/stages.py | 2 | ||||
-rw-r--r-- | cloudinit/templater.py | 11 | ||||
-rw-r--r-- | doc/examples/cloud-config.txt | 6 | ||||
-rwxr-xr-x | packages/bddeb | 6 | ||||
-rw-r--r-- | tests/unittests/test_datasource/test_azure_helper.py | 1 | ||||
-rw-r--r-- | tests/unittests/test_datasource/test_smartos.py | 4 | ||||
-rw-r--r-- | tests/unittests/test_handler/test_handler_apt_configure_sources_list.py | 65 | ||||
-rw-r--r-- | tests/unittests/test_handler/test_handler_apt_source.py | 169 |
11 files changed, 216 insertions, 175 deletions
@@ -121,6 +121,7 @@ to "pass" if modules_init should be executed with network access. - ConfigDrive: improved support for networking information from a network_data.json or older interfaces formated network_config. + - Change missing Cheetah log warning to debug [Andrew Jorgensen] 0.7.6: - open 0.7.6 diff --git a/cloudinit/config/cc_apt_configure.py b/cloudinit/config/cc_apt_configure.py index 7a9777c0..96c4a43d 100644 --- a/cloudinit/config/cc_apt_configure.py +++ b/cloudinit/config/cc_apt_configure.py @@ -22,6 +22,7 @@ import glob import os import re +from cloudinit import gpg from cloudinit import templater from cloudinit import util @@ -34,21 +35,6 @@ APT_PROXY_FN = "/etc/apt/apt.conf.d/95cloud-init-proxy" # this will match 'XXX:YYY' (ie, 'cloud-archive:foo' or 'ppa:bar') ADD_APT_REPO_MATCH = r"^[\w-]+:\w" -# A temporary shell program to get a given gpg key -# from a given keyserver -EXPORT_GPG_KEYID = """ - k=${1} ks=${2}; - exec 2>/dev/null - [ -n "$k" ] || exit 1; - armour=$(gpg --export --armour "${k}") - if [ -z "${armour}" ]; then - gpg --keyserver ${ks} --recv "${k}" >/dev/null && - armour=$(gpg --export --armour "${k}") && - gpg --batch --yes --delete-keys "${k}" - fi - [ -n "${armour}" ] && echo "${armour}" -""" - def handle(name, cfg, cloud, log, _args): if util.is_false(cfg.get('apt_configure_enabled', True)): @@ -94,8 +80,8 @@ def handle(name, cfg, cloud, log, _args): def matcher(x): return False - errors = add_sources(cfg['apt_sources'], params, - aa_repo_match=matcher) + errors = add_apt_sources(cfg['apt_sources'], params, + aa_repo_match=matcher) for e in errors: log.warn("Add source error: %s", ':'.join(e)) @@ -108,17 +94,7 @@ def handle(name, cfg, cloud, log, _args): util.logexc(log, "Failed to run debconf-set-selections") -# get gpg keyid from keyserver -def getkeybyid(keyid, keyserver): - with util.ExtendedTemporaryFile(suffix='.sh', mode="w+", ) as fh: - fh.write(EXPORT_GPG_KEYID) - fh.flush() - cmd = ['/bin/sh', fh.name, keyid, keyserver] - (stdout, _stderr) = util.subp(cmd) - return stdout.strip() - - -def mirror2lists_fileprefix(mirror): +def mirrorurl_to_apt_fileprefix(mirror): string = mirror # take off http:// or ftp:// if string.endswith("/"): @@ -135,8 +111,8 @@ def rename_apt_lists(old_mirrors, new_mirrors, lists_d="/var/lib/apt/lists"): nmirror = new_mirrors.get(name) if not nmirror: continue - oprefix = os.path.join(lists_d, mirror2lists_fileprefix(omirror)) - nprefix = os.path.join(lists_d, mirror2lists_fileprefix(nmirror)) + oprefix = os.path.join(lists_d, mirrorurl_to_apt_fileprefix(omirror)) + nprefix = os.path.join(lists_d, mirrorurl_to_apt_fileprefix(nmirror)) if oprefix == nprefix: continue olen = len(oprefix) @@ -171,7 +147,7 @@ def generate_sources_list(cfg, codename, mirrors, cloud, log): templater.render_to_file(template_fn, '/etc/apt/sources.list', params) -def add_key_raw(key): +def add_apt_key_raw(key): """ actual adding of a key as defined in key argument to the system @@ -179,10 +155,10 @@ def add_key_raw(key): try: util.subp(('apt-key', 'add', '-'), key) except util.ProcessExecutionError: - raise Exception('failed add key') + raise ValueError('failed to add apt GPG Key to apt keyring') -def add_key(ent): +def add_apt_key(ent): """ add key to the system as defined in ent (if any) supports raw keys or keyid's @@ -192,10 +168,10 @@ def add_key(ent): keyserver = "keyserver.ubuntu.com" if 'keyserver' in ent: keyserver = ent['keyserver'] - ent['key'] = getkeybyid(ent['keyid'], keyserver) + ent['key'] = gpg.get_key_by_id(ent['keyid'], keyserver) if 'key' in ent: - add_key_raw(ent['key']) + add_apt_key_raw(ent['key']) def convert_to_new_format(srclist): @@ -222,7 +198,7 @@ def convert_to_new_format(srclist): return srcdict -def add_sources(srclist, template_params=None, aa_repo_match=None): +def add_apt_sources(srclist, template_params=None, aa_repo_match=None): """ add entries in /etc/apt/sources.list.d for each abbreviated sources.list entry in 'srclist'. When rendering template, also @@ -245,8 +221,8 @@ def add_sources(srclist, template_params=None, aa_repo_match=None): # keys can be added without specifying a source try: - add_key(ent) - except Exception as detail: + add_apt_key(ent) + except ValueError as detail: errorlist.append([ent, detail]) if 'source' not in ent: diff --git a/cloudinit/gpg.py b/cloudinit/gpg.py new file mode 100644 index 00000000..6a76d785 --- /dev/null +++ b/cloudinit/gpg.py @@ -0,0 +1,74 @@ +"""gpg.py - Collection of gpg key related functions""" +# vi: ts=4 expandtab +# +# Copyright (C) 2016 Canonical Ltd. +# +# Author: Scott Moser <scott.moser@canonical.com> +# Author: Christian Ehrhardt <christian.ehrhardt@canonical.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 3, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from cloudinit import log as logging +from cloudinit import util + +LOG = logging.getLogger(__name__) + + +def export_armour(key): + """Export gpg key, armoured key gets returned""" + try: + (armour, _) = util.subp(["gpg", "--export", "--armour", key], + capture=True) + except util.ProcessExecutionError as error: + # debug, since it happens for any key not on the system initially + LOG.debug('Failed to export armoured key "%s": %s', key, error) + armour = None + return armour + + +def receive_key(key, keyserver): + """Receive gpg key from the specified keyserver""" + LOG.debug('Receive gpg key "%s"', key) + try: + util.subp(["gpg", "--keyserver", keyserver, "--recv-keys", key], + capture=True) + except util.ProcessExecutionError as error: + raise ValueError(('Failed to import key "%s" ' + 'from server "%s" - error %s') % + (key, keyserver, error)) + + +def delete_key(key): + """Delete the specified key from the local gpg ring""" + try: + util.subp(["gpg", "--batch", "--yes", "--delete-keys", key], + capture=True) + except util.ProcessExecutionError as error: + LOG.warn('Failed delete key "%s": %s', key, error) + + +def get_key_by_id(keyid, keyserver="keyserver.ubuntu.com"): + """get gpg keyid from keyserver""" + armour = export_armour(keyid) + if not armour: + try: + receive_key(keyid, keyserver=keyserver) + armour = export_armour(keyid) + except ValueError: + LOG.exception('Failed to obtain gpg key %s', keyid) + raise + finally: + # delete just imported key to leave environment as it was before + delete_key(keyid) + + return armour diff --git a/cloudinit/stages.py b/cloudinit/stages.py index 9b3cc71c..47deac6e 100644 --- a/cloudinit/stages.py +++ b/cloudinit/stages.py @@ -619,7 +619,7 @@ class Init(object): dscfg = ('ds', self.datasource.network_config) sys_cfg = ('system_cfg', self.cfg.get('network')) - for loc, ncfg in (cmdline_cfg, dscfg, sys_cfg): + for loc, ncfg in (cmdline_cfg, sys_cfg, dscfg): if net.is_disabled_cfg(ncfg): LOG.debug("network config disabled by %s", loc) return (None, loc) diff --git a/cloudinit/templater.py b/cloudinit/templater.py index 8a6ad417..41ef27e3 100644 --- a/cloudinit/templater.py +++ b/cloudinit/templater.py @@ -3,10 +3,12 @@ # Copyright (C) 2012 Canonical Ltd. # Copyright (C) 2012 Hewlett-Packard Development Company, L.P. # Copyright (C) 2012 Yahoo! Inc. +# Copyright (C) 2016 Amazon.com, Inc. or its affiliates. # # Author: Scott Moser <scott.moser@canonical.com> # Author: Juerg Haefliger <juerg.haefliger@hp.com> # Author: Joshua Harlow <harlowja@yahoo-inc.com> +# Author: Andrew Jorgensen <ajorgens@amazon.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3, as @@ -102,12 +104,11 @@ def detect_template(text): rest = '' type_match = TYPE_MATCHER.match(ident) if not type_match: - if not CHEETAH_AVAILABLE: - LOG.warn("Cheetah not available as the default renderer for" - " unknown template, reverting to the basic renderer.") - return ('basic', basic_render, text) - else: + if CHEETAH_AVAILABLE: + LOG.debug("Using Cheetah as the renderer for unknown template.") return ('cheetah', cheetah_render, text) + else: + return ('basic', basic_render, text) else: template_type = type_match.group(1).lower().strip() if template_type not in ('jinja', 'cheetah', 'basic'): diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt index 62b297bc..3cc9c055 100644 --- a/doc/examples/cloud-config.txt +++ b/doc/examples/cloud-config.txt @@ -125,11 +125,11 @@ add_apt_repo_match: '^[\w-]+:\w' # better merging between multiple input files than a list like: # cloud-config1 # sources: - s1: {'key': 'key1', 'source': 'source1'} +# s1: {'key': 'key1', 'source': 'source1'} # cloud-config2 # sources: - s2: {'key': 'key2'} - s1: {filename: 'foo'} +# s2: {'key': 'key2'} +# s1: {filename: 'foo'} # this would be merged to #sources: # s1: diff --git a/packages/bddeb b/packages/bddeb index acce0229..3c77ce1d 100755 --- a/packages/bddeb +++ b/packages/bddeb @@ -149,11 +149,17 @@ def main(): parser.add_argument("--sign", default=False, action='store_true', help="sign result. do not pass -us -uc to debuild") + parser.add_argument("--signuser", default=False, action='store', + help="user to sign, see man dpkg-genchanges") + args = parser.parse_args() if not args.sign: args.debuild_args.extend(['-us', '-uc']) + if args.signuser: + args.debuild_args.extend(['-e%s' % args.signuser]) + os.environ['INIT_SYSTEM'] = args.init_system capture = True diff --git a/tests/unittests/test_datasource/test_azure_helper.py b/tests/unittests/test_datasource/test_azure_helper.py index 49227b53..65202ff0 100644 --- a/tests/unittests/test_datasource/test_azure_helper.py +++ b/tests/unittests/test_datasource/test_azure_helper.py @@ -278,6 +278,7 @@ class TestOpenSSLManager(TestCase): self.subp.side_effect = capture_directory manager = azure_helper.OpenSSLManager() self.assertEqual(manager.tmpdir, subp_directory['path']) + manager.clean_up() @mock.patch.object(azure_helper, 'cd', mock.MagicMock()) @mock.patch.object(azure_helper.tempfile, 'mkdtemp', mock.MagicMock()) diff --git a/tests/unittests/test_datasource/test_smartos.py b/tests/unittests/test_datasource/test_smartos.py index ddbb8fbd..9c6c8768 100644 --- a/tests/unittests/test_datasource/test_smartos.py +++ b/tests/unittests/test_datasource/test_smartos.py @@ -147,7 +147,9 @@ class TestSmartOSDataSource(FilesystemMockingTestCase): self.addCleanup(shutil.rmtree, self.tmp) self.paths = c_helpers.Paths({'cloud_dir': self.tmp}) - self.legacy_user_d = tempfile.mkdtemp() + self.legacy_user_d = os.path.join(self.tmp, 'legacy_user_tmp') + os.mkdir(self.legacy_user_d) + self.orig_lud = DataSourceSmartOS.LEGACY_USER_D DataSourceSmartOS.LEGACY_USER_D = self.legacy_user_d diff --git a/tests/unittests/test_handler/test_handler_apt_configure_sources_list.py b/tests/unittests/test_handler/test_handler_apt_configure_sources_list.py index 5d0417a2..acde0863 100644 --- a/tests/unittests/test_handler/test_handler_apt_configure_sources_list.py +++ b/tests/unittests/test_handler/test_handler_apt_configure_sources_list.py @@ -20,6 +20,8 @@ from cloudinit import util from cloudinit.config import cc_apt_configure from cloudinit.sources import DataSourceNone +from cloudinit.distros.debian import Distro + from .. import helpers as t_help LOG = logging.getLogger(__name__) @@ -103,8 +105,9 @@ class TestAptSourceConfigSourceList(t_help.FilesystemMockingTestCase): with mock.patch.object(templater, 'render_to_file') as mocktmpl: with mock.patch.object(os.path, 'isfile', return_value=True) as mockisfile: - cc_apt_configure.handle("notimportant", cfg, mycloud, - LOG, None) + with mock.patch.object(util, 'rename'): + cc_apt_configure.handle("notimportant", cfg, mycloud, + LOG, None) mockisfile.assert_any_call( ('/etc/cloud/templates/sources.list.%s.tmpl' % distro)) @@ -114,37 +117,47 @@ class TestAptSourceConfigSourceList(t_help.FilesystemMockingTestCase): {'codename': '', 'primary': mirrorcheck, 'mirror': mirrorcheck}) def test_apt_source_list_debian(self): - """test_apt_source_list_debian - Test rendering of a source.list from template for debian - """ + """Test rendering of a source.list from template for debian""" self.apt_source_list('debian', 'http://httpredir.debian.org/debian') def test_apt_source_list_ubuntu(self): - """test_apt_source_list_ubuntu - Test rendering of a source.list from template for ubuntu - """ + """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_srcl_debian_mirrorfail(self): - """test_apt_source_list_debian_mirrorfail - Test rendering of a source.list from template for debian - """ - self.apt_source_list('debian', ['http://does.not.exist', - 'http://httpredir.debian.org/debian'], - 'http://httpredir.debian.org/debian') + """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_srcl_ubuntu_mirrorfail(self): - """test_apt_source_list_ubuntu_mirrorfail - Test rendering of a source.list from template for ubuntu - """ - self.apt_source_list('ubuntu', ['http://does.not.exist', - 'http://archive.ubuntu.com/ubuntu/'], - 'http://archive.ubuntu.com/ubuntu/') + """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_srcl_custom(self): - """test_apt_srcl_custom - Test rendering from a custom source.list template - """ + """Test rendering from a custom source.list template""" cfg = util.load_yaml(YAML_TEXT_CUSTOM_SL) mycloud = self._get_cloud('ubuntu') @@ -153,8 +166,10 @@ class TestAptSourceConfigSourceList(t_help.FilesystemMockingTestCase): with mock.patch.object(util, 'subp', self.subp): with mock.patch.object(cc_apt_configure, 'get_release', return_value='fakerelease'): - cc_apt_configure.handle("notimportant", cfg, mycloud, - LOG, None) + 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', diff --git a/tests/unittests/test_handler/test_handler_apt_source.py b/tests/unittests/test_handler/test_handler_apt_source.py index 4dbe69f0..99a4d860 100644 --- a/tests/unittests/test_handler/test_handler_apt_source.py +++ b/tests/unittests/test_handler/test_handler_apt_source.py @@ -13,6 +13,7 @@ except ImportError: from mock import call from cloudinit.config import cc_apt_configure +from cloudinit import gpg from cloudinit import util from ..helpers import TestCase @@ -43,6 +44,8 @@ class TestAptSourceConfig(TestCase): """TestAptSourceConfig Main Class to test apt_source configs """ + release = "fantastic" + def setUp(self): super(TestAptSourceConfig, self).setUp() self.tmp = tempfile.mkdtemp() @@ -55,6 +58,11 @@ class TestAptSourceConfig(TestCase): self.fallbackfn = os.path.join(self.tmp, "etc/apt/sources.list.d/", "cloud_config_sources.list") + patcher = mock.patch("cloudinit.config.cc_apt_configure.get_release") + get_rel = patcher.start() + get_rel.return_value = self.release + self.addCleanup(patcher.stop) + @staticmethod def _get_default_params(): """get_default_params @@ -80,7 +88,7 @@ class TestAptSourceConfig(TestCase): """ params = self._get_default_params() - cc_apt_configure.add_sources(cfg, params) + cc_apt_configure.add_apt_sources(cfg, params) self.assertTrue(os.path.isfile(filename)) @@ -92,10 +100,7 @@ class TestAptSourceConfig(TestCase): contents, flags=re.IGNORECASE)) def test_apt_src_basic(self): - """test_apt_src_basic - Test Fix deb source string, has to overwrite mirror conf in params. - Test with a filename provided in config. - """ + """Test deb source string, overwrite mirror and filename""" cfg = {'source': ('deb http://archive.ubuntu.com/ubuntu' ' karmic-backports' ' main universe multiverse restricted'), @@ -103,11 +108,7 @@ class TestAptSourceConfig(TestCase): self.apt_src_basic(self.aptlistfile, [cfg]) def test_apt_src_basic_dict(self): - """test_apt_src_basic_dict - Test Fix deb source string, has to overwrite mirror conf in params. - Test with a filename provided in config. - Provided in a dictionary with filename being the key (new format) - """ + """Test deb source string, overwrite mirror and filename (dict)""" cfg = {self.aptlistfile: {'source': ('deb http://archive.ubuntu.com/ubuntu' ' karmic-backports' @@ -137,10 +138,7 @@ class TestAptSourceConfig(TestCase): contents, flags=re.IGNORECASE)) def test_apt_src_basic_tri(self): - """test_apt_src_basic_tri - Test Fix three deb source string, has to overwrite mirror conf in - params. Test with filenames provided in config. - """ + """Test Fix three deb source string with filenames""" cfg1 = {'source': ('deb http://archive.ubuntu.com/ubuntu' ' karmic-backports' ' main universe multiverse restricted'), @@ -156,11 +154,7 @@ class TestAptSourceConfig(TestCase): self.apt_src_basic_tri([cfg1, cfg2, cfg3]) def test_apt_src_basic_dict_tri(self): - """test_apt_src_basic_dict_tri - Test Fix three deb source string, has to overwrite mirror conf in - params. Test with filenames provided in config. - Provided in a dictionary with filename being the key (new format) - """ + """Test Fix three deb source string with filenames (dict)""" cfg = {self.aptlistfile: {'source': ('deb http://archive.ubuntu.com/ubuntu' ' karmic-backports' @@ -176,10 +170,7 @@ class TestAptSourceConfig(TestCase): self.apt_src_basic_tri(cfg) def test_apt_src_basic_nofn(self): - """test_apt_src_basic_nofn - Test Fix deb source string, has to overwrite mirror conf in params. - Test without a filename provided in config and test for known fallback. - """ + """Test Fix three deb source string without filenames (dict)""" cfg = {'source': ('deb http://archive.ubuntu.com/ubuntu' ' karmic-backports' ' main universe multiverse restricted')} @@ -191,7 +182,7 @@ class TestAptSourceConfig(TestCase): Test Autoreplacement of MIRROR and RELEASE in source specs """ params = self._get_default_params() - cc_apt_configure.add_sources(cfg, params) + cc_apt_configure.add_apt_sources(cfg, params) self.assertTrue(os.path.isfile(filename)) @@ -202,10 +193,7 @@ class TestAptSourceConfig(TestCase): contents, flags=re.IGNORECASE)) def test_apt_src_replace(self): - """test_apt_src_replace - Test Autoreplacement of MIRROR and RELEASE in source specs with - Filename being set - """ + """Test Autoreplacement of MIRROR and RELEASE in source specs""" cfg = {'source': 'deb $MIRROR $RELEASE multiverse', 'filename': self.aptlistfile} self.apt_src_replacement(self.aptlistfile, [cfg]) @@ -231,10 +219,7 @@ class TestAptSourceConfig(TestCase): contents, flags=re.IGNORECASE)) def test_apt_src_replace_tri(self): - """test_apt_src_replace_tri - Test three autoreplacements of MIRROR and RELEASE in source specs with - Filename being set - """ + """Test triple Autoreplacement of MIRROR and RELEASE in source specs""" cfg1 = {'source': 'deb $MIRROR $RELEASE multiverse', 'filename': self.aptlistfile} cfg2 = {'source': 'deb $MIRROR $RELEASE main', @@ -244,13 +229,7 @@ class TestAptSourceConfig(TestCase): self.apt_src_replace_tri([cfg1, cfg2, cfg3]) def test_apt_src_replace_dict_tri(self): - """test_apt_src_replace_dict_tri - Test three autoreplacements of MIRROR and RELEASE in source specs with - Filename being set - Provided in a dictionary with filename being the key (new format) - We also test a new special conditions of the new format that allows - filenames to be overwritten inside the directory entry. - """ + """Test triple Autoreplacement in source specs (dict)""" cfg = {self.aptlistfile: {'source': 'deb $MIRROR $RELEASE multiverse'}, 'notused': {'source': 'deb $MIRROR $RELEASE main', 'filename': self.aptlistfile2}, @@ -258,10 +237,7 @@ class TestAptSourceConfig(TestCase): self.apt_src_replace_tri(cfg) def test_apt_src_replace_nofn(self): - """test_apt_src_replace_nofn - Test Autoreplacement of MIRROR and RELEASE in source specs with - No filename being set - """ + """Test Autoreplacement of MIRROR and RELEASE in source specs nofile""" cfg = {'source': 'deb $MIRROR $RELEASE multiverse'} with mock.patch.object(os.path, 'join', side_effect=self.myjoin): self.apt_src_replacement(self.fallbackfn, [cfg]) @@ -274,7 +250,7 @@ class TestAptSourceConfig(TestCase): with mock.patch.object(util, 'subp', return_value=('fakekey 1234', '')) as mockobj: - cc_apt_configure.add_sources(cfg, params) + cc_apt_configure.add_apt_sources(cfg, params) # check if it added the right ammount of keys calls = [] @@ -293,9 +269,7 @@ class TestAptSourceConfig(TestCase): contents, flags=re.IGNORECASE)) def test_apt_src_keyid(self): - """test_apt_src_keyid - Test specification of a source + keyid with filename being set - """ + """Test specification of a source + keyid with filename being set""" cfg = {'source': ('deb ' 'http://ppa.launchpad.net/' 'smoser/cloud-init-test/ubuntu' @@ -305,10 +279,7 @@ class TestAptSourceConfig(TestCase): self.apt_src_keyid(self.aptlistfile, [cfg], 1) def test_apt_src_keyid_tri(self): - """test_apt_src_keyid_tri - Test specification of a source + keyid with filename being set - Setting three of such, check for content and keys - """ + """Test 3x specification of a source + keyid with filename being set""" cfg1 = {'source': ('deb ' 'http://ppa.launchpad.net/' 'smoser/cloud-init-test/ubuntu' @@ -345,9 +316,7 @@ class TestAptSourceConfig(TestCase): contents, flags=re.IGNORECASE)) def test_apt_src_keyid_nofn(self): - """test_apt_src_keyid_nofn - Test specification of a source + keyid without filename being set - """ + """Test specification of a source + keyid without filename being set""" cfg = {'source': ('deb ' 'http://ppa.launchpad.net/' 'smoser/cloud-init-test/ubuntu' @@ -363,7 +332,7 @@ class TestAptSourceConfig(TestCase): params = self._get_default_params() with mock.patch.object(util, 'subp') as mockobj: - cc_apt_configure.add_sources([cfg], params) + cc_apt_configure.add_apt_sources([cfg], params) mockobj.assert_called_with(('apt-key', 'add', '-'), 'fakekey 4321') @@ -378,9 +347,7 @@ class TestAptSourceConfig(TestCase): contents, flags=re.IGNORECASE)) def test_apt_src_key(self): - """test_apt_src_key - Test specification of a source + key with filename being set - """ + """Test specification of a source + key with filename being set""" cfg = {'source': ('deb ' 'http://ppa.launchpad.net/' 'smoser/cloud-init-test/ubuntu' @@ -390,9 +357,7 @@ class TestAptSourceConfig(TestCase): self.apt_src_key(self.aptlistfile, cfg) def test_apt_src_key_nofn(self): - """test_apt_src_key_nofn - Test specification of a source + key without filename being set - """ + """Test specification of a source + key without filename being set""" cfg = {'source': ('deb ' 'http://ppa.launchpad.net/' 'smoser/cloud-init-test/ubuntu' @@ -402,15 +367,13 @@ class TestAptSourceConfig(TestCase): self.apt_src_key(self.fallbackfn, cfg) def test_apt_src_keyonly(self): - """test_apt_src_keyonly - Test specification key without source - """ + """Test specifying key without source""" params = self._get_default_params() cfg = {'key': "fakekey 4242", 'filename': self.aptlistfile} with mock.patch.object(util, 'subp') as mockobj: - cc_apt_configure.add_sources([cfg], params) + cc_apt_configure.add_apt_sources([cfg], params) mockobj.assert_called_once_with(('apt-key', 'add', '-'), 'fakekey 4242') @@ -419,62 +382,68 @@ class TestAptSourceConfig(TestCase): self.assertFalse(os.path.isfile(self.aptlistfile)) def test_apt_src_keyidonly(self): - """test_apt_src_keyidonly - Test specification of a keyid without source - """ + """Test specification of a keyid without source""" params = self._get_default_params() cfg = {'keyid': "03683F77", 'filename': self.aptlistfile} with mock.patch.object(util, 'subp', return_value=('fakekey 1212', '')) as mockobj: - cc_apt_configure.add_sources([cfg], params) + cc_apt_configure.add_apt_sources([cfg], params) mockobj.assert_called_with(('apt-key', 'add', '-'), 'fakekey 1212') # filename should be ignored on key only self.assertFalse(os.path.isfile(self.aptlistfile)) - def test_apt_src_keyid_real(self): - """test_apt_src_keyid_real - Test specification of a keyid without source incl - up to addition of the key (nothing but add_key_raw mocked) + def apt_src_keyid_real(self, cfg, expectedkey): + """apt_src_keyid_real + Test specification of a keyid without source including + up to addition of the key (add_apt_key_raw mocked to keep the + environment as is) """ - keyid = "03683F77" params = self._get_default_params() - cfg = {'keyid': keyid, - 'filename': self.aptlistfile} - with mock.patch.object(cc_apt_configure, 'add_key_raw') as mockobj: - cc_apt_configure.add_sources([cfg], params) + with mock.patch.object(cc_apt_configure, 'add_apt_key_raw') as mockkey: + with mock.patch.object(gpg, 'get_key_by_id', + return_value=expectedkey) as mockgetkey: + cc_apt_configure.add_apt_sources([cfg], params) - mockobj.assert_called_with(EXPECTEDKEY) + mockgetkey.assert_called_with(cfg['keyid'], + cfg.get('keyserver', + 'keyserver.ubuntu.com')) + mockkey.assert_called_with(expectedkey) # filename should be ignored on key only self.assertFalse(os.path.isfile(self.aptlistfile)) + def test_apt_src_keyid_real(self): + """test_apt_src_keyid_real - Test keyid including key add""" + keyid = "03683F77" + cfg = {'keyid': keyid, + 'filename': self.aptlistfile} + + self.apt_src_keyid_real(cfg, EXPECTEDKEY) + def test_apt_src_longkeyid_real(self): - """test_apt_src_longkeyid_real - Test specification of a long key fingerprint without source incl - up to addition of the key (nothing but add_key_raw mocked) - """ + """test_apt_src_longkeyid_real - Test long keyid including key add""" keyid = "B59D 5F15 97A5 04B7 E230 6DCA 0620 BBCF 0368 3F77" - params = self._get_default_params() cfg = {'keyid': keyid, 'filename': self.aptlistfile} - with mock.patch.object(cc_apt_configure, 'add_key_raw') as mockobj: - cc_apt_configure.add_sources([cfg], params) + self.apt_src_keyid_real(cfg, EXPECTEDKEY) - mockobj.assert_called_with(EXPECTEDKEY) + def test_apt_src_longkeyid_ks_real(self): + """test_apt_src_longkeyid_ks_real - Test long keyid from other ks""" + keyid = "B59D 5F15 97A5 04B7 E230 6DCA 0620 BBCF 0368 3F77" + cfg = {'keyid': keyid, + 'keyserver': 'keys.gnupg.net', + 'filename': self.aptlistfile} - # filename should be ignored on key only - self.assertFalse(os.path.isfile(self.aptlistfile)) + self.apt_src_keyid_real(cfg, EXPECTEDKEY) def test_apt_src_ppa(self): - """test_apt_src_ppa - Test specification of a ppa - """ + """Test adding a ppa""" params = self._get_default_params() cfg = {'source': 'ppa:smoser/cloud-init-test', 'filename': self.aptlistfile} @@ -483,7 +452,8 @@ class TestAptSourceConfig(TestCase): matcher = re.compile(r'^[\w-]+:\w').search with mock.patch.object(util, 'subp') as mockobj: - cc_apt_configure.add_sources([cfg], params, aa_repo_match=matcher) + cc_apt_configure.add_apt_sources([cfg], params, + aa_repo_match=matcher) mockobj.assert_called_once_with(['add-apt-repository', 'ppa:smoser/cloud-init-test']) @@ -491,9 +461,7 @@ class TestAptSourceConfig(TestCase): self.assertFalse(os.path.isfile(self.aptlistfile)) def test_apt_src_ppa_tri(self): - """test_apt_src_ppa_tri - Test specification of a ppa - """ + """Test adding three ppa's""" params = self._get_default_params() cfg1 = {'source': 'ppa:smoser/cloud-init-test', 'filename': self.aptlistfile} @@ -506,8 +474,8 @@ class TestAptSourceConfig(TestCase): matcher = re.compile(r'^[\w-]+:\w').search with mock.patch.object(util, 'subp') as mockobj: - cc_apt_configure.add_sources([cfg1, cfg2, cfg3], params, - aa_repo_match=matcher) + cc_apt_configure.add_apt_sources([cfg1, cfg2, cfg3], params, + aa_repo_match=matcher) calls = [call(['add-apt-repository', 'ppa:smoser/cloud-init-test']), call(['add-apt-repository', 'ppa:smoser/cloud-init-test2']), call(['add-apt-repository', 'ppa:smoser/cloud-init-test3'])] @@ -519,10 +487,7 @@ class TestAptSourceConfig(TestCase): self.assertFalse(os.path.isfile(self.aptlistfile3)) def test_convert_to_new_format(self): - """test_convert_to_new_format - Test the conversion of old to new format - And the noop conversion of new to new format as well - """ + """Test the conversion of old to new format""" cfg1 = {'source': 'deb $MIRROR $RELEASE multiverse', 'filename': self.aptlistfile} cfg2 = {'source': 'deb $MIRROR $RELEASE main', |