Statistics
| Branch: | Tag: | Revision:

root / test / py / cfgupgrade_unittest.py @ effc1b86

History | View | Annotate | Download (17.1 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2010, 2012, 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
"""Script for testing tools/cfgupgrade"""
23

    
24
import os
25
import sys
26
import unittest
27
import shutil
28
import tempfile
29
import operator
30

    
31
from ganeti import constants
32
from ganeti import utils
33
from ganeti import errors
34
from ganeti import serializer
35
from ganeti import netutils
36

    
37
from ganeti.utils import version
38

    
39
import testutils
40

    
41

    
42
def GetMinimalConfig():
43
  return {
44
    "version": constants.CONFIG_VERSION,
45
    "cluster": {
46
      "master_node": "node1-uuid",
47
      "ipolicy": None
48
    },
49
    "instances": {},
50
    "networks": {},
51
    "nodegroups": {},
52
    "nodes": {
53
      "node1-uuid": {
54
        "name": "node1",
55
        "uuid": "node1-uuid"
56
      }
57
    },
58
  }
59

    
60

    
61
def _RunUpgrade(path, dry_run, no_verify, ignore_hostname=True,
62
                downgrade=False):
63
  cmd = [sys.executable, "%s/tools/cfgupgrade" % testutils.GetSourceDir(),
64
         "--debug", "--force", "--path=%s" % path, "--confdir=%s" % path]
65

    
66
  if ignore_hostname:
67
    cmd.append("--ignore-hostname")
68
  if dry_run:
69
    cmd.append("--dry-run")
70
  if no_verify:
71
    cmd.append("--no-verify")
72
  if downgrade:
73
    cmd.append("--downgrade")
74

    
75
  result = utils.RunCmd(cmd, cwd=os.getcwd())
76
  if result.failed:
77
    raise Exception("cfgupgrade failed: %s, output %r" %
78
                    (result.fail_reason, result.output))
79

    
80

    
81
class TestCfgupgrade(unittest.TestCase):
82
  def setUp(self):
83
    self.tmpdir = tempfile.mkdtemp()
84

    
85
    self.config_path = utils.PathJoin(self.tmpdir, "config.data")
86
    self.noded_cert_path = utils.PathJoin(self.tmpdir, "server.pem")
87
    self.rapi_cert_path = utils.PathJoin(self.tmpdir, "rapi.pem")
88
    self.rapi_users_path = utils.PathJoin(self.tmpdir, "rapi", "users")
89
    self.rapi_users_path_pre24 = utils.PathJoin(self.tmpdir, "rapi_users")
90
    self.known_hosts_path = utils.PathJoin(self.tmpdir, "known_hosts")
91
    self.confd_hmac_path = utils.PathJoin(self.tmpdir, "hmac.key")
92
    self.cds_path = utils.PathJoin(self.tmpdir, "cluster-domain-secret")
93
    self.ss_master_node_path = utils.PathJoin(self.tmpdir, "ssconf_master_node")
94
    self.file_storage_paths = utils.PathJoin(self.tmpdir, "file-storage-paths")
95

    
96
  def tearDown(self):
97
    shutil.rmtree(self.tmpdir)
98

    
99
  def _LoadConfig(self):
100
    return serializer.LoadJson(utils.ReadFile(self.config_path))
101

    
102
  def _LoadTestDataConfig(self, filename):
103
    return serializer.LoadJson(testutils.ReadTestData(filename))
104

    
105
  def _CreateValidConfigDir(self):
106
    utils.WriteFile(self.noded_cert_path, data="")
107
    utils.WriteFile(self.known_hosts_path, data="")
108
    utils.WriteFile(self.ss_master_node_path,
109
                    data="node.has.another.name.example.net")
110

    
111
  def testNoConfigDir(self):
112
    self.assertFalse(utils.ListVisibleFiles(self.tmpdir))
113
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
114
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, True, True)
115

    
116
  def testWrongHostname(self):
117
    self._CreateValidConfigDir()
118

    
119
    utils.WriteFile(self.config_path,
120
                    data=serializer.DumpJson(GetMinimalConfig()))
121

    
122
    hostname = netutils.GetHostname().name
123
    assert hostname != utils.ReadOneLineFile(self.ss_master_node_path)
124

    
125
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True,
126
                      ignore_hostname=False)
127

    
128
  def testCorrectHostname(self):
129
    self._CreateValidConfigDir()
130

    
131
    utils.WriteFile(self.config_path,
132
                    data=serializer.DumpJson(GetMinimalConfig()))
133

    
134
    utils.WriteFile(self.ss_master_node_path,
135
                    data="%s\n" % netutils.GetHostname().name)
136

    
137
    _RunUpgrade(self.tmpdir, False, True, ignore_hostname=False)
138

    
139
  def testInconsistentConfig(self):
140
    self._CreateValidConfigDir()
141
    # There should be no "config_version"
142
    cfg = GetMinimalConfig()
143
    cfg["version"] = 0
144
    cfg["cluster"]["config_version"] = 0
145
    utils.WriteFile(self.config_path, data=serializer.DumpJson(cfg))
146
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
147

    
148
  def testInvalidConfig(self):
149
    self._CreateValidConfigDir()
150
    # Missing version from config
151
    utils.WriteFile(self.config_path, data=serializer.DumpJson({}))
152
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
153

    
154
  def _TestUpgradeFromFile(self, filename, dry_run):
155
    cfg = self._LoadTestDataConfig(filename)
156
    self._TestUpgradeFromData(cfg, dry_run)
157

    
158
  def _TestSimpleUpgrade(self, from_version, dry_run,
159
                         file_storage_dir=None,
160
                         shared_file_storage_dir=None):
161
    cfg = GetMinimalConfig()
162
    cfg["version"] = from_version
163
    cluster = cfg["cluster"]
164

    
165
    if file_storage_dir:
166
      cluster["file_storage_dir"] = file_storage_dir
167
    if shared_file_storage_dir:
168
      cluster["shared_file_storage_dir"] = shared_file_storage_dir
169

    
170
    self._TestUpgradeFromData(cfg, dry_run)
171

    
172
  def _TestUpgradeFromData(self, cfg, dry_run):
173
    assert "version" in cfg
174
    from_version = cfg["version"]
175
    self._CreateValidConfigDir()
176
    utils.WriteFile(self.config_path, data=serializer.DumpJson(cfg))
177

    
178
    self.assertFalse(os.path.isfile(self.rapi_cert_path))
179
    self.assertFalse(os.path.isfile(self.confd_hmac_path))
180
    self.assertFalse(os.path.isfile(self.cds_path))
181

    
182
    _RunUpgrade(self.tmpdir, dry_run, True)
183

    
184
    if dry_run:
185
      expversion = from_version
186
      checkfn = operator.not_
187
    else:
188
      expversion = constants.CONFIG_VERSION
189
      checkfn = operator.truth
190

    
191
    self.assert_(checkfn(os.path.isfile(self.rapi_cert_path)))
192
    self.assert_(checkfn(os.path.isfile(self.confd_hmac_path)))
193
    self.assert_(checkfn(os.path.isfile(self.cds_path)))
194

    
195
    newcfg = self._LoadConfig()
196
    self.assertEqual(newcfg["version"], expversion)
197

    
198
  def testRapiUsers(self):
199
    self.assertFalse(os.path.exists(self.rapi_users_path))
200
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
201
    self.assertFalse(os.path.exists(os.path.dirname(self.rapi_users_path)))
202

    
203
    utils.WriteFile(self.rapi_users_path_pre24, data="some user\n")
204
    self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), False)
205

    
206
    self.assertTrue(os.path.isdir(os.path.dirname(self.rapi_users_path)))
207
    self.assert_(os.path.islink(self.rapi_users_path_pre24))
208
    self.assert_(os.path.isfile(self.rapi_users_path))
209
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
210
                     self.rapi_users_path)
211
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
212
      self.assertEqual(utils.ReadFile(path), "some user\n")
213

    
214
  def testRapiUsers24AndAbove(self):
215
    self.assertFalse(os.path.exists(self.rapi_users_path))
216
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
217

    
218
    os.mkdir(os.path.dirname(self.rapi_users_path))
219
    utils.WriteFile(self.rapi_users_path, data="other user\n")
220
    self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), False)
221

    
222
    self.assert_(os.path.islink(self.rapi_users_path_pre24))
223
    self.assert_(os.path.isfile(self.rapi_users_path))
224
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
225
                     self.rapi_users_path)
226
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
227
      self.assertEqual(utils.ReadFile(path), "other user\n")
228

    
229
  def testRapiUsersExistingSymlink(self):
230
    self.assertFalse(os.path.exists(self.rapi_users_path))
231
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
232

    
233
    os.mkdir(os.path.dirname(self.rapi_users_path))
234
    os.symlink(self.rapi_users_path, self.rapi_users_path_pre24)
235
    utils.WriteFile(self.rapi_users_path, data="hello world\n")
236

    
237
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), False)
238

    
239
    self.assert_(os.path.isfile(self.rapi_users_path) and
240
                 not os.path.islink(self.rapi_users_path))
241
    self.assert_(os.path.islink(self.rapi_users_path_pre24))
242
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
243
                     self.rapi_users_path)
244
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
245
      self.assertEqual(utils.ReadFile(path), "hello world\n")
246

    
247
  def testRapiUsersExistingTarget(self):
248
    self.assertFalse(os.path.exists(self.rapi_users_path))
249
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
250

    
251
    os.mkdir(os.path.dirname(self.rapi_users_path))
252
    utils.WriteFile(self.rapi_users_path, data="other user\n")
253
    utils.WriteFile(self.rapi_users_path_pre24, data="hello world\n")
254

    
255
    self.assertRaises(Exception, self._TestSimpleUpgrade,
256
                      version.BuildVersion(2, 2, 0), False)
257

    
258
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
259
      self.assert_(os.path.isfile(path) and not os.path.islink(path))
260
    self.assertEqual(utils.ReadFile(self.rapi_users_path), "other user\n")
261
    self.assertEqual(utils.ReadFile(self.rapi_users_path_pre24),
262
                     "hello world\n")
263

    
264
  def testRapiUsersDryRun(self):
265
    self.assertFalse(os.path.exists(self.rapi_users_path))
266
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
267

    
268
    utils.WriteFile(self.rapi_users_path_pre24, data="some user\n")
269
    self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), True)
270

    
271
    self.assertFalse(os.path.isdir(os.path.dirname(self.rapi_users_path)))
272
    self.assertTrue(os.path.isfile(self.rapi_users_path_pre24) and
273
                    not os.path.islink(self.rapi_users_path_pre24))
274
    self.assertFalse(os.path.exists(self.rapi_users_path))
275

    
276
  def testRapiUsers24AndAboveDryRun(self):
277
    self.assertFalse(os.path.exists(self.rapi_users_path))
278
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
279

    
280
    os.mkdir(os.path.dirname(self.rapi_users_path))
281
    utils.WriteFile(self.rapi_users_path, data="other user\n")
282
    self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), True)
283

    
284
    self.assertTrue(os.path.isfile(self.rapi_users_path) and
285
                    not os.path.islink(self.rapi_users_path))
286
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
287
    self.assertEqual(utils.ReadFile(self.rapi_users_path), "other user\n")
288

    
289
  def testRapiUsersExistingSymlinkDryRun(self):
290
    self.assertFalse(os.path.exists(self.rapi_users_path))
291
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
292

    
293
    os.mkdir(os.path.dirname(self.rapi_users_path))
294
    os.symlink(self.rapi_users_path, self.rapi_users_path_pre24)
295
    utils.WriteFile(self.rapi_users_path, data="hello world\n")
296

    
297
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), True)
298

    
299
    self.assertTrue(os.path.islink(self.rapi_users_path_pre24))
300
    self.assertTrue(os.path.isfile(self.rapi_users_path) and
301
                    not os.path.islink(self.rapi_users_path))
302
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
303
                     self.rapi_users_path)
304
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
305
      self.assertEqual(utils.ReadFile(path), "hello world\n")
306

    
307
  def testFileStoragePathsDryRun(self):
308
    self.assertFalse(os.path.exists(self.file_storage_paths))
309

    
310
    self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), True,
311
                            file_storage_dir=self.tmpdir,
312
                            shared_file_storage_dir="/tmp")
313

    
314
    self.assertFalse(os.path.exists(self.file_storage_paths))
315

    
316
  def testFileStoragePathsBoth(self):
317
    self.assertFalse(os.path.exists(self.file_storage_paths))
318

    
319
    self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), False,
320
                            file_storage_dir=self.tmpdir,
321
                            shared_file_storage_dir="/tmp")
322

    
323
    lines = utils.ReadFile(self.file_storage_paths).splitlines()
324
    self.assertTrue(lines.pop(0).startswith("# "))
325
    self.assertTrue(lines.pop(0).startswith("# cfgupgrade"))
326
    self.assertEqual(lines.pop(0), self.tmpdir)
327
    self.assertEqual(lines.pop(0), "/tmp")
328
    self.assertFalse(lines)
329
    self.assertEqual(os.stat(self.file_storage_paths).st_mode & 0777,
330
                     0600, msg="Wrong permissions")
331

    
332
  def testFileStoragePathsSharedOnly(self):
333
    self.assertFalse(os.path.exists(self.file_storage_paths))
334

    
335
    self._TestSimpleUpgrade(version.BuildVersion(2, 5, 0), False,
336
                            file_storage_dir=None,
337
                            shared_file_storage_dir=self.tmpdir)
338

    
339
    lines = utils.ReadFile(self.file_storage_paths).splitlines()
340
    self.assertTrue(lines.pop(0).startswith("# "))
341
    self.assertTrue(lines.pop(0).startswith("# cfgupgrade"))
342
    self.assertEqual(lines.pop(0), self.tmpdir)
343
    self.assertFalse(lines)
344

    
345
  def testUpgradeFrom_2_0(self):
346
    self._TestSimpleUpgrade(version.BuildVersion(2, 0, 0), False)
347

    
348
  def testUpgradeFrom_2_1(self):
349
    self._TestSimpleUpgrade(version.BuildVersion(2, 1, 0), False)
350

    
351
  def testUpgradeFrom_2_2(self):
352
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), False)
353

    
354
  def testUpgradeFrom_2_3(self):
355
    self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), False)
356

    
357
  def testUpgradeFrom_2_4(self):
358
    self._TestSimpleUpgrade(version.BuildVersion(2, 4, 0), False)
359

    
360
  def testUpgradeFrom_2_5(self):
361
    self._TestSimpleUpgrade(version.BuildVersion(2, 5, 0), False)
362

    
363
  def testUpgradeFrom_2_6(self):
364
    self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), False)
365

    
366
  def testUpgradeFrom_2_7(self):
367
    self._TestSimpleUpgrade(version.BuildVersion(2, 7, 0), False)
368

    
369
  def testUpgradeFullConfigFrom_2_7(self):
370
    self._TestUpgradeFromFile("cluster_config_2.7.json", False)
371

    
372
  def testUpgradeFullConfigFrom_2_8(self):
373
    self._TestUpgradeFromFile("cluster_config_2.8.json", False)
374

    
375
  def testUpgradeCurrent(self):
376
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
377

    
378
  def _RunDowngradeUpgrade(self):
379
    oldconf = self._LoadConfig()
380
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
381
    _RunUpgrade(self.tmpdir, False, True)
382
    newconf = self._LoadConfig()
383
    self.assertEqual(oldconf, newconf)
384

    
385
  def testDowngrade(self):
386
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
387
    self._RunDowngradeUpgrade()
388

    
389
  def testDowngradeFullConfig(self):
390
    """Test for upgrade + downgrade combination."""
391
    # This test can work only with the previous version of a configuration!
392
    oldconfname = "cluster_config_2.9.json"
393
    self._TestUpgradeFromFile(oldconfname, False)
394
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
395
    oldconf = self._LoadTestDataConfig(oldconfname)
396
    newconf = self._LoadConfig()
397

    
398
    # downgrade from 2.10 to 2.9 does not add physical_id to disks, which is ok
399
    # TODO (2.11): Remove this code, it's not required to downgrade from 2.11
400
    #              to 2.10
401
    def RemovePhysicalId(disk):
402
      if "children" in disk:
403
        for d in disk["children"]:
404
          RemovePhysicalId(d)
405
      if "physical_id" in disk:
406
        del disk["physical_id"]
407

    
408
    for inst in oldconf["instances"].values():
409
      for disk in inst["disks"]:
410
        RemovePhysicalId(disk)
411

    
412
    self.assertEqual(oldconf, newconf)
413

    
414
  def testDowngradeFullConfigBackwardFrom_2_7(self):
415
    """Test for upgrade + downgrade + upgrade combination."""
416
    self._TestUpgradeFromFile("cluster_config_2.7.json", False)
417
    self._RunDowngradeUpgrade()
418

    
419
  def _RunDowngradeTwice(self):
420
    """Make sure that downgrade is idempotent."""
421
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
422
    oldconf = self._LoadConfig()
423
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
424
    newconf = self._LoadConfig()
425
    self.assertEqual(oldconf, newconf)
426

    
427
  def testDowngradeTwice(self):
428
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
429
    self._RunDowngradeTwice()
430

    
431
  def testDowngradeTwiceFullConfigFrom_2_7(self):
432
    self._TestUpgradeFromFile("cluster_config_2.7.json", False)
433
    self._RunDowngradeTwice()
434

    
435
  def testUpgradeDryRunFrom_2_0(self):
436
    self._TestSimpleUpgrade(version.BuildVersion(2, 0, 0), True)
437

    
438
  def testUpgradeDryRunFrom_2_1(self):
439
    self._TestSimpleUpgrade(version.BuildVersion(2, 1, 0), True)
440

    
441
  def testUpgradeDryRunFrom_2_2(self):
442
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), True)
443

    
444
  def testUpgradeDryRunFrom_2_3(self):
445
    self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), True)
446

    
447
  def testUpgradeDryRunFrom_2_4(self):
448
    self._TestSimpleUpgrade(version.BuildVersion(2, 4, 0), True)
449

    
450
  def testUpgradeDryRunFrom_2_5(self):
451
    self._TestSimpleUpgrade(version.BuildVersion(2, 5, 0), True)
452

    
453
  def testUpgradeDryRunFrom_2_6(self):
454
    self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), True)
455

    
456
  def testUpgradeCurrentDryRun(self):
457
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, True)
458

    
459
  def testDowngradeDryRun(self):
460
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
461
    oldconf = self._LoadConfig()
462
    _RunUpgrade(self.tmpdir, True, True, downgrade=True)
463
    newconf = self._LoadConfig()
464
    self.assertEqual(oldconf["version"], newconf["version"])
465

    
466
if __name__ == "__main__":
467
  testutils.GanetiTestProgram()