Revision effc1b86
b/Makefile.am | ||
---|---|---|
483 | 483 |
lib/utils/retry.py \ |
484 | 484 |
lib/utils/storage.py \ |
485 | 485 |
lib/utils/text.py \ |
486 |
lib/utils/version.py \ |
|
486 | 487 |
lib/utils/wrapper.py \ |
487 | 488 |
lib/utils/x509.py |
488 | 489 |
|
b/lib/constants.py | ||
---|---|---|
44 | 44 |
EXPORT_VERSION = 0 |
45 | 45 |
RAPI_VERSION = 2 |
46 | 46 |
|
47 |
|
|
48 |
# Format for CONFIG_VERSION: |
|
49 |
# 01 03 0123 = 01030123 |
|
50 |
# ^^ ^^ ^^^^ |
|
51 |
# | | + Configuration version/revision |
|
52 |
# | + Minor version |
|
53 |
# + Major version |
|
54 |
# |
|
55 |
# It is stored as an integer. Make sure not to write an octal number. |
|
56 |
|
|
57 |
# BuildVersion and SplitVersion must be in here because we can't import other |
|
58 |
# modules. The cfgupgrade tool must be able to read and write version numbers |
|
59 |
# and thus requires these functions. To avoid code duplication, they're kept in |
|
60 |
# here. |
|
61 |
|
|
62 |
def BuildVersion(major, minor, revision): |
|
63 |
"""Calculates int version number from major, minor and revision numbers. |
|
64 |
|
|
65 |
Returns: int representing version number |
|
66 |
|
|
67 |
""" |
|
68 |
assert isinstance(major, int) |
|
69 |
assert isinstance(minor, int) |
|
70 |
assert isinstance(revision, int) |
|
71 |
return (1000000 * major + |
|
72 |
10000 * minor + |
|
73 |
1 * revision) |
|
74 |
|
|
75 |
|
|
76 |
def SplitVersion(version): |
|
77 |
"""Splits version number stored in an int. |
|
78 |
|
|
79 |
Returns: tuple; (major, minor, revision) |
|
80 |
|
|
81 |
""" |
|
82 |
assert isinstance(version, int) |
|
83 |
|
|
84 |
(major, remainder) = divmod(version, 1000000) |
|
85 |
(minor, revision) = divmod(remainder, 10000) |
|
86 |
|
|
87 |
return (major, minor, revision) |
|
88 |
|
|
89 |
|
|
90 | 47 |
CONFIG_MAJOR = _constants.CONFIG_MAJOR |
91 | 48 |
CONFIG_MINOR = _constants.CONFIG_MINOR |
92 | 49 |
CONFIG_REVISION = _constants.CONFIG_REVISION |
b/lib/server/masterd.py | ||
---|---|---|
61 | 61 |
from ganeti import pathutils |
62 | 62 |
from ganeti import ht |
63 | 63 |
|
64 |
from ganeti.utils import version |
|
65 |
|
|
64 | 66 |
|
65 | 67 |
CLIENT_REQUEST_WORKERS = 16 |
66 | 68 |
|
... | ... | |
90 | 92 |
client_ops = ClientOps(server) |
91 | 93 |
|
92 | 94 |
try: |
93 |
(method, args, version) = luxi.ParseRequest(message)
|
|
95 |
(method, args, ver) = luxi.ParseRequest(message) |
|
94 | 96 |
except luxi.ProtocolError, err: |
95 | 97 |
logging.error("Protocol Error: %s", err) |
96 | 98 |
client.close_log() |
... | ... | |
99 | 101 |
success = False |
100 | 102 |
try: |
101 | 103 |
# Verify client's version if there was one in the request |
102 |
if version is not None and version != constants.LUXI_VERSION:
|
|
104 |
if ver is not None and ver != constants.LUXI_VERSION:
|
|
103 | 105 |
raise errors.LuxiError("LUXI version mismatch, server %s, request %s" % |
104 |
(constants.LUXI_VERSION, version))
|
|
106 |
(constants.LUXI_VERSION, ver)) |
|
105 | 107 |
|
106 | 108 |
result = client_ops.handle_request(method, args) |
107 | 109 |
success = True |
... | ... | |
685 | 687 |
try: |
686 | 688 |
config.ConfigWriter() |
687 | 689 |
except errors.ConfigVersionMismatch, err: |
688 |
v1 = "%s.%s.%s" % constants.SplitVersion(err.args[0])
|
|
689 |
v2 = "%s.%s.%s" % constants.SplitVersion(err.args[1])
|
|
690 |
v1 = "%s.%s.%s" % version.SplitVersion(err.args[0])
|
|
691 |
v2 = "%s.%s.%s" % version.SplitVersion(err.args[1])
|
|
690 | 692 |
print >> sys.stderr, \ |
691 | 693 |
("Configuration version mismatch. The current Ganeti software" |
692 | 694 |
" expects version %s, but the on-disk configuration file has" |
b/lib/utils/version.py | ||
---|---|---|
1 |
#!/usr/bin/python |
|
2 |
# |
|
3 |
|
|
4 |
# Copyright (C) 2013 Google Inc. |
|
5 |
# |
|
6 |
# This program is free software; you can redistribute it and/or modify |
|
7 |
# it under the terms of the GNU General Public License as published by |
|
8 |
# the Free Software Foundation; either version 2 of the License, or |
|
9 |
# (at your option) any later version. |
|
10 |
# |
|
11 |
# This program is distributed in the hope that it will be useful, but |
|
12 |
# WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 |
# General Public License for more details. |
|
15 |
# |
|
16 |
# You should have received a copy of the GNU General Public License |
|
17 |
# along with this program; if not, write to the Free Software |
|
18 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
19 |
# 02110-1301, USA. |
|
20 |
|
|
21 |
|
|
22 |
"""Version utilities.""" |
|
23 |
|
|
24 |
|
|
25 |
# Format for CONFIG_VERSION: |
|
26 |
# 01 03 0123 = 01030123 |
|
27 |
# ^^ ^^ ^^^^ |
|
28 |
# | | + Configuration version/revision |
|
29 |
# | + Minor version |
|
30 |
# + Major version |
|
31 |
# |
|
32 |
# It is stored as an integer. Make sure not to write an octal number. |
|
33 |
|
|
34 |
# BuildVersion and SplitVersion must be in here because we can't import other |
|
35 |
# modules. The cfgupgrade tool must be able to read and write version numbers |
|
36 |
# and thus requires these functions. To avoid code duplication, they're kept in |
|
37 |
# here. |
|
38 |
|
|
39 |
def BuildVersion(major, minor, revision): |
|
40 |
"""Calculates int version number from major, minor and revision numbers. |
|
41 |
|
|
42 |
Returns: int representing version number |
|
43 |
|
|
44 |
""" |
|
45 |
assert isinstance(major, int) |
|
46 |
assert isinstance(minor, int) |
|
47 |
assert isinstance(revision, int) |
|
48 |
return (1000000 * major + |
|
49 |
10000 * minor + |
|
50 |
1 * revision) |
|
51 |
|
|
52 |
|
|
53 |
def SplitVersion(version): |
|
54 |
"""Splits version number stored in an int. |
|
55 |
|
|
56 |
Returns: tuple; (major, minor, revision) |
|
57 |
|
|
58 |
""" |
|
59 |
assert isinstance(version, int) |
|
60 |
|
|
61 |
(major, remainder) = divmod(version, 1000000) |
|
62 |
(minor, revision) = divmod(remainder, 10000) |
|
63 |
|
|
64 |
return (major, minor, revision) |
b/test/py/cfgupgrade_unittest.py | ||
---|---|---|
34 | 34 |
from ganeti import serializer |
35 | 35 |
from ganeti import netutils |
36 | 36 |
|
37 |
from ganeti.utils import version |
|
38 |
|
|
37 | 39 |
import testutils |
38 | 40 |
|
39 | 41 |
|
... | ... | |
199 | 201 |
self.assertFalse(os.path.exists(os.path.dirname(self.rapi_users_path))) |
200 | 202 |
|
201 | 203 |
utils.WriteFile(self.rapi_users_path_pre24, data="some user\n") |
202 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), False)
|
|
204 |
self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), False)
|
|
203 | 205 |
|
204 | 206 |
self.assertTrue(os.path.isdir(os.path.dirname(self.rapi_users_path))) |
205 | 207 |
self.assert_(os.path.islink(self.rapi_users_path_pre24)) |
... | ... | |
215 | 217 |
|
216 | 218 |
os.mkdir(os.path.dirname(self.rapi_users_path)) |
217 | 219 |
utils.WriteFile(self.rapi_users_path, data="other user\n") |
218 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), False)
|
|
220 |
self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), False)
|
|
219 | 221 |
|
220 | 222 |
self.assert_(os.path.islink(self.rapi_users_path_pre24)) |
221 | 223 |
self.assert_(os.path.isfile(self.rapi_users_path)) |
... | ... | |
232 | 234 |
os.symlink(self.rapi_users_path, self.rapi_users_path_pre24) |
233 | 235 |
utils.WriteFile(self.rapi_users_path, data="hello world\n") |
234 | 236 |
|
235 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), False)
|
|
237 |
self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), False)
|
|
236 | 238 |
|
237 | 239 |
self.assert_(os.path.isfile(self.rapi_users_path) and |
238 | 240 |
not os.path.islink(self.rapi_users_path)) |
... | ... | |
251 | 253 |
utils.WriteFile(self.rapi_users_path_pre24, data="hello world\n") |
252 | 254 |
|
253 | 255 |
self.assertRaises(Exception, self._TestSimpleUpgrade, |
254 |
constants.BuildVersion(2, 2, 0), False)
|
|
256 |
version.BuildVersion(2, 2, 0), False)
|
|
255 | 257 |
|
256 | 258 |
for path in [self.rapi_users_path, self.rapi_users_path_pre24]: |
257 | 259 |
self.assert_(os.path.isfile(path) and not os.path.islink(path)) |
... | ... | |
264 | 266 |
self.assertFalse(os.path.exists(self.rapi_users_path_pre24)) |
265 | 267 |
|
266 | 268 |
utils.WriteFile(self.rapi_users_path_pre24, data="some user\n") |
267 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
|
|
269 |
self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), True)
|
|
268 | 270 |
|
269 | 271 |
self.assertFalse(os.path.isdir(os.path.dirname(self.rapi_users_path))) |
270 | 272 |
self.assertTrue(os.path.isfile(self.rapi_users_path_pre24) and |
... | ... | |
277 | 279 |
|
278 | 280 |
os.mkdir(os.path.dirname(self.rapi_users_path)) |
279 | 281 |
utils.WriteFile(self.rapi_users_path, data="other user\n") |
280 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
|
|
282 |
self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), True)
|
|
281 | 283 |
|
282 | 284 |
self.assertTrue(os.path.isfile(self.rapi_users_path) and |
283 | 285 |
not os.path.islink(self.rapi_users_path)) |
... | ... | |
292 | 294 |
os.symlink(self.rapi_users_path, self.rapi_users_path_pre24) |
293 | 295 |
utils.WriteFile(self.rapi_users_path, data="hello world\n") |
294 | 296 |
|
295 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), True)
|
|
297 |
self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), True)
|
|
296 | 298 |
|
297 | 299 |
self.assertTrue(os.path.islink(self.rapi_users_path_pre24)) |
298 | 300 |
self.assertTrue(os.path.isfile(self.rapi_users_path) and |
... | ... | |
305 | 307 |
def testFileStoragePathsDryRun(self): |
306 | 308 |
self.assertFalse(os.path.exists(self.file_storage_paths)) |
307 | 309 |
|
308 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), True,
|
|
310 |
self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), True,
|
|
309 | 311 |
file_storage_dir=self.tmpdir, |
310 | 312 |
shared_file_storage_dir="/tmp") |
311 | 313 |
|
... | ... | |
314 | 316 |
def testFileStoragePathsBoth(self): |
315 | 317 |
self.assertFalse(os.path.exists(self.file_storage_paths)) |
316 | 318 |
|
317 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), False,
|
|
319 |
self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), False,
|
|
318 | 320 |
file_storage_dir=self.tmpdir, |
319 | 321 |
shared_file_storage_dir="/tmp") |
320 | 322 |
|
... | ... | |
330 | 332 |
def testFileStoragePathsSharedOnly(self): |
331 | 333 |
self.assertFalse(os.path.exists(self.file_storage_paths)) |
332 | 334 |
|
333 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), False,
|
|
335 |
self._TestSimpleUpgrade(version.BuildVersion(2, 5, 0), False,
|
|
334 | 336 |
file_storage_dir=None, |
335 | 337 |
shared_file_storage_dir=self.tmpdir) |
336 | 338 |
|
... | ... | |
341 | 343 |
self.assertFalse(lines) |
342 | 344 |
|
343 | 345 |
def testUpgradeFrom_2_0(self): |
344 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 0, 0), False)
|
|
346 |
self._TestSimpleUpgrade(version.BuildVersion(2, 0, 0), False)
|
|
345 | 347 |
|
346 | 348 |
def testUpgradeFrom_2_1(self): |
347 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 1, 0), False)
|
|
349 |
self._TestSimpleUpgrade(version.BuildVersion(2, 1, 0), False)
|
|
348 | 350 |
|
349 | 351 |
def testUpgradeFrom_2_2(self): |
350 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), False)
|
|
352 |
self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), False)
|
|
351 | 353 |
|
352 | 354 |
def testUpgradeFrom_2_3(self): |
353 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), False)
|
|
355 |
self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), False)
|
|
354 | 356 |
|
355 | 357 |
def testUpgradeFrom_2_4(self): |
356 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 4, 0), False)
|
|
358 |
self._TestSimpleUpgrade(version.BuildVersion(2, 4, 0), False)
|
|
357 | 359 |
|
358 | 360 |
def testUpgradeFrom_2_5(self): |
359 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), False)
|
|
361 |
self._TestSimpleUpgrade(version.BuildVersion(2, 5, 0), False)
|
|
360 | 362 |
|
361 | 363 |
def testUpgradeFrom_2_6(self): |
362 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), False)
|
|
364 |
self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), False)
|
|
363 | 365 |
|
364 | 366 |
def testUpgradeFrom_2_7(self): |
365 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 7, 0), False)
|
|
367 |
self._TestSimpleUpgrade(version.BuildVersion(2, 7, 0), False)
|
|
366 | 368 |
|
367 | 369 |
def testUpgradeFullConfigFrom_2_7(self): |
368 | 370 |
self._TestUpgradeFromFile("cluster_config_2.7.json", False) |
... | ... | |
431 | 433 |
self._RunDowngradeTwice() |
432 | 434 |
|
433 | 435 |
def testUpgradeDryRunFrom_2_0(self): |
434 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 0, 0), True)
|
|
436 |
self._TestSimpleUpgrade(version.BuildVersion(2, 0, 0), True)
|
|
435 | 437 |
|
436 | 438 |
def testUpgradeDryRunFrom_2_1(self): |
437 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 1, 0), True)
|
|
439 |
self._TestSimpleUpgrade(version.BuildVersion(2, 1, 0), True)
|
|
438 | 440 |
|
439 | 441 |
def testUpgradeDryRunFrom_2_2(self): |
440 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), True)
|
|
442 |
self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), True)
|
|
441 | 443 |
|
442 | 444 |
def testUpgradeDryRunFrom_2_3(self): |
443 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
|
|
445 |
self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), True)
|
|
444 | 446 |
|
445 | 447 |
def testUpgradeDryRunFrom_2_4(self): |
446 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 4, 0), True)
|
|
448 |
self._TestSimpleUpgrade(version.BuildVersion(2, 4, 0), True)
|
|
447 | 449 |
|
448 | 450 |
def testUpgradeDryRunFrom_2_5(self): |
449 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), True)
|
|
451 |
self._TestSimpleUpgrade(version.BuildVersion(2, 5, 0), True)
|
|
450 | 452 |
|
451 | 453 |
def testUpgradeDryRunFrom_2_6(self): |
452 |
self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), True)
|
|
454 |
self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), True)
|
|
453 | 455 |
|
454 | 456 |
def testUpgradeCurrentDryRun(self): |
455 | 457 |
self._TestSimpleUpgrade(constants.CONFIG_VERSION, True) |
b/test/py/ganeti.constants_unittest.py | ||
---|---|---|
30 | 30 |
from ganeti import locking |
31 | 31 |
from ganeti import utils |
32 | 32 |
|
33 |
from ganeti.utils import version |
|
34 |
|
|
33 | 35 |
import testutils |
34 | 36 |
|
35 | 37 |
|
... | ... | |
46 | 48 |
self.failUnless(constants.CONFIG_VERSION >= 0 and |
47 | 49 |
constants.CONFIG_VERSION <= 99999999) |
48 | 50 |
|
49 |
self.failUnless(constants.BuildVersion(0, 0, 0) == 0)
|
|
50 |
self.failUnless(constants.BuildVersion(10, 10, 1010) == 10101010)
|
|
51 |
self.failUnless(constants.BuildVersion(12, 34, 5678) == 12345678)
|
|
52 |
self.failUnless(constants.BuildVersion(99, 99, 9999) == 99999999)
|
|
51 |
self.failUnless(version.BuildVersion(0, 0, 0) == 0)
|
|
52 |
self.failUnless(version.BuildVersion(10, 10, 1010) == 10101010)
|
|
53 |
self.failUnless(version.BuildVersion(12, 34, 5678) == 12345678)
|
|
54 |
self.failUnless(version.BuildVersion(99, 99, 9999) == 99999999)
|
|
53 | 55 |
|
54 |
self.failUnless(constants.SplitVersion(00000000) == (0, 0, 0))
|
|
55 |
self.failUnless(constants.SplitVersion(10101010) == (10, 10, 1010))
|
|
56 |
self.failUnless(constants.SplitVersion(12345678) == (12, 34, 5678))
|
|
57 |
self.failUnless(constants.SplitVersion(99999999) == (99, 99, 9999))
|
|
58 |
self.failUnless(constants.SplitVersion(constants.CONFIG_VERSION) ==
|
|
56 |
self.failUnless(version.SplitVersion(00000000) == (0, 0, 0))
|
|
57 |
self.failUnless(version.SplitVersion(10101010) == (10, 10, 1010))
|
|
58 |
self.failUnless(version.SplitVersion(12345678) == (12, 34, 5678))
|
|
59 |
self.failUnless(version.SplitVersion(99999999) == (99, 99, 9999))
|
|
60 |
self.failUnless(version.SplitVersion(constants.CONFIG_VERSION) ==
|
|
59 | 61 |
(constants.CONFIG_MAJOR, constants.CONFIG_MINOR, |
60 | 62 |
constants.CONFIG_REVISION)) |
61 | 63 |
|
b/tools/cfgupgrade | ||
---|---|---|
44 | 44 |
from ganeti import netutils |
45 | 45 |
from ganeti import pathutils |
46 | 46 |
|
47 |
from ganeti.utils import version |
|
48 |
|
|
47 | 49 |
|
48 | 50 |
options = None |
49 | 51 |
args = None |
... | ... | |
347 | 349 |
|
348 | 350 |
|
349 | 351 |
def UpgradeAll(config_data): |
350 |
config_data["version"] = constants.BuildVersion(TARGET_MAJOR, |
|
351 |
TARGET_MINOR, 0) |
|
352 |
config_data["version"] = version.BuildVersion(TARGET_MAJOR, TARGET_MINOR, 0) |
|
352 | 353 |
UpgradeRapiUsers() |
353 | 354 |
UpgradeWatcher() |
354 | 355 |
UpgradeFileStoragePaths(config_data) |
... | ... | |
379 | 380 |
def DowngradeAll(config_data): |
380 | 381 |
# Any code specific to a particular version should be labeled that way, so |
381 | 382 |
# it can be removed when updating to the next version. |
382 |
config_data["version"] = constants.BuildVersion(DOWNGRADE_MAJOR,
|
|
383 |
DOWNGRADE_MINOR, 0)
|
|
383 |
config_data["version"] = version.BuildVersion(DOWNGRADE_MAJOR,
|
|
384 |
DOWNGRADE_MINOR, 0) |
|
384 | 385 |
DowngradeInstances(config_data) |
385 | 386 |
|
386 | 387 |
|
... | ... | |
482 | 483 |
raise Error("Unable to determine configuration version") |
483 | 484 |
|
484 | 485 |
(config_major, config_minor, config_revision) = \ |
485 |
constants.SplitVersion(config_version)
|
|
486 |
version.SplitVersion(config_version)
|
|
486 | 487 |
|
487 | 488 |
logging.info("Found configuration version %s (%d.%d.%d)", |
488 | 489 |
config_version, config_major, config_minor, config_revision) |
b/tools/cfgupgrade12 | ||
---|---|---|
49 | 49 |
from ganeti import cli |
50 | 50 |
from ganeti import pathutils |
51 | 51 |
|
52 |
from ganeti.utils import version |
|
53 |
|
|
52 | 54 |
|
53 | 55 |
options = None |
54 | 56 |
args = None |
... | ... | |
345 | 347 |
raise Error("Unsupported configuration version: %s" % |
346 | 348 |
old_config_version) |
347 | 349 |
if "version" not in config_data: |
348 |
config_data["version"] = constants.BuildVersion(2, 0, 0)
|
|
350 |
config_data["version"] = version.BuildVersion(2, 0, 0)
|
|
349 | 351 |
if F_SERIAL not in config_data: |
350 | 352 |
config_data[F_SERIAL] = 1 |
351 | 353 |
|
Also available in: Unified diff