Merge lp:~thedac/charm-helpers/os-snaps into lp:charm-helpers
- os-snaps
- Merge into devel
Status: | Merged |
---|---|
Merged at revision: | 763 |
Proposed branch: | lp:~thedac/charm-helpers/os-snaps |
Merge into: | lp:charm-helpers |
Diff against target: |
358 lines (+171/-11) 5 files modified
charmhelpers/contrib/openstack/context.py (+6/-0) charmhelpers/contrib/openstack/utils.py (+81/-2) charmhelpers/fetch/snap.py (+6/-0) charmhelpers/fetch/ubuntu.py (+1/-0) tests/contrib/openstack/test_openstack_utils.py (+77/-9) |
To merge this branch: | bzr merge lp:~thedac/charm-helpers/os-snaps |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alex Kavanagh | Approve | ||
Corey Bryant (community) | Approve | ||
Review via email:
|
Commit message
Description of the change
Helpers for install OpenStack snaps in OpenStack charms
- 754. By Jorge Niedbalski
-
[freyes, r=niedbalski,
ajkavanagh] Invoke apt-get only if there
missing packages. - 755. By Jorge Niedbalski
-
[freyes,
r=niedbalski, ajkavanagh] Fix for test_is_ ipv6_disabled.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
David Ames (thedac) wrote : | # |
Alex,
Thanks for your suggestions.
I wrote the unit tests first which made make the changes simpler ;)
Fixed pretty much everything you requested.
- 756. By Jorge Niedbalski
-
[niedbalski, r=freyes,
ajkavanagh] Partial fix required for LP:#1699565. - 757. By Jorge Niedbalski
-
[billy-olsen, r=niedbalski] Ensure the config_flags_parser returns an
OrderedDict. - 758. By Tim Van Steenburgh
-
v0.17.0
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Corey Bryant (corey.bryant) wrote : | # |
Hi David, I have a few comments below. I think the major thing that is messing things up now is that the current snaps aren't published to a track like they all will be in the future. I'll look into publishing them to the edge channel of the ocata track.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
David Ames (thedac) wrote : | # |
Corey,
I see your point about tracks. Do let me know when you have the snaps published to both the track and the channel and I'll get this MP ready to handle it.
- 759. By Stuart Bishop
-
[peter-
sabaini, r=stub] Helper module for bcache devices
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
David Ames (thedac) wrote : | # |
Corey,
I have responded inline on where we are at with your concerns. The next commit fixes the typos.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Corey Bryant (corey.bryant) wrote : | # |
LGTM. I think we should move ahead with what David has here. Once we get tracks enabled [1] we can land track support in charm-helpers.
[1] https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Corey Bryant (corey.bryant) : | # |
- 760. By Jorge Niedbalski
-
[freyes, r=niedbalski] Add support to change a user's password in MySQL.
- 761. By Edward Hope-Morley
-
[zhhuabj,
r=ajkavanagh] When OpenStack clouds get bigger, more messaging transactions
will happen, which will cause more load on rabbitmq server. In
order to mitigate this, polling_interval rpc_response_timeout
and report_interval values are important to adjust accordingly
to the size of OpenStack cluster.So this patch supports setting those values in neutron-api
centrally, then:1. polling_interval
neutron-
openvswitch charm gets polling_interval via it's
relations and set it in [agent] of ml2_conf.ini or
openvswitch_agent.ini( >=Mitaka) 2. rpc_response_
timeout neutron-gateway charm gets rpc_response_
timeout via it's
relations and set it in [default] of neutron.conf3. report_interval
Both neutron-openvswitch charm and neutron-gateway charm
get report_interval via it's relations and set it in
[agent] of neutron.confThus we need to modifty charm-helpers to also set those values
in NeutronAPIContext.Related-Bug: 1685788
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alex Kavanagh (ajkavanagh) wrote : | # |
Looks good. Just a single comment for food for thought in the future.
- 762. By James Page
-
Fix release name typos in CLOUD_ARCHIVE_
POCKETS - 763. By David Ames
-
[thedac, r=coreycb,tinwood] OpenStack Charm snap helpers
Preview Diff
1 | === modified file 'charmhelpers/contrib/openstack/context.py' |
2 | --- charmhelpers/contrib/openstack/context.py 2017-05-01 05:08:50 +0000 |
3 | +++ charmhelpers/contrib/openstack/context.py 2017-07-12 15:52:52 +0000 |
4 | @@ -97,6 +97,7 @@ |
5 | git_determine_usr_bin, |
6 | git_determine_python_path, |
7 | enable_memcache, |
8 | + snap_install_requested, |
9 | ) |
10 | from charmhelpers.core.unitdata import kv |
11 | |
12 | @@ -244,6 +245,11 @@ |
13 | 'database_password': rdata.get(password_setting), |
14 | 'database_type': 'mysql' |
15 | } |
16 | + # Note(coreycb): We can drop mysql+pymysql if we want when the |
17 | + # following review lands, though it seems mysql+pymysql would |
18 | + # be preferred. https://review.openstack.org/#/c/462190/ |
19 | + if snap_install_requested(): |
20 | + ctxt['database_type'] = 'mysql+pymysql' |
21 | if self.context_complete(ctxt): |
22 | db_ssl(rdata, ctxt, self.ssl_dir) |
23 | return ctxt |
24 | |
25 | === modified file 'charmhelpers/contrib/openstack/utils.py' |
26 | --- charmhelpers/contrib/openstack/utils.py 2017-06-29 22:46:34 +0000 |
27 | +++ charmhelpers/contrib/openstack/utils.py 2017-07-12 15:52:52 +0000 |
28 | @@ -51,6 +51,7 @@ |
29 | status_set, |
30 | hook_name, |
31 | application_version_set, |
32 | + cached, |
33 | ) |
34 | |
35 | from charmhelpers.core.strutils import BasicStringComparator |
36 | @@ -90,6 +91,12 @@ |
37 | GPGKeyError, |
38 | get_upstream_version |
39 | ) |
40 | + |
41 | +from charmhelpers.fetch.snap import ( |
42 | + snap_install, |
43 | + SNAP_CHANNELS, |
44 | +) |
45 | + |
46 | from charmhelpers.contrib.storage.linux.utils import is_block_device, zap_disk |
47 | from charmhelpers.contrib.storage.linux.loopback import ensure_loopback_device |
48 | from charmhelpers.contrib.openstack.exceptions import OSContextError |
49 | @@ -327,8 +334,10 @@ |
50 | return ca_rel |
51 | |
52 | # Best guess match based on deb string provided |
53 | - if src.startswith('deb') or src.startswith('ppa'): |
54 | - for k, v in six.iteritems(OPENSTACK_CODENAMES): |
55 | + if (src.startswith('deb') or |
56 | + src.startswith('ppa') or |
57 | + src.startswith('snap')): |
58 | + for v in OPENSTACK_CODENAMES.values(): |
59 | if v in src: |
60 | return v |
61 | |
62 | @@ -397,6 +406,10 @@ |
63 | |
64 | def get_os_codename_package(package, fatal=True): |
65 | '''Derive OpenStack release codename from an installed package.''' |
66 | + |
67 | + if snap_install_requested(): |
68 | + return None |
69 | + |
70 | import apt_pkg as apt |
71 | |
72 | cache = apt_cache() |
73 | @@ -610,6 +623,10 @@ |
74 | a newer version of package. |
75 | """ |
76 | |
77 | + # TODO make upgrades snap aware |
78 | + if snap_install_requested(): |
79 | + return False |
80 | + |
81 | import apt_pkg as apt |
82 | src = config('openstack-origin') |
83 | cur_vers = get_os_version_package(package) |
84 | @@ -2016,3 +2033,65 @@ |
85 | policy.update(items) |
86 | with open(filename, "w") as fd: |
87 | fd.write(json.dumps(policy, indent=4)) |
88 | + |
89 | + |
90 | +@cached |
91 | +def snap_install_requested(): |
92 | + """ Determine if installing from snaps |
93 | + |
94 | + If openstack-origin is of the form snap:channel-series-release |
95 | + and channel is in SNAPS_CHANNELS return True. |
96 | + """ |
97 | + origin = config('openstack-origin') |
98 | + if not origin.startswith('snap:'): |
99 | + return False |
100 | + |
101 | + _src = origin[5:] |
102 | + channel, series, release = _src.split('-') |
103 | + if channel.lower() in SNAP_CHANNELS: |
104 | + return True |
105 | + return False |
106 | + |
107 | + |
108 | +def get_snaps_install_info_from_origin(snaps, src, mode='classic'): |
109 | + """Generate a dictionary of snap install information from origin |
110 | + |
111 | + @param snaps: List of snaps |
112 | + @param src: String of openstack-origin or source of the form |
113 | + snap:channel-series-release |
114 | + @param mode: String classic, devmode or jailmode |
115 | + @returns: Dictionary of snaps with channels and modes |
116 | + """ |
117 | + |
118 | + if not src.startswith('snap:'): |
119 | + juju_log("Snap source is not a snap origin", 'WARN') |
120 | + return {} |
121 | + |
122 | + _src = src[5:] |
123 | + channel, series, release = _src.split('-') |
124 | + |
125 | + return {snap: {'channel': channel, 'mode': mode} |
126 | + for snap in snaps} |
127 | + |
128 | + |
129 | +def install_os_snaps(snaps): |
130 | + """Install OpenStack snaps from channel and with mode |
131 | + |
132 | + @param snaps: Dictionary of snaps with channels and modes of the form: |
133 | + {'snap_name': {'channel': 'snap_channel', |
134 | + 'mode': 'snap_mode'}} |
135 | + Where channel a snapstore channel and mode is --classic, --devmode or |
136 | + --jailmode. |
137 | + @param post_snap_install: Callback function to run after snaps have been |
138 | + installed |
139 | + """ |
140 | + |
141 | + def _ensure_flag(flag): |
142 | + if flag.startswith('--'): |
143 | + return flag |
144 | + return '--{}'.format(flag) |
145 | + |
146 | + for snap in snaps.keys(): |
147 | + snap_install(snap, |
148 | + _ensure_flag(snaps[snap]['channel']), |
149 | + _ensure_flag(snaps[snap]['mode'])) |
150 | |
151 | === modified file 'charmhelpers/fetch/snap.py' |
152 | --- charmhelpers/fetch/snap.py 2017-03-03 09:41:22 +0000 |
153 | +++ charmhelpers/fetch/snap.py 2017-07-12 15:52:52 +0000 |
154 | @@ -27,6 +27,12 @@ |
155 | SNAP_NO_LOCK = 1 # The return code for "couldn't acquire lock" in Snap (hopefully this will be improved). |
156 | SNAP_NO_LOCK_RETRY_DELAY = 10 # Wait X seconds between Snap lock checks. |
157 | SNAP_NO_LOCK_RETRY_COUNT = 30 # Retry to acquire the lock X times. |
158 | +SNAP_CHANNELS = [ |
159 | + 'edge', |
160 | + 'beta', |
161 | + 'candidate', |
162 | + 'stable', |
163 | +] |
164 | |
165 | |
166 | class CouldNotAcquireLockException(Exception): |
167 | |
168 | === modified file 'charmhelpers/fetch/ubuntu.py' |
169 | --- charmhelpers/fetch/ubuntu.py 2017-05-25 13:46:14 +0000 |
170 | +++ charmhelpers/fetch/ubuntu.py 2017-07-12 15:52:52 +0000 |
171 | @@ -364,6 +364,7 @@ |
172 | (r"^cloud:(.*)-(.*)\/staging$", _add_cloud_staging), |
173 | (r"^cloud:(.*)-(.*)$", _add_cloud_distro_check), |
174 | (r"^cloud:(.*)$", _add_cloud_pocket), |
175 | + (r"^snap:.*-(.*)-(.*)$", _add_cloud_distro_check), |
176 | ]) |
177 | if source is None: |
178 | source = '' |
179 | |
180 | === modified file 'tests/contrib/openstack/test_openstack_utils.py' |
181 | --- tests/contrib/openstack/test_openstack_utils.py 2017-04-10 17:51:42 +0000 |
182 | +++ tests/contrib/openstack/test_openstack_utils.py 2017-07-12 15:52:52 +0000 |
183 | @@ -8,6 +8,7 @@ |
184 | from mock import MagicMock, patch, call |
185 | |
186 | from charmhelpers.fetch import ubuntu as fetch |
187 | +from charmhelpers.core.hookenv import flush |
188 | import charmhelpers.contrib.openstack.utils as openstack |
189 | |
190 | import six |
191 | @@ -292,8 +293,10 @@ |
192 | def test_get_swift_codename_none(self): |
193 | self.assertEquals(openstack.get_swift_codename('1.2.3'), None) |
194 | |
195 | - def test_os_codename_from_package(self): |
196 | + @patch.object(openstack, 'snap_install_requested') |
197 | + def test_os_codename_from_package(self, mock_snap_install_requested): |
198 | """Test deriving OpenStack codename from an installed package""" |
199 | + mock_snap_install_requested.return_value = False |
200 | with patch('apt_pkg.Cache') as cache: |
201 | cache.return_value = self._apt_cache() |
202 | for pkg, vers in six.iteritems(FAKE_REPO): |
203 | @@ -305,18 +308,24 @@ |
204 | self.assertEquals(openstack.get_os_codename_package(pkg), |
205 | vers['os_release']) |
206 | |
207 | + @patch.object(openstack, 'snap_install_requested') |
208 | @patch('charmhelpers.contrib.openstack.utils.error_out') |
209 | - def test_os_codename_from_bad_package_version(self, mocked_error): |
210 | + def test_os_codename_from_bad_package_version(self, mocked_error, |
211 | + mock_snap_install_requested): |
212 | """Test deriving OpenStack codename for a poorly versioned package""" |
213 | + mock_snap_install_requested.return_value = False |
214 | with patch('apt_pkg.Cache') as cache: |
215 | cache.return_value = self._apt_cache() |
216 | openstack.get_os_codename_package('bad-version') |
217 | _e = ('Could not determine OpenStack codename for version 2200.1') |
218 | mocked_error.assert_called_with(_e) |
219 | |
220 | + @patch.object(openstack, 'snap_install_requested') |
221 | @patch('charmhelpers.contrib.openstack.utils.error_out') |
222 | - def test_os_codename_from_bad_package(self, mocked_error): |
223 | + def test_os_codename_from_bad_package(self, mocked_error, |
224 | + mock_snap_install_requested): |
225 | """Test deriving OpenStack codename from an unavailable package""" |
226 | + mock_snap_install_requested.return_value = False |
227 | with patch('apt_pkg.Cache') as cache: |
228 | cache.return_value = self._apt_cache() |
229 | try: |
230 | @@ -329,8 +338,11 @@ |
231 | 'candidate: foo' |
232 | mocked_error.assert_called_with(e) |
233 | |
234 | - def test_os_codename_from_bad_package_nonfatal(self): |
235 | + @patch.object(openstack, 'snap_install_requested') |
236 | + def test_os_codename_from_bad_package_nonfatal( |
237 | + self, mock_snap_install_requested): |
238 | """Test OpenStack codename from an unavailable package is non-fatal""" |
239 | + mock_snap_install_requested.return_value = False |
240 | with patch('apt_pkg.Cache') as cache: |
241 | cache.return_value = self._apt_cache() |
242 | self.assertEquals( |
243 | @@ -338,9 +350,12 @@ |
244 | openstack.get_os_codename_package('foo', fatal=False) |
245 | ) |
246 | |
247 | + @patch.object(openstack, 'snap_install_requested') |
248 | @patch('charmhelpers.contrib.openstack.utils.error_out') |
249 | - def test_os_codename_from_uninstalled_package(self, mock_error): |
250 | + def test_os_codename_from_uninstalled_package(self, mock_error, |
251 | + mock_snap_install_requested): |
252 | """Test OpenStack codename from an available but uninstalled pkg""" |
253 | + mock_snap_install_requested.return_value = False |
254 | with patch('apt_pkg.Cache') as cache: |
255 | cache.return_value = self._apt_cache() |
256 | try: |
257 | @@ -351,8 +366,11 @@ |
258 | 'cinder-common') |
259 | mock_error.assert_called_with(e) |
260 | |
261 | - def test_os_codename_from_uninstalled_package_nonfatal(self): |
262 | + @patch.object(openstack, 'snap_install_requested') |
263 | + def test_os_codename_from_uninstalled_package_nonfatal( |
264 | + self, mock_snap_install_requested): |
265 | """Test OpenStack codename from avail uninstalled pkg is non fatal""" |
266 | + mock_snap_install_requested.return_value = False |
267 | with patch('apt_pkg.Cache') as cache: |
268 | cache.return_value = self._apt_cache() |
269 | self.assertEquals( |
270 | @@ -360,9 +378,12 @@ |
271 | openstack.get_os_codename_package('cinder-common', fatal=False) |
272 | ) |
273 | |
274 | + @patch.object(openstack, 'snap_install_requested') |
275 | @patch('charmhelpers.contrib.openstack.utils.error_out') |
276 | - def test_os_version_from_package(self, mocked_error): |
277 | + def test_os_version_from_package(self, mocked_error, |
278 | + mock_snap_install_requested): |
279 | """Test deriving OpenStack version from an installed package""" |
280 | + mock_snap_install_requested.return_value = False |
281 | with patch('apt_pkg.Cache') as cache: |
282 | cache.return_value = self._apt_cache() |
283 | for pkg, vers in six.iteritems(FAKE_REPO): |
284 | @@ -373,9 +394,12 @@ |
285 | self.assertEquals(openstack.get_os_version_package(pkg), |
286 | vers['os_version']) |
287 | |
288 | + @patch.object(openstack, 'snap_install_requested') |
289 | @patch('charmhelpers.contrib.openstack.utils.error_out') |
290 | - def test_os_version_from_bad_package(self, mocked_error): |
291 | + def test_os_version_from_bad_package(self, mocked_error, |
292 | + mock_snap_install_requested): |
293 | """Test deriving OpenStack version from an uninstalled package""" |
294 | + mock_snap_install_requested.return_value = False |
295 | with patch('apt_pkg.Cache') as cache: |
296 | cache.return_value = self._apt_cache() |
297 | try: |
298 | @@ -388,8 +412,11 @@ |
299 | 'candidate: foo' |
300 | mocked_error.assert_called_with(e) |
301 | |
302 | - def test_os_version_from_bad_package_nonfatal(self): |
303 | + @patch.object(openstack, 'snap_install_requested') |
304 | + def test_os_version_from_bad_package_nonfatal( |
305 | + self, mock_snap_install_requested): |
306 | """Test OpenStack version from an uninstalled package is non-fatal""" |
307 | + mock_snap_install_requested.return_value = False |
308 | with patch('apt_pkg.Cache') as cache: |
309 | cache.return_value = self._apt_cache() |
310 | self.assertEquals( |
311 | @@ -1886,6 +1913,47 @@ |
312 | openstack.os_application_version_set('cinder-common') |
313 | mock_application_version_set.assert_called_with('mitaka') |
314 | |
315 | + @patch('charmhelpers.contrib.openstack.utils.config') |
316 | + def test_snap_install_requested(self, config): |
317 | + # Expect True |
318 | + flush('snap_install_requested') |
319 | + config.return_value = 'snap:edge-xenial-ocata' |
320 | + self.assertTrue(openstack.snap_install_requested()) |
321 | + flush('snap_install_requested') |
322 | + config.return_value = 'snap:BETA-xenial-ocata' |
323 | + self.assertTrue(openstack.snap_install_requested()) |
324 | + # Expect False |
325 | + flush('snap_install_requested') |
326 | + config.return_value = 'snap:None-xenial-ocata' |
327 | + self.assertFalse(openstack.snap_install_requested()) |
328 | + flush('snap_install_requested') |
329 | + config.return_value = 'cloud:xenial-ocata' |
330 | + self.assertFalse(openstack.snap_install_requested()) |
331 | + |
332 | + def test_get_snaps_install_info_from_origin(self): |
333 | + snaps = ['os_project'] |
334 | + mode = 'jailmode' |
335 | + src = 'snap:beta-xenial-ocata' |
336 | + expected = {snaps[0]: {'mode': mode, |
337 | + 'channel': 'beta'}} |
338 | + self.assertEqual( |
339 | + expected, |
340 | + openstack.get_snaps_install_info_from_origin(snaps, src, |
341 | + mode=mode)) |
342 | + |
343 | + @patch.object(openstack, 'snap_install') |
344 | + def test_install_os_snaps(self, mock_snap_install): |
345 | + snaps = ['os_project'] |
346 | + mode = 'jailmode' |
347 | + src = 'snap:beta-xenial-ocata' |
348 | + post_install = MagicMock() |
349 | + |
350 | + openstack.install_os_snaps( |
351 | + openstack.get_snaps_install_info_from_origin( |
352 | + snaps, src, mode=mode)) |
353 | + mock_snap_install.assert_called_with( |
354 | + 'os_project', '--beta', '--jailmode') |
355 | + |
356 | |
357 | if __name__ == '__main__': |
358 | unittest.main() |
Please see inline comments.
Also, are there no tests for the new functions? I see patches to some of the existing tests for patching out the snaps existence test, but not for the new functions.
(I picked 'needs information' rather than 'needs fixing' because I'm not sure about the design aspect of passing in the post_snap function).