Merge ~mpontillo/maas:rack-version-utils into maas:master
- Git
- lp:~mpontillo/maas
- rack-version-utils
- Merge into master
Proposed by
Mike Pontillo
Status: | Merged |
---|---|
Approved by: | Mike Pontillo |
Approved revision: | f660088482f7947bda6654935deb03c382b7f5df |
Merge reported by: | MAAS Lander |
Merged at revision: | not available |
Proposed branch: | ~mpontillo/maas:rack-version-utils |
Merge into: | maas:master |
Diff against target: |
1137 lines (+461/-159) 17 files modified
dev/null (+0/-142) src/maasserver/__init__.py (+3/-1) src/maasserver/api/tests/test_version.py (+1/-1) src/maasserver/api/version.py (+1/-1) src/maasserver/bootresources.py (+4/-4) src/maasserver/bootsources.py (+1/-1) src/maasserver/context_processors.py (+1/-1) src/maasserver/tests/test_bootresources.py (+1/-1) src/maasserver/tests/test_bootsources.py (+1/-1) src/maasserver/websockets/handlers/bootresource.py (+1/-1) src/maasserver/websockets/handlers/general.py (+1/-1) src/maasserver/websockets/handlers/tests/test_bootresource.py (+1/-1) src/metadataserver/builtin_scripts/__init__.py (+1/-1) src/metadataserver/builtin_scripts/tests/test_builtin_scripts.py (+1/-1) src/provisioningserver/utils/tests/test_version.py (+293/-0) src/provisioningserver/utils/version.py (+149/-0) utilities/check-imports (+1/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mike Pontillo (community) | Approve | ||
Newell Jensen | Pending | ||
Review via email: mp+327333@code.launchpad.net |
This proposal supersedes a proposal from 2017-07-12.
Commit message
Make version check utilities work for the rack.
This allows rack-only installations to determine their version.
Also moves code to determine MAAS version to the src/provisionin
Description of the change
To post a comment you must log in.
Revision history for this message
Newell Jensen (newell-jensen) wrote : Posted in a previous version of this proposal | # |
review:
Approve
Revision history for this message
Mike Pontillo (mpontillo) wrote : | # |
Self-approving previously approved branch. (I resubmitted to land two related branches together.)
review:
Approve
Revision history for this message
MAAS Lander (maas-lander) wrote : | # |
LANDING
-b rack-version-utils lp:~mpontillo/maas into -b master lp:~maas-committers/maas
STATUS: FAILED BUILD
LOG: http://
- f660088... by Mike Pontillo
-
Fix imports.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/maasserver/__init__.py b/src/maasserver/__init__.py |
2 | index cd6b4d6..7d85981 100644 |
3 | --- a/src/maasserver/__init__.py |
4 | +++ b/src/maasserver/__init__.py |
5 | @@ -13,8 +13,10 @@ __all__ = [ |
6 | import logging |
7 | from os import environ |
8 | |
9 | +from provisioningserver.utils import version |
10 | |
11 | -__version__ = '2.3.0' |
12 | + |
13 | +__version__ = version.DEFAULT_VERSION |
14 | |
15 | default_app_config = 'maasserver.apps.MAASConfig' |
16 | |
17 | diff --git a/src/maasserver/api/tests/test_version.py b/src/maasserver/api/tests/test_version.py |
18 | index b9204d2..defa1fb 100644 |
19 | --- a/src/maasserver/api/tests/test_version.py |
20 | +++ b/src/maasserver/api/tests/test_version.py |
21 | @@ -13,7 +13,7 @@ from django.conf import settings |
22 | from django.core.urlresolvers import reverse |
23 | from maasserver.api.version import API_CAPABILITIES_LIST |
24 | from maasserver.testing.api import APITestCase |
25 | -from maasserver.utils import version as version_module |
26 | +from provisioningserver.utils import version as version_module |
27 | |
28 | |
29 | class TestVersionAPIBasics(APITestCase.ForAnonymousAndUserAndAdmin): |
30 | diff --git a/src/maasserver/api/version.py b/src/maasserver/api/version.py |
31 | index 3fc557b..77bb317 100644 |
32 | --- a/src/maasserver/api/version.py |
33 | +++ b/src/maasserver/api/version.py |
34 | @@ -12,7 +12,7 @@ import json |
35 | |
36 | from django.http import HttpResponse |
37 | from maasserver.api.support import AnonymousOperationsHandler |
38 | -from maasserver.utils.version import get_maas_version_subversion |
39 | +from provisioningserver.utils.version import get_maas_version_subversion |
40 | |
41 | # MAAS capabilities. See docs/version.rst for documentation. |
42 | CAP_NETWORKS_MANAGEMENT = 'networks-management' |
43 | diff --git a/src/maasserver/bootresources.py b/src/maasserver/bootresources.py |
44 | index 996a6a0..fd7ede4 100644 |
45 | --- a/src/maasserver/bootresources.py |
46 | +++ b/src/maasserver/bootresources.py |
47 | @@ -77,10 +77,6 @@ from maasserver.utils.orm import ( |
48 | with_connection, |
49 | ) |
50 | from maasserver.utils.threads import deferToDatabase |
51 | -from maasserver.utils.version import ( |
52 | - get_maas_version_tuple, |
53 | - get_maas_version_user_agent, |
54 | -) |
55 | from provisioningserver.config import is_dev_environment |
56 | from provisioningserver.events import EVENT_TYPES |
57 | from provisioningserver.import_images.download_descriptions import ( |
58 | @@ -111,6 +107,10 @@ from provisioningserver.utils.twisted import ( |
59 | pause, |
60 | synchronous, |
61 | ) |
62 | +from provisioningserver.utils.version import ( |
63 | + get_maas_version_tuple, |
64 | + get_maas_version_user_agent, |
65 | +) |
66 | from simplestreams import util as sutil |
67 | from simplestreams.mirrors import ( |
68 | BasicMirrorWriter, |
69 | diff --git a/src/maasserver/bootsources.py b/src/maasserver/bootsources.py |
70 | index 999a6d8..2cd5ab2 100644 |
71 | --- a/src/maasserver/bootsources.py |
72 | +++ b/src/maasserver/bootsources.py |
73 | @@ -27,7 +27,6 @@ from maasserver.models import ( |
74 | ) |
75 | from maasserver.utils.orm import transactional |
76 | from maasserver.utils.threads import deferToDatabase |
77 | -from maasserver.utils.version import get_maas_version_user_agent |
78 | from provisioningserver.auth import get_maas_user_gpghome |
79 | from provisioningserver.config import ( |
80 | DEFAULT_IMAGES_URL, |
81 | @@ -44,6 +43,7 @@ from provisioningserver.utils.twisted import ( |
82 | asynchronous, |
83 | FOREVER, |
84 | ) |
85 | +from provisioningserver.utils.version import get_maas_version_user_agent |
86 | from requests.exceptions import ConnectionError |
87 | from twisted.internet.defer import inlineCallbacks |
88 | |
89 | diff --git a/src/maasserver/context_processors.py b/src/maasserver/context_processors.py |
90 | index da8e817..697ec15 100644 |
91 | --- a/src/maasserver/context_processors.py |
92 | +++ b/src/maasserver/context_processors.py |
93 | @@ -11,7 +11,7 @@ __all__ = [ |
94 | from django.conf import settings |
95 | from maasserver.config import RegionConfiguration |
96 | from maasserver.models import Config |
97 | -from maasserver.utils.version import ( |
98 | +from provisioningserver.utils.version import ( |
99 | get_maas_doc_version, |
100 | get_maas_version_ui, |
101 | ) |
102 | diff --git a/src/maasserver/tests/test_bootresources.py b/src/maasserver/tests/test_bootresources.py |
103 | index 135715b..b3fd049 100644 |
104 | --- a/src/maasserver/tests/test_bootresources.py |
105 | +++ b/src/maasserver/tests/test_bootresources.py |
106 | @@ -92,7 +92,6 @@ from maasserver.utils.orm import ( |
107 | transactional, |
108 | ) |
109 | from maasserver.utils.threads import deferToDatabase |
110 | -from maasserver.utils.version import get_maas_version_user_agent |
111 | from maastesting.matchers import ( |
112 | MockCalledOnce, |
113 | MockCalledOnceWith, |
114 | @@ -115,6 +114,7 @@ from provisioningserver.utils.twisted import ( |
115 | asynchronous, |
116 | DeferredValue, |
117 | ) |
118 | +from provisioningserver.utils.version import get_maas_version_user_agent |
119 | from testtools.matchers import ( |
120 | Contains, |
121 | ContainsAll, |
122 | diff --git a/src/maasserver/tests/test_bootsources.py b/src/maasserver/tests/test_bootsources.py |
123 | index ecba7ce..d7f8ce8 100644 |
124 | --- a/src/maasserver/tests/test_bootsources.py |
125 | +++ b/src/maasserver/tests/test_bootsources.py |
126 | @@ -42,7 +42,6 @@ from maasserver.testing.testcase import ( |
127 | MAASTransactionServerTestCase, |
128 | ) |
129 | from maasserver.tests.test_bootresources import SimplestreamsEnvFixture |
130 | -from maasserver.utils.version import get_maas_version_user_agent |
131 | from maastesting.matchers import MockCalledOnceWith |
132 | from provisioningserver.config import DEFAULT_IMAGES_URL |
133 | from provisioningserver.import_images import ( |
134 | @@ -52,6 +51,7 @@ from provisioningserver.import_images.boot_image_mapping import ( |
135 | BootImageMapping, |
136 | ) |
137 | from provisioningserver.import_images.helpers import ImageSpec |
138 | +from provisioningserver.utils.version import get_maas_version_user_agent |
139 | from requests.exceptions import ConnectionError |
140 | from testtools.matchers import HasLength |
141 | |
142 | diff --git a/src/maasserver/utils/tests/test_version.py b/src/maasserver/utils/tests/test_version.py |
143 | deleted file mode 100644 |
144 | index 92b31dd..0000000 |
145 | --- a/src/maasserver/utils/tests/test_version.py |
146 | +++ /dev/null |
147 | @@ -1,278 +0,0 @@ |
148 | -# Copyright 2015-2016 Canonical Ltd. This software is licensed under the |
149 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
150 | - |
151 | -"""Test version utilities.""" |
152 | - |
153 | -__all__ = [] |
154 | - |
155 | -import os.path |
156 | -import random |
157 | -from unittest import skipUnless |
158 | -from unittest.mock import ( |
159 | - MagicMock, |
160 | - sentinel, |
161 | -) |
162 | - |
163 | -from maasserver import __version__ as old_version |
164 | -from maasserver.utils import version |
165 | -from maastesting import root |
166 | -from maastesting.matchers import MockCalledOnceWith |
167 | -from maastesting.testcase import MAASTestCase |
168 | -from provisioningserver.utils import ( |
169 | - shell, |
170 | - snappy, |
171 | -) |
172 | -from testtools.matchers import ( |
173 | - GreaterThan, |
174 | - Is, |
175 | - IsInstance, |
176 | -) |
177 | - |
178 | - |
179 | -class TestGetVersionFromAPT(MAASTestCase): |
180 | - |
181 | - def test__creates_cache_with_None_progress(self): |
182 | - mock_Cache = self.patch(version.apt_pkg, "Cache") |
183 | - version.get_version_from_apt(version.REGION_PACKAGE_NAME) |
184 | - self.assertThat(mock_Cache, MockCalledOnceWith(None)) |
185 | - |
186 | - def test__returns_empty_string_if_package_not_in_cache(self): |
187 | - self.patch(version.apt_pkg, "Cache") |
188 | - self.assertEqual( |
189 | - "", |
190 | - version.get_version_from_apt(version.REGION_PACKAGE_NAME)) |
191 | - |
192 | - def test__returns_empty_string_if_not_current_ver_from_package(self): |
193 | - package = MagicMock() |
194 | - package.current_ver = None |
195 | - mock_cache = { |
196 | - version.REGION_PACKAGE_NAME: package, |
197 | - } |
198 | - self.patch(version.apt_pkg, "Cache").return_value = mock_cache |
199 | - self.assertEqual( |
200 | - "", |
201 | - version.get_version_from_apt(version.REGION_PACKAGE_NAME)) |
202 | - |
203 | - def test__returns_ver_str_from_package(self): |
204 | - package = MagicMock() |
205 | - package.current_ver.ver_str = sentinel.ver_str |
206 | - mock_cache = { |
207 | - version.REGION_PACKAGE_NAME: package, |
208 | - } |
209 | - self.patch(version.apt_pkg, "Cache").return_value = mock_cache |
210 | - self.assertIs( |
211 | - sentinel.ver_str, |
212 | - version.get_version_from_apt(version.REGION_PACKAGE_NAME)) |
213 | - |
214 | - |
215 | -class TestGetMAASBranchVersion(MAASTestCase): |
216 | - |
217 | - def test__returns_None_if_this_is_not_a_branch(self): |
218 | - self.patch(version, "__file__", "/") |
219 | - self.assertIsNone(version.get_maas_branch_version()) |
220 | - |
221 | - def test__returns_None_if_bzr_crashes(self): |
222 | - call_and_check = self.patch(shell, "call_and_check") |
223 | - call_and_check.side_effect = shell.ExternalProcessError(2, "cmd") |
224 | - self.assertIsNone(version.get_maas_branch_version()) |
225 | - |
226 | - def test__returns_None_if_bzr_not_found(self): |
227 | - call_and_check = self.patch(shell, "call_and_check") |
228 | - call_and_check.side_effect = FileNotFoundError() |
229 | - self.assertIsNone(version.get_maas_branch_version()) |
230 | - |
231 | - def test__returns_None_if_bzr_emits_something_thats_not_a_number(self): |
232 | - call_and_check = self.patch(shell, "call_and_check") |
233 | - call_and_check.return_value = b"???" |
234 | - self.assertIsNone(version.get_maas_branch_version()) |
235 | - |
236 | - @skipUnless(os.path.isdir(os.path.join(root, ".bzr")), "Not a branch") |
237 | - def test__returns_revno_for_this_branch(self): |
238 | - revno = version.get_maas_branch_version() |
239 | - self.assertThat(revno, IsInstance(int)) |
240 | - self.assertThat(revno, GreaterThan(0)) |
241 | - |
242 | - |
243 | -class TestExtractVersionSubversion(MAASTestCase): |
244 | - |
245 | - scenarios = [ |
246 | - ("with ~", { |
247 | - "version": "2.2.0~beta4+bzr5856-0ubuntu1", |
248 | - "output": ("2.2.0~beta4", "bzr5856-0ubuntu1"), |
249 | - }), |
250 | - ("without ~", { |
251 | - "version": "2.1.0+bzr5480-0ubuntu1", |
252 | - "output": ("2.1.0", "bzr5480-0ubuntu1"), |
253 | - }), |
254 | - ("without ~ or +", { |
255 | - "version": "2.1.0-0ubuntu1", |
256 | - "output": ("2.1.0", "0ubuntu1"), |
257 | - }), |
258 | - ] |
259 | - |
260 | - def test__returns_version_subversion(self): |
261 | - self.assertEqual( |
262 | - self.output, version.extract_version_subversion(self.version)) |
263 | - |
264 | - |
265 | -class TestVersionTestCase(MAASTestCase): |
266 | - """MAASTestCase that resets the cache used by utility methods.""" |
267 | - |
268 | - def setUp(self): |
269 | - super(TestVersionTestCase, self).setUp() |
270 | - for attribute in vars(version).values(): |
271 | - if hasattr(attribute, "cache_clear"): |
272 | - attribute.cache_clear() |
273 | - |
274 | - |
275 | -class TestGetMAASVersion(TestVersionTestCase): |
276 | - |
277 | - def test__calls_get_version_from_apt(self): |
278 | - mock_apt = self.patch(version, "get_version_from_apt") |
279 | - mock_apt.return_value = sentinel.version |
280 | - self.expectThat( |
281 | - version.get_maas_version(), Is(sentinel.version)) |
282 | - self.expectThat( |
283 | - mock_apt, MockCalledOnceWith(version.REGION_PACKAGE_NAME)) |
284 | - |
285 | - def test__uses_snappy_get_snap_version(self): |
286 | - self.patch(snappy, 'running_in_snap').return_value = True |
287 | - self.patch(snappy, 'get_snap_version').return_value = sentinel.version |
288 | - self.assertEqual(sentinel.version, version.get_maas_version()) |
289 | - |
290 | - |
291 | -class TestGetMAASVersionSubversion(TestVersionTestCase): |
292 | - |
293 | - def test__returns_package_version(self): |
294 | - mock_apt = self.patch(version, "get_version_from_apt") |
295 | - mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1" |
296 | - self.assertEqual( |
297 | - ("1.8.0~alpha4", "bzr356-0ubuntu1"), |
298 | - version.get_maas_version_subversion()) |
299 | - |
300 | - def test__returns_unknown_if_version_is_empty_and_not_bzr_branch(self): |
301 | - mock_version = self.patch(version, "get_version_from_apt") |
302 | - mock_version.return_value = "" |
303 | - mock_branch_version = self.patch(version, "get_maas_branch_version") |
304 | - mock_branch_version.return_value = None |
305 | - self.assertEqual( |
306 | - (old_version, "unknown"), |
307 | - version.get_maas_version_subversion()) |
308 | - |
309 | - def test__returns_from_source_and_revno_from_branch(self): |
310 | - mock_version = self.patch(version, "get_version_from_apt") |
311 | - mock_version.return_value = "" |
312 | - revno = random.randint(1, 5000) |
313 | - mock_branch_version = self.patch(version, "get_maas_branch_version") |
314 | - mock_branch_version.return_value = revno |
315 | - self.assertEqual( |
316 | - ("%s from source" % old_version, "bzr%d" % revno), |
317 | - version.get_maas_version_subversion()) |
318 | - |
319 | - |
320 | -class TestGetMAASVersionUI(TestVersionTestCase): |
321 | - |
322 | - def test__returns_package_version(self): |
323 | - mock_apt = self.patch(version, "get_version_from_apt") |
324 | - mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1" |
325 | - self.assertEqual( |
326 | - "1.8.0~alpha4 (bzr356-0ubuntu1)", version.get_maas_version_ui()) |
327 | - |
328 | - def test__returns_unknown_if_version_is_empty_and_not_bzr_branch(self): |
329 | - mock_version = self.patch(version, "get_version_from_apt") |
330 | - mock_version.return_value = "" |
331 | - mock_branch_version = self.patch(version, "get_maas_branch_version") |
332 | - mock_branch_version.return_value = None |
333 | - self.assertEqual( |
334 | - "%s (unknown)" % old_version, |
335 | - version.get_maas_version_ui()) |
336 | - |
337 | - def test__returns_from_source_and_revno_from_branch(self): |
338 | - mock_version = self.patch(version, "get_version_from_apt") |
339 | - mock_version.return_value = "" |
340 | - revno = random.randint(1, 5000) |
341 | - mock_branch_version = self.patch(version, "get_maas_branch_version") |
342 | - mock_branch_version.return_value = revno |
343 | - self.assertEqual( |
344 | - "%s from source (bzr%d)" % (old_version, revno), |
345 | - version.get_maas_version_ui()) |
346 | - |
347 | - |
348 | -class TestGetMAASVersionUserAgent(TestVersionTestCase): |
349 | - |
350 | - def test__returns_package_version(self): |
351 | - mock_apt = self.patch(version, "get_version_from_apt") |
352 | - mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1" |
353 | - self.assertEqual( |
354 | - "maas/1.8.0~alpha4/bzr356-0ubuntu1", |
355 | - version.get_maas_version_user_agent()) |
356 | - |
357 | - def test__returns_unknown_if_version_is_empty_and_not_bzr_branch(self): |
358 | - mock_version = self.patch(version, "get_version_from_apt") |
359 | - mock_version.return_value = "" |
360 | - mock_branch_version = self.patch(version, "get_maas_branch_version") |
361 | - mock_branch_version.return_value = None |
362 | - self.assertEqual( |
363 | - "maas/%s/unknown" % old_version, |
364 | - version.get_maas_version_user_agent()) |
365 | - |
366 | - def test__returns_from_source_and_revno_from_branch(self): |
367 | - mock_version = self.patch(version, "get_version_from_apt") |
368 | - mock_version.return_value = "" |
369 | - revno = random.randint(1, 5000) |
370 | - mock_branch_version = self.patch(version, "get_maas_branch_version") |
371 | - mock_branch_version.return_value = revno |
372 | - self.assertEqual( |
373 | - "maas/%s from source/bzr%d" % (old_version, revno), |
374 | - version.get_maas_version_user_agent()) |
375 | - |
376 | - |
377 | -class TestGetMAASDocVersion(TestVersionTestCase): |
378 | - |
379 | - def test__returns_doc_version_with_greater_than_1_decimals(self): |
380 | - mock_apt = self.patch(version, "get_version_from_apt") |
381 | - mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1" |
382 | - self.assertEqual("1.8", version.get_maas_doc_version()) |
383 | - |
384 | - def test__returns_doc_version_with_equal_to_1_decimals(self): |
385 | - mock_apt = self.patch(version, "get_version_from_apt") |
386 | - mock_apt.return_value = "1.8~alpha4+bzr356-0ubuntu1" |
387 | - self.assertEqual("1.8", version.get_maas_doc_version()) |
388 | - |
389 | - def test__returns_empty_if_version_is_empty(self): |
390 | - mock_apt = self.patch(version, "get_version_from_apt") |
391 | - mock_apt.return_value = "" |
392 | - self.assertEqual("", version.get_maas_doc_version()) |
393 | - |
394 | - |
395 | -class TestVersionMethodsCached(TestVersionTestCase): |
396 | - |
397 | - scenarios = [ |
398 | - ("get_maas_version", dict(method="get_maas_version")), |
399 | - ("get_maas_version_subversion", dict( |
400 | - method="get_maas_version_subversion")), |
401 | - ("get_maas_version_ui", dict(method="get_maas_version_ui")), |
402 | - ("get_maas_doc_version", dict(method="get_maas_doc_version")), |
403 | - ] |
404 | - |
405 | - def test_method_is_cached(self): |
406 | - mock_apt = self.patch(version, "get_version_from_apt") |
407 | - mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1" |
408 | - cached_method = getattr(version, self.method) |
409 | - first_return_value = cached_method() |
410 | - second_return_value = cached_method() |
411 | - # The return value is not empty (full unit tests have been performed |
412 | - # earlier). |
413 | - self.assertNotIn(first_return_value, [b'', '', None]) |
414 | - self.assertEqual(first_return_value, second_return_value) |
415 | - # Apt has only been called once. |
416 | - self.expectThat( |
417 | - mock_apt, MockCalledOnceWith(version.REGION_PACKAGE_NAME)) |
418 | - |
419 | - |
420 | -class TestGetMAASVersionTuple(MAASTestCase): |
421 | - |
422 | - def test_get_maas_version_tuple(self): |
423 | - self.assertEquals( |
424 | - '.'.join([str(i) for i in version.get_maas_version_tuple()]), |
425 | - version.get_maas_version_subversion()[0]) |
426 | diff --git a/src/maasserver/utils/version.py b/src/maasserver/utils/version.py |
427 | deleted file mode 100644 |
428 | index bdd6424..0000000 |
429 | --- a/src/maasserver/utils/version.py |
430 | +++ /dev/null |
431 | @@ -1,142 +0,0 @@ |
432 | -# Copyright 2015-2016 Canonical Ltd. This software is licensed under the |
433 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
434 | - |
435 | -"""Version utilities.""" |
436 | - |
437 | -__all__ = [ |
438 | - "get_maas_doc_version", |
439 | - "get_maas_version_subversion", |
440 | - "get_maas_version_ui", |
441 | - ] |
442 | - |
443 | -from functools import lru_cache |
444 | -import re |
445 | - |
446 | -from maasserver import __version__ as old_version |
447 | -from maasserver.api.logger import maaslog |
448 | -from provisioningserver.utils import ( |
449 | - shell, |
450 | - snappy, |
451 | -) |
452 | - |
453 | -# Only import apt_pkg and initialize when not running in a snap. |
454 | -if not snappy.running_in_snap(): |
455 | - import apt_pkg |
456 | - apt_pkg.init() |
457 | - |
458 | -# Name of maas package to get version from. |
459 | -REGION_PACKAGE_NAME = "maas-region-api" |
460 | - |
461 | - |
462 | -def get_version_from_apt(package): |
463 | - """Return the version output from `apt_pkg.Cache` for the given package or |
464 | - an error message if the package data is not valid.""" |
465 | - try: |
466 | - cache = apt_pkg.Cache(None) |
467 | - except SystemError: |
468 | - maaslog.error( |
469 | - 'Installed version could not be determined. Ensure ' |
470 | - '/var/lib/dpkg/status is valid.') |
471 | - return "" |
472 | - |
473 | - version = None |
474 | - if package in cache: |
475 | - apt_package = cache[package] |
476 | - version = apt_package.current_ver |
477 | - |
478 | - return version.ver_str if version is not None else "" |
479 | - |
480 | - |
481 | -def extract_version_subversion(version): |
482 | - """Return a tuple (version, subversion) from the given apt version.""" |
483 | - main_version, subversion = re.split('[+|-]', version, 1) |
484 | - return main_version, subversion |
485 | - |
486 | - |
487 | -def get_maas_branch_version(): |
488 | - """Return the Bazaar revision for this running MAAS. |
489 | - |
490 | - :return: An integer if MAAS is running from a Bazaar working tree, else |
491 | - `None`. The revision number is only representative of the BRANCH, not |
492 | - the working tree. |
493 | - """ |
494 | - try: |
495 | - revno = shell.call_and_check(("bzr", "revno", __file__)) |
496 | - except shell.ExternalProcessError: |
497 | - # We may not be in a Bazaar working tree, or any manner of other |
498 | - # errors. For the purposes of this function we don't care; simply say |
499 | - # we don't know. |
500 | - return None |
501 | - except FileNotFoundError: |
502 | - # Bazaar is not installed. We don't care and simply say we don't know. |
503 | - return None |
504 | - else: |
505 | - # `bzr revno` can return '???' when it can't find the working tree's |
506 | - # current revision in the branch. Hopefully a fairly unlikely thing to |
507 | - # happen, but we guard against it, and other ills, here. |
508 | - try: |
509 | - return int(revno) |
510 | - except ValueError: |
511 | - return None |
512 | - |
513 | - |
514 | -@lru_cache(maxsize=1) |
515 | -def get_maas_version(): |
516 | - """Return the apt or snap version for the main MAAS package.""" |
517 | - if snappy.running_in_snap(): |
518 | - return snappy.get_snap_version() |
519 | - else: |
520 | - return get_version_from_apt(REGION_PACKAGE_NAME) |
521 | - |
522 | - |
523 | -@lru_cache(maxsize=1) |
524 | -def get_maas_version_subversion(): |
525 | - """Return a tuple with the MAAS version and the MAAS subversion.""" |
526 | - version = get_maas_version() |
527 | - if version: |
528 | - return extract_version_subversion(version) |
529 | - else: |
530 | - # Get the branch information |
531 | - branch_version = get_maas_branch_version() |
532 | - if branch_version is None: |
533 | - # Not installed not in branch, then no way to identify. This should |
534 | - # not happen, but just in case. |
535 | - return old_version, "unknown" |
536 | - else: |
537 | - return "%s from source" % old_version, "bzr%d" % branch_version |
538 | - |
539 | - |
540 | -@lru_cache(maxsize=1) |
541 | -def get_maas_version_ui(): |
542 | - """Return the version string for the running MAAS region. |
543 | - |
544 | - The returned string is suitable to display in the UI. |
545 | - """ |
546 | - version, subversion = get_maas_version_subversion() |
547 | - return "%s (%s)" % (version, subversion) if subversion else version |
548 | - |
549 | - |
550 | -@lru_cache(maxsize=1) |
551 | -def get_maas_version_user_agent(): |
552 | - """Return the version string for the running MAAS region. |
553 | - |
554 | - The returned string is suitable to set the user agent. |
555 | - """ |
556 | - version, subversion = get_maas_version_subversion() |
557 | - return "maas/%s/%s" % (version, subversion) |
558 | - |
559 | - |
560 | -@lru_cache(maxsize=1) |
561 | -def get_maas_doc_version(): |
562 | - """Return the doc version for the running MAAS region.""" |
563 | - apt_version = get_maas_version() |
564 | - if apt_version: |
565 | - version, _ = extract_version_subversion(apt_version) |
566 | - return '.'.join(version.split('~')[0].split('.')[:2]) |
567 | - else: |
568 | - return '' |
569 | - |
570 | - |
571 | -def get_maas_version_tuple(): |
572 | - """Returns a tuple of the MAAS version without the svn rev.""" |
573 | - return tuple(int(x) for x in old_version.split('.')) |
574 | diff --git a/src/maasserver/websockets/handlers/bootresource.py b/src/maasserver/websockets/handlers/bootresource.py |
575 | index 1df2ecd..68742d9 100644 |
576 | --- a/src/maasserver/websockets/handlers/bootresource.py |
577 | +++ b/src/maasserver/websockets/handlers/bootresource.py |
578 | @@ -43,7 +43,6 @@ from maasserver.models import ( |
579 | from maasserver.utils.converters import human_readable_bytes |
580 | from maasserver.utils.orm import transactional |
581 | from maasserver.utils.threads import deferToDatabase |
582 | -from maasserver.utils.version import get_maas_version_user_agent |
583 | from maasserver.websockets.base import ( |
584 | Handler, |
585 | HandlerError, |
586 | @@ -65,6 +64,7 @@ from provisioningserver.utils.twisted import ( |
587 | callOut, |
588 | FOREVER, |
589 | ) |
590 | +from provisioningserver.utils.version import get_maas_version_user_agent |
591 | from twisted.internet.defer import Deferred |
592 | |
593 | |
594 | diff --git a/src/maasserver/websockets/handlers/general.py b/src/maasserver/websockets/handlers/general.py |
595 | index b15300a..e5df4f0 100644 |
596 | --- a/src/maasserver/websockets/handlers/general.py |
597 | +++ b/src/maasserver/websockets/handlers/general.py |
598 | @@ -33,9 +33,9 @@ from maasserver.utils.osystems import ( |
599 | list_osystem_choices, |
600 | list_release_choices, |
601 | ) |
602 | -from maasserver.utils.version import get_maas_version_ui |
603 | from maasserver.websockets.base import Handler |
604 | import petname |
605 | +from provisioningserver.utils.version import get_maas_version_ui |
606 | |
607 | |
608 | class GeneralHandler(Handler): |
609 | diff --git a/src/maasserver/websockets/handlers/tests/test_bootresource.py b/src/maasserver/websockets/handlers/tests/test_bootresource.py |
610 | index 57940a7..87438ea 100644 |
611 | --- a/src/maasserver/websockets/handlers/tests/test_bootresource.py |
612 | +++ b/src/maasserver/websockets/handlers/tests/test_bootresource.py |
613 | @@ -32,7 +32,6 @@ from maasserver.utils.orm import ( |
614 | get_one, |
615 | reload_object, |
616 | ) |
617 | -from maasserver.utils.version import get_maas_version_user_agent |
618 | from maasserver.websockets.base import ( |
619 | HandlerError, |
620 | HandlerValidationError, |
621 | @@ -54,6 +53,7 @@ from provisioningserver.import_images.testing.factory import ( |
622 | make_image_spec, |
623 | set_resource, |
624 | ) |
625 | +from provisioningserver.utils.version import get_maas_version_user_agent |
626 | from testtools.matchers import ( |
627 | ContainsAll, |
628 | HasLength, |
629 | diff --git a/src/metadataserver/builtin_scripts/__init__.py b/src/metadataserver/builtin_scripts/__init__.py |
630 | index 934a3a1..8cff96f 100644 |
631 | --- a/src/metadataserver/builtin_scripts/__init__.py |
632 | +++ b/src/metadataserver/builtin_scripts/__init__.py |
633 | @@ -15,10 +15,10 @@ from attr.validators import ( |
634 | instance_of, |
635 | optional, |
636 | ) |
637 | -from maasserver.utils.version import get_maas_version |
638 | from metadataserver.enum import SCRIPT_TYPE |
639 | from metadataserver.models import Script |
640 | from provisioningserver.utils.fs import read_text_file |
641 | +from provisioningserver.utils.version import get_maas_version |
642 | from zope.interface import ( |
643 | Attribute, |
644 | implementer, |
645 | diff --git a/src/metadataserver/builtin_scripts/tests/test_builtin_scripts.py b/src/metadataserver/builtin_scripts/tests/test_builtin_scripts.py |
646 | index 004560b..703ba94 100644 |
647 | --- a/src/metadataserver/builtin_scripts/tests/test_builtin_scripts.py |
648 | +++ b/src/metadataserver/builtin_scripts/tests/test_builtin_scripts.py |
649 | @@ -11,13 +11,13 @@ from maasserver.models import VersionedTextFile |
650 | from maasserver.testing.factory import factory |
651 | from maasserver.testing.testcase import MAASServerTestCase |
652 | from maasserver.utils.orm import reload_object |
653 | -from maasserver.utils.version import get_maas_version |
654 | from metadataserver.builtin_scripts import ( |
655 | BUILTIN_SCRIPTS, |
656 | load_builtin_scripts, |
657 | ) |
658 | from metadataserver.enum import SCRIPT_TYPE_CHOICES |
659 | from metadataserver.models import Script |
660 | +from provisioningserver.utils.version import get_maas_version |
661 | |
662 | |
663 | class TestBuiltinScripts(MAASServerTestCase): |
664 | diff --git a/src/provisioningserver/utils/tests/test_version.py b/src/provisioningserver/utils/tests/test_version.py |
665 | new file mode 100644 |
666 | index 0000000..410369d |
667 | --- /dev/null |
668 | +++ b/src/provisioningserver/utils/tests/test_version.py |
669 | @@ -0,0 +1,293 @@ |
670 | +# Copyright 2015-2017 Canonical Ltd. This software is licensed under the |
671 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
672 | + |
673 | +"""Test version utilities.""" |
674 | + |
675 | +__all__ = [] |
676 | + |
677 | + |
678 | +import os.path |
679 | +import random |
680 | +from unittest import skipUnless |
681 | +from unittest.mock import ( |
682 | + MagicMock, |
683 | + sentinel, |
684 | +) |
685 | + |
686 | +from maastesting import root |
687 | +from maastesting.matchers import MockCalledOnceWith |
688 | +from maastesting.testcase import MAASTestCase |
689 | +from provisioningserver.utils import ( |
690 | + shell, |
691 | + snappy, |
692 | + version, |
693 | +) |
694 | +from provisioningserver.utils.version import DEFAULT_VERSION as old_version |
695 | +from testtools.matchers import ( |
696 | + GreaterThan, |
697 | + Is, |
698 | + IsInstance, |
699 | +) |
700 | + |
701 | + |
702 | +class TestGetVersionFromAPT(MAASTestCase): |
703 | + |
704 | + def test__creates_cache_with_None_progress(self): |
705 | + mock_Cache = self.patch(version.apt_pkg, "Cache") |
706 | + version.get_version_from_apt(version.REGION_PACKAGE_NAME) |
707 | + self.assertThat(mock_Cache, MockCalledOnceWith(None)) |
708 | + |
709 | + def test__returns_empty_string_if_package_not_in_cache(self): |
710 | + self.patch(version.apt_pkg, "Cache") |
711 | + self.assertEqual( |
712 | + "", |
713 | + version.get_version_from_apt(version.REGION_PACKAGE_NAME)) |
714 | + |
715 | + def test__returns_empty_string_if_not_current_ver_from_package(self): |
716 | + package = MagicMock() |
717 | + package.current_ver = None |
718 | + mock_cache = { |
719 | + version.REGION_PACKAGE_NAME: package, |
720 | + } |
721 | + self.patch(version.apt_pkg, "Cache").return_value = mock_cache |
722 | + self.assertEqual( |
723 | + "", |
724 | + version.get_version_from_apt(version.REGION_PACKAGE_NAME)) |
725 | + |
726 | + def test__returns_ver_str_from_package(self): |
727 | + package = MagicMock() |
728 | + package.current_ver.ver_str = sentinel.ver_str |
729 | + mock_cache = { |
730 | + version.RACK_PACKAGE_NAME: package |
731 | + } |
732 | + self.patch(version.apt_pkg, "Cache").return_value = mock_cache |
733 | + self.assertIs( |
734 | + sentinel.ver_str, |
735 | + version.get_version_from_apt(version.RACK_PACKAGE_NAME)) |
736 | + |
737 | + def test__returns_ver_str_from_second_package_if_first_not_found(self): |
738 | + package = MagicMock() |
739 | + package.current_ver.ver_str = sentinel.ver_str |
740 | + mock_cache = { |
741 | + version.REGION_PACKAGE_NAME: package, |
742 | + } |
743 | + self.patch(version.apt_pkg, "Cache").return_value = mock_cache |
744 | + self.assertIs( |
745 | + sentinel.ver_str, |
746 | + version.get_version_from_apt( |
747 | + version.RACK_PACKAGE_NAME, version.REGION_PACKAGE_NAME)) |
748 | + |
749 | + |
750 | +class TestGetMAASBranchVersion(MAASTestCase): |
751 | + |
752 | + def test__returns_None_if_this_is_not_a_branch(self): |
753 | + self.patch(version, "__file__", "/") |
754 | + self.assertIsNone(version.get_maas_branch_version()) |
755 | + |
756 | + def test__returns_None_if_bzr_crashes(self): |
757 | + call_and_check = self.patch(shell, "call_and_check") |
758 | + call_and_check.side_effect = shell.ExternalProcessError(2, "cmd") |
759 | + self.assertIsNone(version.get_maas_branch_version()) |
760 | + |
761 | + def test__returns_None_if_bzr_not_found(self): |
762 | + call_and_check = self.patch(shell, "call_and_check") |
763 | + call_and_check.side_effect = FileNotFoundError() |
764 | + self.assertIsNone(version.get_maas_branch_version()) |
765 | + |
766 | + def test__returns_None_if_bzr_emits_something_thats_not_a_number(self): |
767 | + call_and_check = self.patch(shell, "call_and_check") |
768 | + call_and_check.return_value = b"???" |
769 | + self.assertIsNone(version.get_maas_branch_version()) |
770 | + |
771 | + @skipUnless(os.path.isdir(os.path.join(root, ".bzr")), "Not a branch") |
772 | + def test__returns_revno_for_this_branch(self): |
773 | + revno = version.get_maas_branch_version() |
774 | + self.assertThat(revno, IsInstance(int)) |
775 | + self.assertThat(revno, GreaterThan(0)) |
776 | + |
777 | + |
778 | +class TestExtractVersionSubversion(MAASTestCase): |
779 | + |
780 | + scenarios = [ |
781 | + ("with ~", { |
782 | + "version": "2.2.0~beta4+bzr5856-0ubuntu1", |
783 | + "output": ("2.2.0~beta4", "bzr5856-0ubuntu1"), |
784 | + }), |
785 | + ("without ~", { |
786 | + "version": "2.1.0+bzr5480-0ubuntu1", |
787 | + "output": ("2.1.0", "bzr5480-0ubuntu1"), |
788 | + }), |
789 | + ("without ~ or +", { |
790 | + "version": "2.1.0-0ubuntu1", |
791 | + "output": ("2.1.0", "0ubuntu1"), |
792 | + }), |
793 | + ] |
794 | + |
795 | + def test__returns_version_subversion(self): |
796 | + self.assertEqual( |
797 | + self.output, version.extract_version_subversion(self.version)) |
798 | + |
799 | + |
800 | +class TestVersionTestCase(MAASTestCase): |
801 | + """MAASTestCase that resets the cache used by utility methods.""" |
802 | + |
803 | + def setUp(self): |
804 | + super(TestVersionTestCase, self).setUp() |
805 | + for attribute in vars(version).values(): |
806 | + if hasattr(attribute, "cache_clear"): |
807 | + attribute.cache_clear() |
808 | + |
809 | + |
810 | +class TestGetMAASVersion(TestVersionTestCase): |
811 | + |
812 | + def test__calls_get_version_from_apt(self): |
813 | + mock_apt = self.patch(version, "get_version_from_apt") |
814 | + mock_apt.return_value = sentinel.version |
815 | + self.expectThat( |
816 | + version.get_maas_version(), Is(sentinel.version)) |
817 | + self.expectThat( |
818 | + mock_apt, MockCalledOnceWith( |
819 | + version.RACK_PACKAGE_NAME, version.REGION_PACKAGE_NAME)) |
820 | + |
821 | + def test__uses_snappy_get_snap_version(self): |
822 | + self.patch(snappy, 'running_in_snap').return_value = True |
823 | + self.patch(snappy, 'get_snap_version').return_value = sentinel.version |
824 | + self.assertEqual(sentinel.version, version.get_maas_version()) |
825 | + |
826 | + |
827 | +class TestGetMAASVersionSubversion(TestVersionTestCase): |
828 | + |
829 | + def test__returns_package_version(self): |
830 | + mock_apt = self.patch(version, "get_version_from_apt") |
831 | + mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1" |
832 | + self.assertEqual( |
833 | + ("1.8.0~alpha4", "bzr356-0ubuntu1"), |
834 | + version.get_maas_version_subversion()) |
835 | + |
836 | + def test__returns_unknown_if_version_is_empty_and_not_bzr_branch(self): |
837 | + mock_version = self.patch(version, "get_version_from_apt") |
838 | + mock_version.return_value = "" |
839 | + mock_branch_version = self.patch(version, "get_maas_branch_version") |
840 | + mock_branch_version.return_value = None |
841 | + self.assertEqual( |
842 | + (old_version, "unknown"), |
843 | + version.get_maas_version_subversion()) |
844 | + |
845 | + def test__returns_from_source_and_revno_from_branch(self): |
846 | + mock_version = self.patch(version, "get_version_from_apt") |
847 | + mock_version.return_value = "" |
848 | + revno = random.randint(1, 5000) |
849 | + mock_branch_version = self.patch(version, "get_maas_branch_version") |
850 | + mock_branch_version.return_value = revno |
851 | + self.assertEqual( |
852 | + ("%s from source" % old_version, "bzr%d" % revno), |
853 | + version.get_maas_version_subversion()) |
854 | + |
855 | + |
856 | +class TestGetMAASVersionUI(TestVersionTestCase): |
857 | + |
858 | + def test__returns_package_version(self): |
859 | + mock_apt = self.patch(version, "get_version_from_apt") |
860 | + mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1" |
861 | + self.assertEqual( |
862 | + "1.8.0~alpha4 (bzr356-0ubuntu1)", version.get_maas_version_ui()) |
863 | + |
864 | + def test__returns_unknown_if_version_is_empty_and_not_bzr_branch(self): |
865 | + mock_version = self.patch(version, "get_version_from_apt") |
866 | + mock_version.return_value = "" |
867 | + mock_branch_version = self.patch(version, "get_maas_branch_version") |
868 | + mock_branch_version.return_value = None |
869 | + self.assertEqual( |
870 | + "%s (unknown)" % old_version, |
871 | + version.get_maas_version_ui()) |
872 | + |
873 | + def test__returns_from_source_and_revno_from_branch(self): |
874 | + mock_version = self.patch(version, "get_version_from_apt") |
875 | + mock_version.return_value = "" |
876 | + revno = random.randint(1, 5000) |
877 | + mock_branch_version = self.patch(version, "get_maas_branch_version") |
878 | + mock_branch_version.return_value = revno |
879 | + self.assertEqual( |
880 | + "%s from source (bzr%d)" % (old_version, revno), |
881 | + version.get_maas_version_ui()) |
882 | + |
883 | + |
884 | +class TestGetMAASVersionUserAgent(TestVersionTestCase): |
885 | + |
886 | + def test__returns_package_version(self): |
887 | + mock_apt = self.patch(version, "get_version_from_apt") |
888 | + mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1" |
889 | + self.assertEqual( |
890 | + "maas/1.8.0~alpha4/bzr356-0ubuntu1", |
891 | + version.get_maas_version_user_agent()) |
892 | + |
893 | + def test__returns_unknown_if_version_is_empty_and_not_bzr_branch(self): |
894 | + mock_version = self.patch(version, "get_version_from_apt") |
895 | + mock_version.return_value = "" |
896 | + mock_branch_version = self.patch(version, "get_maas_branch_version") |
897 | + mock_branch_version.return_value = None |
898 | + self.assertEqual( |
899 | + "maas/%s/unknown" % old_version, |
900 | + version.get_maas_version_user_agent()) |
901 | + |
902 | + def test__returns_from_source_and_revno_from_branch(self): |
903 | + mock_version = self.patch(version, "get_version_from_apt") |
904 | + mock_version.return_value = "" |
905 | + revno = random.randint(1, 5000) |
906 | + mock_branch_version = self.patch(version, "get_maas_branch_version") |
907 | + mock_branch_version.return_value = revno |
908 | + self.assertEqual( |
909 | + "maas/%s from source/bzr%d" % (old_version, revno), |
910 | + version.get_maas_version_user_agent()) |
911 | + |
912 | + |
913 | +class TestGetMAASDocVersion(TestVersionTestCase): |
914 | + |
915 | + def test__returns_doc_version_with_greater_than_1_decimals(self): |
916 | + mock_apt = self.patch(version, "get_version_from_apt") |
917 | + mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1" |
918 | + self.assertEqual("1.8", version.get_maas_doc_version()) |
919 | + |
920 | + def test__returns_doc_version_with_equal_to_1_decimals(self): |
921 | + mock_apt = self.patch(version, "get_version_from_apt") |
922 | + mock_apt.return_value = "1.8~alpha4+bzr356-0ubuntu1" |
923 | + self.assertEqual("1.8", version.get_maas_doc_version()) |
924 | + |
925 | + def test__returns_empty_if_version_is_empty(self): |
926 | + mock_apt = self.patch(version, "get_version_from_apt") |
927 | + mock_apt.return_value = "" |
928 | + self.assertEqual("", version.get_maas_doc_version()) |
929 | + |
930 | + |
931 | +class TestVersionMethodsCached(TestVersionTestCase): |
932 | + |
933 | + scenarios = [ |
934 | + ("get_maas_version", dict(method="get_maas_version")), |
935 | + ("get_maas_version_subversion", dict( |
936 | + method="get_maas_version_subversion")), |
937 | + ("get_maas_version_ui", dict(method="get_maas_version_ui")), |
938 | + ("get_maas_doc_version", dict(method="get_maas_doc_version")), |
939 | + ] |
940 | + |
941 | + def test_method_is_cached(self): |
942 | + mock_apt = self.patch(version, "get_version_from_apt") |
943 | + mock_apt.return_value = "1.8.0~alpha4+bzr356-0ubuntu1" |
944 | + cached_method = getattr(version, self.method) |
945 | + first_return_value = cached_method() |
946 | + second_return_value = cached_method() |
947 | + # The return value is not empty (full unit tests have been performed |
948 | + # earlier). |
949 | + self.assertNotIn(first_return_value, [b'', '', None]) |
950 | + self.assertEqual(first_return_value, second_return_value) |
951 | + # Apt has only been called once. |
952 | + self.expectThat( |
953 | + mock_apt, MockCalledOnceWith( |
954 | + version.RACK_PACKAGE_NAME, version.REGION_PACKAGE_NAME)) |
955 | + |
956 | + |
957 | +class TestGetMAASVersionTuple(MAASTestCase): |
958 | + |
959 | + def test_get_maas_version_tuple(self): |
960 | + self.assertEquals( |
961 | + '.'.join([str(i) for i in version.get_maas_version_tuple()]), |
962 | + version.get_maas_version_subversion()[0]) |
963 | diff --git a/src/provisioningserver/utils/version.py b/src/provisioningserver/utils/version.py |
964 | new file mode 100644 |
965 | index 0000000..f372b0d |
966 | --- /dev/null |
967 | +++ b/src/provisioningserver/utils/version.py |
968 | @@ -0,0 +1,149 @@ |
969 | +# Copyright 2015-2017 Canonical Ltd. This software is licensed under the |
970 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
971 | + |
972 | +"""Version utilities.""" |
973 | + |
974 | +__all__ = [ |
975 | + "get_maas_doc_version", |
976 | + "get_maas_version_subversion", |
977 | + "get_maas_version_ui", |
978 | + ] |
979 | + |
980 | +from functools import lru_cache |
981 | +import re |
982 | + |
983 | +from provisioningserver.logger import get_maas_logger |
984 | +from provisioningserver.utils import ( |
985 | + shell, |
986 | + snappy, |
987 | +) |
988 | + |
989 | + |
990 | +maaslog = get_maas_logger('version') |
991 | + |
992 | +DEFAULT_VERSION = "2.3.0" |
993 | + |
994 | +# Only import apt_pkg and initialize when not running in a snap. |
995 | +if not snappy.running_in_snap(): |
996 | + import apt_pkg |
997 | + apt_pkg.init() |
998 | + |
999 | +# Name of maas package to get version from. |
1000 | +REGION_PACKAGE_NAME = "maas-region-api" |
1001 | +RACK_PACKAGE_NAME = "maas-rack-controller" |
1002 | + |
1003 | + |
1004 | +def get_version_from_apt(*packages): |
1005 | + """Return the version output from `apt_pkg.Cache` for the given package(s), |
1006 | + or log an error message if the package data is not valid.""" |
1007 | + try: |
1008 | + cache = apt_pkg.Cache(None) |
1009 | + except SystemError: |
1010 | + maaslog.error( |
1011 | + 'Installed version could not be determined. Ensure ' |
1012 | + '/var/lib/dpkg/status is valid.') |
1013 | + return "" |
1014 | + |
1015 | + version = None |
1016 | + for package in packages: |
1017 | + if package in cache: |
1018 | + apt_package = cache[package] |
1019 | + version = apt_package.current_ver |
1020 | + break |
1021 | + |
1022 | + return version.ver_str if version is not None else "" |
1023 | + |
1024 | + |
1025 | +def extract_version_subversion(version): |
1026 | + """Return a tuple (version, subversion) from the given apt version.""" |
1027 | + main_version, subversion = re.split('[+|-]', version, 1) |
1028 | + return main_version, subversion |
1029 | + |
1030 | + |
1031 | +def get_maas_branch_version(): |
1032 | + """Return the Bazaar revision for this running MAAS. |
1033 | + |
1034 | + :return: An integer if MAAS is running from a Bazaar working tree, else |
1035 | + `None`. The revision number is only representative of the BRANCH, not |
1036 | + the working tree. |
1037 | + """ |
1038 | + try: |
1039 | + revno = shell.call_and_check(("bzr", "revno", __file__)) |
1040 | + except shell.ExternalProcessError: |
1041 | + # We may not be in a Bazaar working tree, or any manner of other |
1042 | + # errors. For the purposes of this function we don't care; simply say |
1043 | + # we don't know. |
1044 | + return None |
1045 | + except FileNotFoundError: |
1046 | + # Bazaar is not installed. We don't care and simply say we don't know. |
1047 | + return None |
1048 | + else: |
1049 | + # `bzr revno` can return '???' when it can't find the working tree's |
1050 | + # current revision in the branch. Hopefully a fairly unlikely thing to |
1051 | + # happen, but we guard against it, and other ills, here. |
1052 | + try: |
1053 | + return int(revno) |
1054 | + except ValueError: |
1055 | + return None |
1056 | + |
1057 | + |
1058 | +@lru_cache(maxsize=1) |
1059 | +def get_maas_version(): |
1060 | + """Return the apt or snap version for the main MAAS package.""" |
1061 | + if snappy.running_in_snap(): |
1062 | + return snappy.get_snap_version() |
1063 | + else: |
1064 | + return get_version_from_apt(RACK_PACKAGE_NAME, REGION_PACKAGE_NAME) |
1065 | + |
1066 | + |
1067 | +@lru_cache(maxsize=1) |
1068 | +def get_maas_version_subversion(): |
1069 | + """Return a tuple with the MAAS version and the MAAS subversion.""" |
1070 | + version = get_maas_version() |
1071 | + if version: |
1072 | + return extract_version_subversion(version) |
1073 | + else: |
1074 | + # Get the branch information |
1075 | + branch_version = get_maas_branch_version() |
1076 | + if branch_version is None: |
1077 | + # Not installed not in branch, then no way to identify. This should |
1078 | + # not happen, but just in case. |
1079 | + return DEFAULT_VERSION, "unknown" |
1080 | + else: |
1081 | + return "%s from source" % DEFAULT_VERSION, "bzr%d" % branch_version |
1082 | + |
1083 | + |
1084 | +@lru_cache(maxsize=1) |
1085 | +def get_maas_version_ui(): |
1086 | + """Return the version string for the running MAAS region. |
1087 | + |
1088 | + The returned string is suitable to display in the UI. |
1089 | + """ |
1090 | + version, subversion = get_maas_version_subversion() |
1091 | + return "%s (%s)" % (version, subversion) if subversion else version |
1092 | + |
1093 | + |
1094 | +@lru_cache(maxsize=1) |
1095 | +def get_maas_version_user_agent(): |
1096 | + """Return the version string for the running MAAS region. |
1097 | + |
1098 | + The returned string is suitable to set the user agent. |
1099 | + """ |
1100 | + version, subversion = get_maas_version_subversion() |
1101 | + return "maas/%s/%s" % (version, subversion) |
1102 | + |
1103 | + |
1104 | +@lru_cache(maxsize=1) |
1105 | +def get_maas_doc_version(): |
1106 | + """Return the doc version for the running MAAS region.""" |
1107 | + apt_version = get_maas_version() |
1108 | + if apt_version: |
1109 | + version, _ = extract_version_subversion(apt_version) |
1110 | + return '.'.join(version.split('~')[0].split('.')[:2]) |
1111 | + else: |
1112 | + return '' |
1113 | + |
1114 | + |
1115 | +def get_maas_version_tuple(): |
1116 | + """Returns a tuple of the MAAS version without the svn rev.""" |
1117 | + return tuple(int(x) for x in DEFAULT_VERSION.split('.')) |
1118 | diff --git a/utilities/check-imports b/utilities/check-imports |
1119 | index 405ca8d..d047e70 100755 |
1120 | --- a/utilities/check-imports |
1121 | +++ b/utilities/check-imports |
1122 | @@ -195,6 +195,7 @@ RackControllerRule = Rule( |
1123 | Allow("apiclient.creds.*"), |
1124 | Allow("apiclient.maas_client.*"), |
1125 | Allow("apiclient.utils.*"), |
1126 | + Allow("apt_pkg"), |
1127 | Allow("attr|attr.**"), |
1128 | Allow("bson|bson.**"), |
1129 | Allow("crochet|crochet.**"), |
1130 | @@ -245,7 +246,6 @@ RegionControllerRule = Rule( |
1131 | Allow("apiclient.creds.*"), |
1132 | Allow("apiclient.multipart.*"), |
1133 | Allow("apiclient.utils.*"), |
1134 | - Allow("apt_pkg"), |
1135 | Allow("attr|attr.**"), |
1136 | Allow("bson"), |
1137 | Allow("convoy|convoy.**"), |
Looks good. Just one small suggestion.