Merge lp:~paelzer/cloud-init/bug-1589174-fix-tests-in-adt-env into lp:~cloud-init-dev/cloud-init/trunk

Proposed by Christian Ehrhardt 
Status: Merged
Merged at revision: 1230
Proposed branch: lp:~paelzer/cloud-init/bug-1589174-fix-tests-in-adt-env
Merge into: lp:~cloud-init-dev/cloud-init/trunk
Diff against target: 727 lines (+205/-179)
5 files modified
cloudinit/config/cc_apt_configure.py (+16/-40)
cloudinit/gpg.py (+76/-0)
packages/bddeb (+6/-0)
tests/unittests/test_handler/test_handler_apt_configure_sources_list.py (+37/-24)
tests/unittests/test_handler/test_handler_apt_source.py (+70/-115)
To merge this branch: bzr merge lp:~paelzer/cloud-init/bug-1589174-fix-tests-in-adt-env
Reviewer Review Type Date Requested Status
cloud-init Commiters Pending
Review via email: mp+296643@code.launchpad.net

Commit message

Fixes to the unittests to run in more environments;
As well as some improvements that were found along testing them and due to the fact that we review some of that code again in the scope of curtin currently.

Tests:
- add a test for an alternate keyserver
- harden mirrorfail tests to detect and skip if no network is available
- improve apt_source related tests to work on CentOS7

Changes:
- gpg key handling is now in python instead of a shell blob
- packages/bddeb has an option to sign as someone else than smoser
- make exception handling of apt_source features more specific (i.e. no catch Exception)
- rename some functions to relfect better what they actually do
- capture some helper subp calls output to avoid spilling into stdout when not intended

Description of the change

Fixes to the unittests to run in more environments;
As well as some improvements that were found along testing them and due to the fact that we review some of that code again in the scope of curtin currently.

Tests:
- add a test for an alternate keyserver
- harden mirrorfail tests to detect and skip if no network is available
- improve apt_source related tests to work on CentOS7

Changes:
- gpg key handling is now in python instead of a shell blob
- packages/bddeb has an option to sign as someone else than smoser
- make exception handling of apt_source features more specific (i.e. no catch Exception)
- rename some functions to relfect better what they actually do
- capture some helper subp calls output to avoid spilling into stdout when not intended

To post a comment you must log in.
1246. By Christian Ehrhardt 

merge with upstream to avoid merge conflicts on the merge proposal

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

I hope it merges without conflict now

Revision history for this message
Scott Moser (smoser) wrote :

mostly looks good. a couple comments. thank you.

1247. By Christian Ehrhardt 

move gpg functions into gpg.py

This helps for cleaner code structuring.
ALong that makeing sure all these functions have a gpg_prefix.

1248. By Christian Ehrhardt 

improve error handling and reporting in gpg functions

1249. By Christian Ehrhardt 

move SkipTest definition to tests/unittests/helpers.py to be reusable

1250. By Christian Ehrhardt 

remove unused BIN_APT constant

1251. By Christian Ehrhardt 

fix docstring for check connectivity

1252. By Christian Ehrhardt 

mock is_resolvable in mirrorfail tests to remove dependency to external net

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Thanks, addressed all you mentioned - will throw it through more testing now.

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Ok, fine in sbuild, a partially shutdown network env and buildd (https://launchpad.net/~paelzer/+archive/ubuntu/derived-repository-testbuilds/+build/9891133), no merge conflict atm - please reconsider for merging

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'cloudinit/config/cc_apt_configure.py'
--- cloudinit/config/cc_apt_configure.py 2016-06-03 19:27:32 +0000
+++ cloudinit/config/cc_apt_configure.py 2016-06-09 08:37:01 +0000
@@ -24,6 +24,7 @@
2424
25from cloudinit import templater25from cloudinit import templater
26from cloudinit import util26from cloudinit import util
27from cloudinit import gpg
2728
28distros = ['ubuntu', 'debian']29distros = ['ubuntu', 'debian']
2930
@@ -34,21 +35,6 @@
34# this will match 'XXX:YYY' (ie, 'cloud-archive:foo' or 'ppa:bar')35# this will match 'XXX:YYY' (ie, 'cloud-archive:foo' or 'ppa:bar')
35ADD_APT_REPO_MATCH = r"^[\w-]+:\w"36ADD_APT_REPO_MATCH = r"^[\w-]+:\w"
3637
37# A temporary shell program to get a given gpg key
38# from a given keyserver
39EXPORT_GPG_KEYID = """
40 k=${1} ks=${2};
41 exec 2>/dev/null
42 [ -n "$k" ] || exit 1;
43 armour=$(gpg --export --armour "${k}")
44 if [ -z "${armour}" ]; then
45 gpg --keyserver ${ks} --recv "${k}" >/dev/null &&
46 armour=$(gpg --export --armour "${k}") &&
47 gpg --batch --yes --delete-keys "${k}"
48 fi
49 [ -n "${armour}" ] && echo "${armour}"
50"""
51
5238
53def handle(name, cfg, cloud, log, _args):39def handle(name, cfg, cloud, log, _args):
54 if util.is_false(cfg.get('apt_configure_enabled', True)):40 if util.is_false(cfg.get('apt_configure_enabled', True)):
@@ -94,8 +80,8 @@
94 def matcher(x):80 def matcher(x):
95 return False81 return False
9682
97 errors = add_sources(cfg['apt_sources'], params,83 errors = add_apt_sources(cfg['apt_sources'], params,
98 aa_repo_match=matcher)84 aa_repo_match=matcher)
99 for e in errors:85 for e in errors:
100 log.warn("Add source error: %s", ':'.join(e))86 log.warn("Add source error: %s", ':'.join(e))
10187
@@ -108,17 +94,7 @@
108 util.logexc(log, "Failed to run debconf-set-selections")94 util.logexc(log, "Failed to run debconf-set-selections")
10995
11096
111# get gpg keyid from keyserver97def mirrorurl_to_apt_fileprefix(mirror):
112def getkeybyid(keyid, keyserver):
113 with util.ExtendedTemporaryFile(suffix='.sh', mode="w+", ) as fh:
114 fh.write(EXPORT_GPG_KEYID)
115 fh.flush()
116 cmd = ['/bin/sh', fh.name, keyid, keyserver]
117 (stdout, _stderr) = util.subp(cmd)
118 return stdout.strip()
119
120
121def mirror2lists_fileprefix(mirror):
122 string = mirror98 string = mirror
123 # take off http:// or ftp://99 # take off http:// or ftp://
124 if string.endswith("/"):100 if string.endswith("/"):
@@ -135,8 +111,8 @@
135 nmirror = new_mirrors.get(name)111 nmirror = new_mirrors.get(name)
136 if not nmirror:112 if not nmirror:
137 continue113 continue
138 oprefix = os.path.join(lists_d, mirror2lists_fileprefix(omirror))114 oprefix = os.path.join(lists_d, mirrorurl_to_apt_fileprefix(omirror))
139 nprefix = os.path.join(lists_d, mirror2lists_fileprefix(nmirror))115 nprefix = os.path.join(lists_d, mirrorurl_to_apt_fileprefix(nmirror))
140 if oprefix == nprefix:116 if oprefix == nprefix:
141 continue117 continue
142 olen = len(oprefix)118 olen = len(oprefix)
@@ -171,7 +147,7 @@
171 templater.render_to_file(template_fn, '/etc/apt/sources.list', params)147 templater.render_to_file(template_fn, '/etc/apt/sources.list', params)
172148
173149
174def add_key_raw(key):150def add_apt_key_raw(key):
175 """151 """
176 actual adding of a key as defined in key argument152 actual adding of a key as defined in key argument
177 to the system153 to the system
@@ -179,10 +155,10 @@
179 try:155 try:
180 util.subp(('apt-key', 'add', '-'), key)156 util.subp(('apt-key', 'add', '-'), key)
181 except util.ProcessExecutionError:157 except util.ProcessExecutionError:
182 raise Exception('failed add key')158 raise ValueError('failed to add apt GPG Key to apt keyring')
183159
184160
185def add_key(ent):161def add_apt_key(ent):
186 """162 """
187 add key to the system as defined in ent (if any)163 add key to the system as defined in ent (if any)
188 supports raw keys or keyid's164 supports raw keys or keyid's
@@ -192,10 +168,10 @@
192 keyserver = "keyserver.ubuntu.com"168 keyserver = "keyserver.ubuntu.com"
193 if 'keyserver' in ent:169 if 'keyserver' in ent:
194 keyserver = ent['keyserver']170 keyserver = ent['keyserver']
195 ent['key'] = getkeybyid(ent['keyid'], keyserver)171 ent['key'] = gpg.gpg_getkeybyid(ent['keyid'], keyserver)
196172
197 if 'key' in ent:173 if 'key' in ent:
198 add_key_raw(ent['key'])174 add_apt_key_raw(ent['key'])
199175
200176
201def convert_to_new_format(srclist):177def convert_to_new_format(srclist):
@@ -222,7 +198,7 @@
222 return srcdict198 return srcdict
223199
224200
225def add_sources(srclist, template_params=None, aa_repo_match=None):201def add_apt_sources(srclist, template_params=None, aa_repo_match=None):
226 """202 """
227 add entries in /etc/apt/sources.list.d for each abbreviated203 add entries in /etc/apt/sources.list.d for each abbreviated
228 sources.list entry in 'srclist'. When rendering template, also204 sources.list entry in 'srclist'. When rendering template, also
@@ -245,8 +221,8 @@
245221
246 # keys can be added without specifying a source222 # keys can be added without specifying a source
247 try:223 try:
248 add_key(ent)224 add_apt_key(ent)
249 except Exception as detail:225 except ValueError as detail:
250 errorlist.append([ent, detail])226 errorlist.append([ent, detail])
251227
252 if 'source' not in ent:228 if 'source' not in ent:
253229
=== added file 'cloudinit/gpg.py'
--- cloudinit/gpg.py 1970-01-01 00:00:00 +0000
+++ cloudinit/gpg.py 2016-06-09 08:37:01 +0000
@@ -0,0 +1,76 @@
1"""gpg.py - Collection of gpg key related functions"""
2# vi: ts=4 expandtab
3#
4# Copyright (C) 2016 Canonical Ltd.
5#
6# Author: Scott Moser <scott.moser@canonical.com>
7# Author: Juerg Haefliger <juerg.haefliger@hp.com>
8# Author: Joshua Harlow <harlowja@yahoo-inc.com>
9# Author: Christian Ehrhardt <christian.ehrhardt@canonical.com>
10#
11# This program is free software: you can redistribute it and/or modify
12# it under the terms of the GNU General Public License version 3, as
13# published by the Free Software Foundation.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program. If not, see <http://www.gnu.org/licenses/>.
22
23from cloudinit import util
24from cloudinit import log as logging
25
26LOG = logging.getLogger(__name__)
27
28
29def gpg_export_armour(key):
30 """Export gpg key, armoured key gets returned"""
31 try:
32 (armour, _) = util.subp(["gpg", "--export", "--armour", key],
33 capture=True)
34 except util.ProcessExecutionError as error:
35 # debug, since it happens for any key not on the system initially
36 LOG.debug('Failed to export armoured key "%s": %s', key, error)
37 armour = None
38 return armour
39
40
41def gpg_recv_key(key, keyserver):
42 """Receive gpg key from the specified keyserver"""
43 LOG.debug('Receive gpg key "%s"', key)
44 try:
45 util.subp(["gpg", "--keyserver", keyserver, "--recv", key],
46 capture=True)
47 except util.ProcessExecutionError as error:
48 raise ValueError(('Failed to import key "%s" '
49 'from server "%s" - error %s') %
50 (key, keyserver, error))
51
52
53def gpg_delete_key(key):
54 """Delete the specified key from the local gpg ring"""
55 try:
56 util.subp(["gpg", "--batch", "--yes", "--delete-keys", key],
57 capture=True)
58 except util.ProcessExecutionError as error:
59 LOG.warn('Failed delete key "%s": %s', key, error)
60
61
62def gpg_getkeybyid(keyid, keyserver):
63 """get gpg keyid from keyserver"""
64 armour = gpg_export_armour(keyid)
65 if not armour:
66 try:
67 gpg_recv_key(keyid, keyserver=keyserver)
68 armour = gpg_export_armour(keyid)
69 except ValueError:
70 LOG.exception('Failed to obtain gpg key %s', keyid)
71 raise
72 finally:
73 # delete just imported key to leave environment as it was before
74 gpg_delete_key(keyid)
75
76 return armour.rstrip('\n')
077
=== modified file 'packages/bddeb'
--- packages/bddeb 2016-05-26 15:51:38 +0000
+++ packages/bddeb 2016-06-09 08:37:01 +0000
@@ -148,11 +148,17 @@
148 parser.add_argument("--sign", default=False, action='store_true',148 parser.add_argument("--sign", default=False, action='store_true',
149 help="sign result. do not pass -us -uc to debuild")149 help="sign result. do not pass -us -uc to debuild")
150150
151 parser.add_argument("--signuser", default=False, action='store',
152 help="user to sign, see man dpkg-genchanges")
153
151 args = parser.parse_args()154 args = parser.parse_args()
152155
153 if not args.sign:156 if not args.sign:
154 args.debuild_args.extend(['-us', '-uc'])157 args.debuild_args.extend(['-us', '-uc'])
155158
159 if args.signuser:
160 args.debuild_args.extend(['-e%s' % args.signuser])
161
156 os.environ['INIT_SYSTEM'] = args.init_system162 os.environ['INIT_SYSTEM'] = args.init_system
157163
158 capture = True164 capture = True
159165
=== modified file 'tests/unittests/test_handler/test_handler_apt_configure_sources_list.py'
--- tests/unittests/test_handler/test_handler_apt_configure_sources_list.py 2016-06-05 00:50:37 +0000
+++ tests/unittests/test_handler/test_handler_apt_configure_sources_list.py 2016-06-09 08:37:01 +0000
@@ -20,6 +20,8 @@
20from cloudinit.config import cc_apt_configure20from cloudinit.config import cc_apt_configure
21from cloudinit.sources import DataSourceNone21from cloudinit.sources import DataSourceNone
2222
23from cloudinit.distros.debian import Distro
24
23from .. import helpers as t_help25from .. import helpers as t_help
2426
25LOG = logging.getLogger(__name__)27LOG = logging.getLogger(__name__)
@@ -115,38 +117,47 @@
115 {'codename': '', 'primary': mirrorcheck, 'mirror': mirrorcheck})117 {'codename': '', 'primary': mirrorcheck, 'mirror': mirrorcheck})
116118
117 def test_apt_source_list_debian(self):119 def test_apt_source_list_debian(self):
118 """test_apt_source_list_debian120 """Test rendering of a source.list from template for debian"""
119 Test rendering of a source.list from template for debian
120 """
121 self.apt_source_list('debian', 'http://httpredir.debian.org/debian')121 self.apt_source_list('debian', 'http://httpredir.debian.org/debian')
122122
123 def test_apt_source_list_ubuntu(self):123 def test_apt_source_list_ubuntu(self):
124 """test_apt_source_list_ubuntu124 """Test rendering of a source.list from template for ubuntu"""
125 Test rendering of a source.list from template for ubuntu
126 """
127 self.apt_source_list('ubuntu', 'http://archive.ubuntu.com/ubuntu/')125 self.apt_source_list('ubuntu', 'http://archive.ubuntu.com/ubuntu/')
128126
129 @t_help.skipIf(True, "LP: #1589174")127 @staticmethod
128 def myresolve(name):
129 """Fake util.is_resolvable for mirrorfail tests"""
130 if name == "does.not.exist":
131 print("Faking FAIL for '%s'" % name)
132 return False
133 else:
134 print("Faking SUCCESS for '%s'" % name)
135 return True
136
130 def test_apt_srcl_debian_mirrorfail(self):137 def test_apt_srcl_debian_mirrorfail(self):
131 """test_apt_source_list_debian_mirrorfail138 """Test rendering of a source.list from template for debian"""
132 Test rendering of a source.list from template for debian139 with mock.patch.object(util, 'is_resolvable',
133 """140 side_effect=self.myresolve) as mockresolve:
134 self.apt_source_list('debian', ['http://does.not.exist',141 self.apt_source_list('debian',
135 'http://httpredir.debian.org/debian'],142 ['http://does.not.exist',
136 'http://httpredir.debian.org/debian')143 'http://httpredir.debian.org/debian'],
144 'http://httpredir.debian.org/debian')
145 mockresolve.assert_any_call("does.not.exist")
146 mockresolve.assert_any_call("httpredir.debian.org")
137147
138 def test_apt_srcl_ubuntu_mirrorfail(self):148 def test_apt_srcl_ubuntu_mirrorfail(self):
139 """test_apt_source_list_ubuntu_mirrorfail149 """Test rendering of a source.list from template for ubuntu"""
140 Test rendering of a source.list from template for ubuntu150 with mock.patch.object(util, 'is_resolvable',
141 """151 side_effect=self.myresolve) as mockresolve:
142 self.apt_source_list('ubuntu', ['http://does.not.exist',152 self.apt_source_list('ubuntu',
143 'http://archive.ubuntu.com/ubuntu/'],153 ['http://does.not.exist',
144 'http://archive.ubuntu.com/ubuntu/')154 'http://archive.ubuntu.com/ubuntu/'],
155 'http://archive.ubuntu.com/ubuntu/')
156 mockresolve.assert_any_call("does.not.exist")
157 mockresolve.assert_any_call("archive.ubuntu.com")
145158
146 def test_apt_srcl_custom(self):159 def test_apt_srcl_custom(self):
147 """test_apt_srcl_custom160 """Test rendering from a custom source.list template"""
148 Test rendering from a custom source.list template
149 """
150 cfg = util.load_yaml(YAML_TEXT_CUSTOM_SL)161 cfg = util.load_yaml(YAML_TEXT_CUSTOM_SL)
151 mycloud = self._get_cloud('ubuntu')162 mycloud = self._get_cloud('ubuntu')
152163
@@ -155,8 +166,10 @@
155 with mock.patch.object(util, 'subp', self.subp):166 with mock.patch.object(util, 'subp', self.subp):
156 with mock.patch.object(cc_apt_configure, 'get_release',167 with mock.patch.object(cc_apt_configure, 'get_release',
157 return_value='fakerelease'):168 return_value='fakerelease'):
158 cc_apt_configure.handle("notimportant", cfg, mycloud,169 with mock.patch.object(Distro, 'get_primary_arch',
159 LOG, None)170 return_value='amd64'):
171 cc_apt_configure.handle("notimportant", cfg, mycloud,
172 LOG, None)
160173
161 mockwrite.assert_called_once_with(174 mockwrite.assert_called_once_with(
162 '/etc/apt/sources.list',175 '/etc/apt/sources.list',
163176
=== modified file 'tests/unittests/test_handler/test_handler_apt_source.py'
--- tests/unittests/test_handler/test_handler_apt_source.py 2016-06-04 02:56:45 +0000
+++ tests/unittests/test_handler/test_handler_apt_source.py 2016-06-09 08:37:01 +0000
@@ -14,6 +14,7 @@
1414
15from cloudinit.config import cc_apt_configure15from cloudinit.config import cc_apt_configure
16from cloudinit import util16from cloudinit import util
17from cloudinit import gpg
1718
18from ..helpers import TestCase19from ..helpers import TestCase
1920
@@ -62,7 +63,8 @@
62 get_rel.return_value = self.release63 get_rel.return_value = self.release
63 self.addCleanup(patcher.stop)64 self.addCleanup(patcher.stop)
6465
65 def _get_default_params(self):66 @staticmethod
67 def _get_default_params():
66 """get_default_params68 """get_default_params
67 Get the most basic default mrror and release info to be used in tests69 Get the most basic default mrror and release info to be used in tests
68 """70 """
@@ -86,7 +88,7 @@
86 """88 """
87 params = self._get_default_params()89 params = self._get_default_params()
8890
89 cc_apt_configure.add_sources(cfg, params)91 cc_apt_configure.add_apt_sources(cfg, params)
9092
91 self.assertTrue(os.path.isfile(filename))93 self.assertTrue(os.path.isfile(filename))
9294
@@ -98,10 +100,7 @@
98 contents, flags=re.IGNORECASE))100 contents, flags=re.IGNORECASE))
99101
100 def test_apt_src_basic(self):102 def test_apt_src_basic(self):
101 """test_apt_src_basic103 """Test deb source string, overwrite mirror and filename"""
102 Test Fix deb source string, has to overwrite mirror conf in params.
103 Test with a filename provided in config.
104 """
105 cfg = {'source': ('deb http://archive.ubuntu.com/ubuntu'104 cfg = {'source': ('deb http://archive.ubuntu.com/ubuntu'
106 ' karmic-backports'105 ' karmic-backports'
107 ' main universe multiverse restricted'),106 ' main universe multiverse restricted'),
@@ -109,11 +108,7 @@
109 self.apt_src_basic(self.aptlistfile, [cfg])108 self.apt_src_basic(self.aptlistfile, [cfg])
110109
111 def test_apt_src_basic_dict(self):110 def test_apt_src_basic_dict(self):
112 """test_apt_src_basic_dict111 """Test deb source string, overwrite mirror and filename (dict)"""
113 Test Fix deb source string, has to overwrite mirror conf in params.
114 Test with a filename provided in config.
115 Provided in a dictionary with filename being the key (new format)
116 """
117 cfg = {self.aptlistfile: {'source':112 cfg = {self.aptlistfile: {'source':
118 ('deb http://archive.ubuntu.com/ubuntu'113 ('deb http://archive.ubuntu.com/ubuntu'
119 ' karmic-backports'114 ' karmic-backports'
@@ -143,10 +138,7 @@
143 contents, flags=re.IGNORECASE))138 contents, flags=re.IGNORECASE))
144139
145 def test_apt_src_basic_tri(self):140 def test_apt_src_basic_tri(self):
146 """test_apt_src_basic_tri141 """Test Fix three deb source string with filenames"""
147 Test Fix three deb source string, has to overwrite mirror conf in
148 params. Test with filenames provided in config.
149 """
150 cfg1 = {'source': ('deb http://archive.ubuntu.com/ubuntu'142 cfg1 = {'source': ('deb http://archive.ubuntu.com/ubuntu'
151 ' karmic-backports'143 ' karmic-backports'
152 ' main universe multiverse restricted'),144 ' main universe multiverse restricted'),
@@ -162,11 +154,7 @@
162 self.apt_src_basic_tri([cfg1, cfg2, cfg3])154 self.apt_src_basic_tri([cfg1, cfg2, cfg3])
163155
164 def test_apt_src_basic_dict_tri(self):156 def test_apt_src_basic_dict_tri(self):
165 """test_apt_src_basic_dict_tri157 """Test Fix three deb source string with filenames (dict)"""
166 Test Fix three deb source string, has to overwrite mirror conf in
167 params. Test with filenames provided in config.
168 Provided in a dictionary with filename being the key (new format)
169 """
170 cfg = {self.aptlistfile: {'source':158 cfg = {self.aptlistfile: {'source':
171 ('deb http://archive.ubuntu.com/ubuntu'159 ('deb http://archive.ubuntu.com/ubuntu'
172 ' karmic-backports'160 ' karmic-backports'
@@ -182,10 +170,7 @@
182 self.apt_src_basic_tri(cfg)170 self.apt_src_basic_tri(cfg)
183171
184 def test_apt_src_basic_nofn(self):172 def test_apt_src_basic_nofn(self):
185 """test_apt_src_basic_nofn173 """Test Fix three deb source string without filenames (dict)"""
186 Test Fix deb source string, has to overwrite mirror conf in params.
187 Test without a filename provided in config and test for known fallback.
188 """
189 cfg = {'source': ('deb http://archive.ubuntu.com/ubuntu'174 cfg = {'source': ('deb http://archive.ubuntu.com/ubuntu'
190 ' karmic-backports'175 ' karmic-backports'
191 ' main universe multiverse restricted')}176 ' main universe multiverse restricted')}
@@ -197,7 +182,7 @@
197 Test Autoreplacement of MIRROR and RELEASE in source specs182 Test Autoreplacement of MIRROR and RELEASE in source specs
198 """183 """
199 params = self._get_default_params()184 params = self._get_default_params()
200 cc_apt_configure.add_sources(cfg, params)185 cc_apt_configure.add_apt_sources(cfg, params)
201186
202 self.assertTrue(os.path.isfile(filename))187 self.assertTrue(os.path.isfile(filename))
203188
@@ -208,10 +193,7 @@
208 contents, flags=re.IGNORECASE))193 contents, flags=re.IGNORECASE))
209194
210 def test_apt_src_replace(self):195 def test_apt_src_replace(self):
211 """test_apt_src_replace196 """Test Autoreplacement of MIRROR and RELEASE in source specs"""
212 Test Autoreplacement of MIRROR and RELEASE in source specs with
213 Filename being set
214 """
215 cfg = {'source': 'deb $MIRROR $RELEASE multiverse',197 cfg = {'source': 'deb $MIRROR $RELEASE multiverse',
216 'filename': self.aptlistfile}198 'filename': self.aptlistfile}
217 self.apt_src_replacement(self.aptlistfile, [cfg])199 self.apt_src_replacement(self.aptlistfile, [cfg])
@@ -237,10 +219,7 @@
237 contents, flags=re.IGNORECASE))219 contents, flags=re.IGNORECASE))
238220
239 def test_apt_src_replace_tri(self):221 def test_apt_src_replace_tri(self):
240 """test_apt_src_replace_tri222 """Test triple Autoreplacement of MIRROR and RELEASE in source specs"""
241 Test three autoreplacements of MIRROR and RELEASE in source specs with
242 Filename being set
243 """
244 cfg1 = {'source': 'deb $MIRROR $RELEASE multiverse',223 cfg1 = {'source': 'deb $MIRROR $RELEASE multiverse',
245 'filename': self.aptlistfile}224 'filename': self.aptlistfile}
246 cfg2 = {'source': 'deb $MIRROR $RELEASE main',225 cfg2 = {'source': 'deb $MIRROR $RELEASE main',
@@ -250,13 +229,7 @@
250 self.apt_src_replace_tri([cfg1, cfg2, cfg3])229 self.apt_src_replace_tri([cfg1, cfg2, cfg3])
251230
252 def test_apt_src_replace_dict_tri(self):231 def test_apt_src_replace_dict_tri(self):
253 """test_apt_src_replace_dict_tri232 """Test triple Autoreplacement in source specs (dict)"""
254 Test three autoreplacements of MIRROR and RELEASE in source specs with
255 Filename being set
256 Provided in a dictionary with filename being the key (new format)
257 We also test a new special conditions of the new format that allows
258 filenames to be overwritten inside the directory entry.
259 """
260 cfg = {self.aptlistfile: {'source': 'deb $MIRROR $RELEASE multiverse'},233 cfg = {self.aptlistfile: {'source': 'deb $MIRROR $RELEASE multiverse'},
261 'notused': {'source': 'deb $MIRROR $RELEASE main',234 'notused': {'source': 'deb $MIRROR $RELEASE main',
262 'filename': self.aptlistfile2},235 'filename': self.aptlistfile2},
@@ -264,10 +237,7 @@
264 self.apt_src_replace_tri(cfg)237 self.apt_src_replace_tri(cfg)
265238
266 def test_apt_src_replace_nofn(self):239 def test_apt_src_replace_nofn(self):
267 """test_apt_src_replace_nofn240 """Test Autoreplacement of MIRROR and RELEASE in source specs nofile"""
268 Test Autoreplacement of MIRROR and RELEASE in source specs with
269 No filename being set
270 """
271 cfg = {'source': 'deb $MIRROR $RELEASE multiverse'}241 cfg = {'source': 'deb $MIRROR $RELEASE multiverse'}
272 with mock.patch.object(os.path, 'join', side_effect=self.myjoin):242 with mock.patch.object(os.path, 'join', side_effect=self.myjoin):
273 self.apt_src_replacement(self.fallbackfn, [cfg])243 self.apt_src_replacement(self.fallbackfn, [cfg])
@@ -280,7 +250,7 @@
280250
281 with mock.patch.object(util, 'subp',251 with mock.patch.object(util, 'subp',
282 return_value=('fakekey 1234', '')) as mockobj:252 return_value=('fakekey 1234', '')) as mockobj:
283 cc_apt_configure.add_sources(cfg, params)253 cc_apt_configure.add_apt_sources(cfg, params)
284254
285 # check if it added the right ammount of keys255 # check if it added the right ammount of keys
286 calls = []256 calls = []
@@ -299,9 +269,7 @@
299 contents, flags=re.IGNORECASE))269 contents, flags=re.IGNORECASE))
300270
301 def test_apt_src_keyid(self):271 def test_apt_src_keyid(self):
302 """test_apt_src_keyid272 """Test specification of a source + keyid with filename being set"""
303 Test specification of a source + keyid with filename being set
304 """
305 cfg = {'source': ('deb '273 cfg = {'source': ('deb '
306 'http://ppa.launchpad.net/'274 'http://ppa.launchpad.net/'
307 'smoser/cloud-init-test/ubuntu'275 'smoser/cloud-init-test/ubuntu'
@@ -311,10 +279,7 @@
311 self.apt_src_keyid(self.aptlistfile, [cfg], 1)279 self.apt_src_keyid(self.aptlistfile, [cfg], 1)
312280
313 def test_apt_src_keyid_tri(self):281 def test_apt_src_keyid_tri(self):
314 """test_apt_src_keyid_tri282 """Test 3x specification of a source + keyid with filename being set"""
315 Test specification of a source + keyid with filename being set
316 Setting three of such, check for content and keys
317 """
318 cfg1 = {'source': ('deb '283 cfg1 = {'source': ('deb '
319 'http://ppa.launchpad.net/'284 'http://ppa.launchpad.net/'
320 'smoser/cloud-init-test/ubuntu'285 'smoser/cloud-init-test/ubuntu'
@@ -351,9 +316,7 @@
351 contents, flags=re.IGNORECASE))316 contents, flags=re.IGNORECASE))
352317
353 def test_apt_src_keyid_nofn(self):318 def test_apt_src_keyid_nofn(self):
354 """test_apt_src_keyid_nofn319 """Test specification of a source + keyid without filename being set"""
355 Test specification of a source + keyid without filename being set
356 """
357 cfg = {'source': ('deb '320 cfg = {'source': ('deb '
358 'http://ppa.launchpad.net/'321 'http://ppa.launchpad.net/'
359 'smoser/cloud-init-test/ubuntu'322 'smoser/cloud-init-test/ubuntu'
@@ -369,7 +332,7 @@
369 params = self._get_default_params()332 params = self._get_default_params()
370333
371 with mock.patch.object(util, 'subp') as mockobj:334 with mock.patch.object(util, 'subp') as mockobj:
372 cc_apt_configure.add_sources([cfg], params)335 cc_apt_configure.add_apt_sources([cfg], params)
373336
374 mockobj.assert_called_with(('apt-key', 'add', '-'), 'fakekey 4321')337 mockobj.assert_called_with(('apt-key', 'add', '-'), 'fakekey 4321')
375338
@@ -384,9 +347,7 @@
384 contents, flags=re.IGNORECASE))347 contents, flags=re.IGNORECASE))
385348
386 def test_apt_src_key(self):349 def test_apt_src_key(self):
387 """test_apt_src_key350 """Test specification of a source + key with filename being set"""
388 Test specification of a source + key with filename being set
389 """
390 cfg = {'source': ('deb '351 cfg = {'source': ('deb '
391 'http://ppa.launchpad.net/'352 'http://ppa.launchpad.net/'
392 'smoser/cloud-init-test/ubuntu'353 'smoser/cloud-init-test/ubuntu'
@@ -396,9 +357,7 @@
396 self.apt_src_key(self.aptlistfile, cfg)357 self.apt_src_key(self.aptlistfile, cfg)
397358
398 def test_apt_src_key_nofn(self):359 def test_apt_src_key_nofn(self):
399 """test_apt_src_key_nofn360 """Test specification of a source + key without filename being set"""
400 Test specification of a source + key without filename being set
401 """
402 cfg = {'source': ('deb '361 cfg = {'source': ('deb '
403 'http://ppa.launchpad.net/'362 'http://ppa.launchpad.net/'
404 'smoser/cloud-init-test/ubuntu'363 'smoser/cloud-init-test/ubuntu'
@@ -408,15 +367,13 @@
408 self.apt_src_key(self.fallbackfn, cfg)367 self.apt_src_key(self.fallbackfn, cfg)
409368
410 def test_apt_src_keyonly(self):369 def test_apt_src_keyonly(self):
411 """test_apt_src_keyonly370 """Test specifying key without source"""
412 Test specification key without source
413 """
414 params = self._get_default_params()371 params = self._get_default_params()
415 cfg = {'key': "fakekey 4242",372 cfg = {'key': "fakekey 4242",
416 'filename': self.aptlistfile}373 'filename': self.aptlistfile}
417374
418 with mock.patch.object(util, 'subp') as mockobj:375 with mock.patch.object(util, 'subp') as mockobj:
419 cc_apt_configure.add_sources([cfg], params)376 cc_apt_configure.add_apt_sources([cfg], params)
420377
421 mockobj.assert_called_once_with(('apt-key', 'add', '-'),378 mockobj.assert_called_once_with(('apt-key', 'add', '-'),
422 'fakekey 4242')379 'fakekey 4242')
@@ -425,66 +382,68 @@
425 self.assertFalse(os.path.isfile(self.aptlistfile))382 self.assertFalse(os.path.isfile(self.aptlistfile))
426383
427 def test_apt_src_keyidonly(self):384 def test_apt_src_keyidonly(self):
428 """test_apt_src_keyidonly385 """Test specification of a keyid without source"""
429 Test specification of a keyid without source
430 """
431 params = self._get_default_params()386 params = self._get_default_params()
432 cfg = {'keyid': "03683F77",387 cfg = {'keyid': "03683F77",
433 'filename': self.aptlistfile}388 'filename': self.aptlistfile}
434389
435 with mock.patch.object(util, 'subp',390 with mock.patch.object(util, 'subp',
436 return_value=('fakekey 1212', '')) as mockobj:391 return_value=('fakekey 1212', '')) as mockobj:
437 cc_apt_configure.add_sources([cfg], params)392 cc_apt_configure.add_apt_sources([cfg], params)
438393
439 mockobj.assert_called_with(('apt-key', 'add', '-'), 'fakekey 1212')394 mockobj.assert_called_with(('apt-key', 'add', '-'), 'fakekey 1212')
440395
441 # filename should be ignored on key only396 # filename should be ignored on key only
442 self.assertFalse(os.path.isfile(self.aptlistfile))397 self.assertFalse(os.path.isfile(self.aptlistfile))
443398
399 def apt_src_keyid_real(self, cfg, expectedkey):
400 """apt_src_keyid_real
401 Test specification of a keyid without source including
402 up to addition of the key (add_apt_key_raw mocked to keep the
403 environment as is)
404 """
405 params = self._get_default_params()
406
407 with mock.patch.object(cc_apt_configure, 'add_apt_key_raw') as mockkey:
408 with mock.patch.object(gpg, 'gpg_getkeybyid',
409 return_value=expectedkey) as mockgetkey:
410 cc_apt_configure.add_apt_sources([cfg], params)
411
412 mockgetkey.assert_called_with(cfg['keyid'],
413 cfg.get('keyserver',
414 'keyserver.ubuntu.com'))
415 mockkey.assert_called_with(expectedkey)
416
417 # filename should be ignored on key only
418 self.assertFalse(os.path.isfile(self.aptlistfile))
419
444 def test_apt_src_keyid_real(self):420 def test_apt_src_keyid_real(self):
445 """test_apt_src_keyid_real421 """test_apt_src_keyid_real - Test keyid including key add"""
446 Test specification of a keyid without source incl
447 up to addition of the key (add_key_raw, getkeybyid mocked)
448 """
449 keyid = "03683F77"422 keyid = "03683F77"
450 params = self._get_default_params()
451 cfg = {'keyid': keyid,423 cfg = {'keyid': keyid,
452 'filename': self.aptlistfile}424 'filename': self.aptlistfile}
453425
454 with mock.patch.object(cc_apt_configure, 'add_key_raw') as mockobj:426 self.apt_src_keyid_real(cfg, EXPECTEDKEY)
455 with mock.patch.object(cc_apt_configure, 'getkeybyid') as gkbi:
456 gkbi.return_value = EXPECTEDKEY
457 cc_apt_configure.add_sources([cfg], params)
458
459 mockobj.assert_called_with(EXPECTEDKEY)
460
461 # filename should be ignored on key only
462 self.assertFalse(os.path.isfile(self.aptlistfile))
463427
464 def test_apt_src_longkeyid_real(self):428 def test_apt_src_longkeyid_real(self):
465 """test_apt_src_longkeyid_real429 """test_apt_src_longkeyid_real - Test long keyid including key add"""
466 Test specification of a long key fingerprint without source incl430 keyid = "B59D 5F15 97A5 04B7 E230 6DCA 0620 BBCF 0368 3F77"
467 up to addition of the key (nothing but add_key_raw mocked)431 cfg = {'keyid': keyid,
468 """432 'filename': self.aptlistfile}
469 keyid = "B59D 5F15 97A5 04B7 E230 6DCA 0620 BBCF 0368 3F77"433
470 params = self._get_default_params()434 self.apt_src_keyid_real(cfg, EXPECTEDKEY)
471 cfg = {'keyid': keyid,435
472 'filename': self.aptlistfile}436 def test_apt_src_longkeyid_ks_real(self):
473437 """test_apt_src_longkeyid_ks_real - Test long keyid from other ks"""
474 with mock.patch.object(cc_apt_configure, 'add_key_raw') as mockobj:438 keyid = "B59D 5F15 97A5 04B7 E230 6DCA 0620 BBCF 0368 3F77"
475 with mock.patch.object(cc_apt_configure, 'getkeybyid') as gkbi:439 cfg = {'keyid': keyid,
476 gkbi.return_value = EXPECTEDKEY440 'keyserver': 'keys.gnupg.net',
477 cc_apt_configure.add_sources([cfg], params)441 'filename': self.aptlistfile}
478442
479 mockobj.assert_called_with(EXPECTEDKEY)443 self.apt_src_keyid_real(cfg, EXPECTEDKEY)
480
481 # filename should be ignored on key only
482 self.assertFalse(os.path.isfile(self.aptlistfile))
483444
484 def test_apt_src_ppa(self):445 def test_apt_src_ppa(self):
485 """test_apt_src_ppa446 """Test adding a ppa"""
486 Test specification of a ppa
487 """
488 params = self._get_default_params()447 params = self._get_default_params()
489 cfg = {'source': 'ppa:smoser/cloud-init-test',448 cfg = {'source': 'ppa:smoser/cloud-init-test',
490 'filename': self.aptlistfile}449 'filename': self.aptlistfile}
@@ -493,7 +452,8 @@
493 matcher = re.compile(r'^[\w-]+:\w').search452 matcher = re.compile(r'^[\w-]+:\w').search
494453
495 with mock.patch.object(util, 'subp') as mockobj:454 with mock.patch.object(util, 'subp') as mockobj:
496 cc_apt_configure.add_sources([cfg], params, aa_repo_match=matcher)455 cc_apt_configure.add_apt_sources([cfg], params,
456 aa_repo_match=matcher)
497 mockobj.assert_called_once_with(['add-apt-repository',457 mockobj.assert_called_once_with(['add-apt-repository',
498 'ppa:smoser/cloud-init-test'])458 'ppa:smoser/cloud-init-test'])
499459
@@ -501,9 +461,7 @@
501 self.assertFalse(os.path.isfile(self.aptlistfile))461 self.assertFalse(os.path.isfile(self.aptlistfile))
502462
503 def test_apt_src_ppa_tri(self):463 def test_apt_src_ppa_tri(self):
504 """test_apt_src_ppa_tri464 """Test adding three ppa's"""
505 Test specification of a ppa
506 """
507 params = self._get_default_params()465 params = self._get_default_params()
508 cfg1 = {'source': 'ppa:smoser/cloud-init-test',466 cfg1 = {'source': 'ppa:smoser/cloud-init-test',
509 'filename': self.aptlistfile}467 'filename': self.aptlistfile}
@@ -516,8 +474,8 @@
516 matcher = re.compile(r'^[\w-]+:\w').search474 matcher = re.compile(r'^[\w-]+:\w').search
517475
518 with mock.patch.object(util, 'subp') as mockobj:476 with mock.patch.object(util, 'subp') as mockobj:
519 cc_apt_configure.add_sources([cfg1, cfg2, cfg3], params,477 cc_apt_configure.add_apt_sources([cfg1, cfg2, cfg3], params,
520 aa_repo_match=matcher)478 aa_repo_match=matcher)
521 calls = [call(['add-apt-repository', 'ppa:smoser/cloud-init-test']),479 calls = [call(['add-apt-repository', 'ppa:smoser/cloud-init-test']),
522 call(['add-apt-repository', 'ppa:smoser/cloud-init-test2']),480 call(['add-apt-repository', 'ppa:smoser/cloud-init-test2']),
523 call(['add-apt-repository', 'ppa:smoser/cloud-init-test3'])]481 call(['add-apt-repository', 'ppa:smoser/cloud-init-test3'])]
@@ -529,10 +487,7 @@
529 self.assertFalse(os.path.isfile(self.aptlistfile3))487 self.assertFalse(os.path.isfile(self.aptlistfile3))
530488
531 def test_convert_to_new_format(self):489 def test_convert_to_new_format(self):
532 """test_convert_to_new_format490 """Test the conversion of old to new format"""
533 Test the conversion of old to new format
534 And the noop conversion of new to new format as well
535 """
536 cfg1 = {'source': 'deb $MIRROR $RELEASE multiverse',491 cfg1 = {'source': 'deb $MIRROR $RELEASE multiverse',
537 'filename': self.aptlistfile}492 'filename': self.aptlistfile}
538 cfg2 = {'source': 'deb $MIRROR $RELEASE main',493 cfg2 = {'source': 'deb $MIRROR $RELEASE main',