cfgupgrade_unittest.py 17.1 KB
Newer Older
1
2
3
#!/usr/bin/python
#

4
# Copyright (C) 2010, 2012, 2013 Google Inc.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.


"""Script for testing tools/cfgupgrade"""

import os
import sys
import unittest
import shutil
import tempfile
import operator
30
import json
31
32
33
34

from ganeti import constants
from ganeti import utils
from ganeti import serializer
35
from ganeti import netutils
36

37
38
from ganeti.utils import version

39
40
41
import testutils


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


65
66
def _RunUpgrade(path, dry_run, no_verify, ignore_hostname=True,
                downgrade=False):
67
  cmd = [sys.executable, "%s/tools/cfgupgrade" % testutils.GetSourceDir(),
68
         "--debug", "--force", "--path=%s" % path, "--confdir=%s" % path]
69
70
71

  if ignore_hostname:
    cmd.append("--ignore-hostname")
72
73
74
75
  if dry_run:
    cmd.append("--dry-run")
  if no_verify:
    cmd.append("--no-verify")
76
77
  if downgrade:
    cmd.append("--downgrade")
78
79
80
81
82
83
84
85
86
87
88
89
90
91

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


class TestCfgupgrade(unittest.TestCase):
  def setUp(self):
    self.tmpdir = tempfile.mkdtemp()

    self.config_path = utils.PathJoin(self.tmpdir, "config.data")
    self.noded_cert_path = utils.PathJoin(self.tmpdir, "server.pem")
    self.rapi_cert_path = utils.PathJoin(self.tmpdir, "rapi.pem")
92
93
    self.rapi_users_path = utils.PathJoin(self.tmpdir, "rapi", "users")
    self.rapi_users_path_pre24 = utils.PathJoin(self.tmpdir, "rapi_users")
94
95
96
    self.known_hosts_path = utils.PathJoin(self.tmpdir, "known_hosts")
    self.confd_hmac_path = utils.PathJoin(self.tmpdir, "hmac.key")
    self.cds_path = utils.PathJoin(self.tmpdir, "cluster-domain-secret")
97
    self.ss_master_node_path = utils.PathJoin(self.tmpdir, "ssconf_master_node")
98
    self.file_storage_paths = utils.PathJoin(self.tmpdir, "file-storage-paths")
99
100
101
102
103
104
105

  def tearDown(self):
    shutil.rmtree(self.tmpdir)

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

106
107
108
  def _LoadTestDataConfig(self, filename):
    return serializer.LoadJson(testutils.ReadTestData(filename))

109
110
111
  def _CreateValidConfigDir(self):
    utils.WriteFile(self.noded_cert_path, data="")
    utils.WriteFile(self.known_hosts_path, data="")
112
113
    utils.WriteFile(self.ss_master_node_path,
                    data="node.has.another.name.example.net")
114
115
116
117
118
119

  def testNoConfigDir(self):
    self.assertFalse(utils.ListVisibleFiles(self.tmpdir))
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, True, True)

120
121
122
  def testWrongHostname(self):
    self._CreateValidConfigDir()

123
124
    utils.WriteFile(self.config_path,
                    data=serializer.DumpJson(GetMinimalConfig()))
125
126
127
128
129
130
131
132
133
134

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

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

  def testCorrectHostname(self):
    self._CreateValidConfigDir()

135
136
    utils.WriteFile(self.config_path,
                    data=serializer.DumpJson(GetMinimalConfig()))
137
138
139
140
141
142

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

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

143
144
145
  def testInconsistentConfig(self):
    self._CreateValidConfigDir()
    # There should be no "config_version"
146
147
148
    cfg = GetMinimalConfig()
    cfg["version"] = 0
    cfg["cluster"]["config_version"] = 0
149
150
151
152
153
154
155
156
157
    utils.WriteFile(self.config_path, data=serializer.DumpJson(cfg))
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)

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

158
159
160
161
  def _TestUpgradeFromFile(self, filename, dry_run):
    cfg = self._LoadTestDataConfig(filename)
    self._TestUpgradeFromData(cfg, dry_run)

162
163
164
  def _TestSimpleUpgrade(self, from_version, dry_run,
                         file_storage_dir=None,
                         shared_file_storage_dir=None):
165
166
167
    cfg = GetMinimalConfig()
    cfg["version"] = from_version
    cluster = cfg["cluster"]
168
169
170
171
172
173

    if file_storage_dir:
      cluster["file_storage_dir"] = file_storage_dir
    if shared_file_storage_dir:
      cluster["shared_file_storage_dir"] = shared_file_storage_dir

174
175
176
177
178
    self._TestUpgradeFromData(cfg, dry_run)

  def _TestUpgradeFromData(self, cfg, dry_run):
    assert "version" in cfg
    from_version = cfg["version"]
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
    self._CreateValidConfigDir()
    utils.WriteFile(self.config_path, data=serializer.DumpJson(cfg))

    self.assertFalse(os.path.isfile(self.rapi_cert_path))
    self.assertFalse(os.path.isfile(self.confd_hmac_path))
    self.assertFalse(os.path.isfile(self.cds_path))

    _RunUpgrade(self.tmpdir, dry_run, True)

    if dry_run:
      expversion = from_version
      checkfn = operator.not_
    else:
      expversion = constants.CONFIG_VERSION
      checkfn = operator.truth

    self.assert_(checkfn(os.path.isfile(self.rapi_cert_path)))
    self.assert_(checkfn(os.path.isfile(self.confd_hmac_path)))
    self.assert_(checkfn(os.path.isfile(self.cds_path)))

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

202
203
204
  def testRapiUsers(self):
    self.assertFalse(os.path.exists(self.rapi_users_path))
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
205
    self.assertFalse(os.path.exists(os.path.dirname(self.rapi_users_path)))
206
207

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

210
    self.assertTrue(os.path.isdir(os.path.dirname(self.rapi_users_path)))
211
212
    self.assert_(os.path.islink(self.rapi_users_path_pre24))
    self.assert_(os.path.isfile(self.rapi_users_path))
213
214
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
                     self.rapi_users_path)
215
216
217
218
219
220
221
222
223
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
      self.assertEqual(utils.ReadFile(path), "some user\n")

  def testRapiUsers24AndAbove(self):
    self.assertFalse(os.path.exists(self.rapi_users_path))
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))

    os.mkdir(os.path.dirname(self.rapi_users_path))
    utils.WriteFile(self.rapi_users_path, data="other user\n")
224
    self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), False)
225
226
227

    self.assert_(os.path.islink(self.rapi_users_path_pre24))
    self.assert_(os.path.isfile(self.rapi_users_path))
228
229
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
                     self.rapi_users_path)
230
231
232
233
234
235
236
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
      self.assertEqual(utils.ReadFile(path), "other user\n")

  def testRapiUsersExistingSymlink(self):
    self.assertFalse(os.path.exists(self.rapi_users_path))
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))

237
    os.mkdir(os.path.dirname(self.rapi_users_path))
238
    os.symlink(self.rapi_users_path, self.rapi_users_path_pre24)
239
    utils.WriteFile(self.rapi_users_path, data="hello world\n")
240

241
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), False)
242

243
244
    self.assert_(os.path.isfile(self.rapi_users_path) and
                 not os.path.islink(self.rapi_users_path))
245
    self.assert_(os.path.islink(self.rapi_users_path_pre24))
246
247
248
249
250
251
252
253
254
255
256
257
258
259
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
                     self.rapi_users_path)
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
      self.assertEqual(utils.ReadFile(path), "hello world\n")

  def testRapiUsersExistingTarget(self):
    self.assertFalse(os.path.exists(self.rapi_users_path))
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))

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

    self.assertRaises(Exception, self._TestSimpleUpgrade,
260
                      version.BuildVersion(2, 2, 0), False)
261
262
263
264
265
266
267
268
269
270
271
272

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

  def testRapiUsersDryRun(self):
    self.assertFalse(os.path.exists(self.rapi_users_path))
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))

    utils.WriteFile(self.rapi_users_path_pre24, data="some user\n")
273
    self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), True)
274
275
276
277
278
279
280
281
282
283
284
285

    self.assertFalse(os.path.isdir(os.path.dirname(self.rapi_users_path)))
    self.assertTrue(os.path.isfile(self.rapi_users_path_pre24) and
                    not os.path.islink(self.rapi_users_path_pre24))
    self.assertFalse(os.path.exists(self.rapi_users_path))

  def testRapiUsers24AndAboveDryRun(self):
    self.assertFalse(os.path.exists(self.rapi_users_path))
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))

    os.mkdir(os.path.dirname(self.rapi_users_path))
    utils.WriteFile(self.rapi_users_path, data="other user\n")
286
    self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), True)
287
288
289
290
291
292
293
294
295
296
297
298
299
300

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

  def testRapiUsersExistingSymlinkDryRun(self):
    self.assertFalse(os.path.exists(self.rapi_users_path))
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))

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

301
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), True)
302
303
304
305
306
307

    self.assertTrue(os.path.islink(self.rapi_users_path_pre24))
    self.assertTrue(os.path.isfile(self.rapi_users_path) and
                    not os.path.islink(self.rapi_users_path))
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
                     self.rapi_users_path)
308
309
310
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
      self.assertEqual(utils.ReadFile(path), "hello world\n")

311
312
313
  def testFileStoragePathsDryRun(self):
    self.assertFalse(os.path.exists(self.file_storage_paths))

314
    self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), True,
315
316
317
318
319
320
321
322
                            file_storage_dir=self.tmpdir,
                            shared_file_storage_dir="/tmp")

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

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

323
    self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), False,
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
                            file_storage_dir=self.tmpdir,
                            shared_file_storage_dir="/tmp")

    lines = utils.ReadFile(self.file_storage_paths).splitlines()
    self.assertTrue(lines.pop(0).startswith("# "))
    self.assertTrue(lines.pop(0).startswith("# cfgupgrade"))
    self.assertEqual(lines.pop(0), self.tmpdir)
    self.assertEqual(lines.pop(0), "/tmp")
    self.assertFalse(lines)
    self.assertEqual(os.stat(self.file_storage_paths).st_mode & 0777,
                     0600, msg="Wrong permissions")

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

339
    self._TestSimpleUpgrade(version.BuildVersion(2, 5, 0), False,
340
341
342
343
344
345
346
347
348
                            file_storage_dir=None,
                            shared_file_storage_dir=self.tmpdir)

    lines = utils.ReadFile(self.file_storage_paths).splitlines()
    self.assertTrue(lines.pop(0).startswith("# "))
    self.assertTrue(lines.pop(0).startswith("# cfgupgrade"))
    self.assertEqual(lines.pop(0), self.tmpdir)
    self.assertFalse(lines)

349
  def testUpgradeFrom_2_0(self):
350
    self._TestSimpleUpgrade(version.BuildVersion(2, 0, 0), False)
351
352

  def testUpgradeFrom_2_1(self):
353
    self._TestSimpleUpgrade(version.BuildVersion(2, 1, 0), False)
354

355
  def testUpgradeFrom_2_2(self):
356
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), False)
357
358

  def testUpgradeFrom_2_3(self):
359
    self._TestSimpleUpgrade(version.BuildVersion(2, 3, 0), False)
360

361
  def testUpgradeFrom_2_4(self):
362
    self._TestSimpleUpgrade(version.BuildVersion(2, 4, 0), False)
363

364
  def testUpgradeFrom_2_5(self):
365
    self._TestSimpleUpgrade(version.BuildVersion(2, 5, 0), False)
366

367
  def testUpgradeFrom_2_6(self):
368
    self._TestSimpleUpgrade(version.BuildVersion(2, 6, 0), False)
369

370
  def testUpgradeFrom_2_7(self):
371
    self._TestSimpleUpgrade(version.BuildVersion(2, 7, 0), False)
372
373
374
375

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

376
377
378
  def testUpgradeFullConfigFrom_2_8(self):
    self._TestUpgradeFromFile("cluster_config_2.8.json", False)

379
380
381
  def testUpgradeFullConfigFrom_2_9(self):
    self._TestUpgradeFromFile("cluster_config_2.9.json", False)

382
383
384
  def testUpgradeFullConfigFrom_2_10(self):
    self._TestUpgradeFromFile("cluster_config_2.10.json", False)

385
386
387
  def testUpgradeCurrent(self):
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)

388
  def _RunDowngradeUpgrade(self):
389
390
391
392
393
394
    oldconf = self._LoadConfig()
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
    _RunUpgrade(self.tmpdir, False, True)
    newconf = self._LoadConfig()
    self.assertEqual(oldconf, newconf)

395
  def testDowngrade(self):
396
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
397
398
    self._RunDowngradeUpgrade()

399
400
401
  def testDowngradeFullConfig(self):
    """Test for upgrade + downgrade combination."""
    # This test can work only with the previous version of a configuration!
402
    oldconfname = "cluster_config_2.11.json"
403
404
405
406
    self._TestUpgradeFromFile(oldconfname, False)
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
    oldconf = self._LoadTestDataConfig(oldconfname)
    newconf = self._LoadConfig()
407
408
409
410
411
412
    old = open('/tmp/old', 'w')
    old.write(json.dumps(oldconf))
    old.close()
    new = open('/tmp/new', 'w')
    new.write(json.dumps(newconf))
    new.close()
413
414
415
416
417
418
419
    self.assertEqual(oldconf, newconf)

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

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

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

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

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

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

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

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

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

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

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

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

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

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