Statistics
| Branch: | Tag: | Revision:

root / test / py / cfgupgrade_unittest.py @ 1d9f9df7

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 serializer
34
from ganeti import netutils
35

    
36
import testutils
37

    
38

    
39
def GetMinimalConfig():
40
  return {
41
    "version": constants.CONFIG_VERSION,
42
    "cluster": {
43
      "master_node": "node1-uuid"
44
    },
45
    "instances": {},
46
    "nodegroups": {},
47
    "nodes": {
48
      "node1-uuid": {
49
        "name": "node1",
50
        "uuid": "node1-uuid"
51
      }
52
    },
53
  }
54

    
55

    
56
def _RunUpgrade(path, dry_run, no_verify, ignore_hostname=True,
57
                downgrade=False):
58
  cmd = [sys.executable, "%s/tools/cfgupgrade" % testutils.GetSourceDir(),
59
         "--debug", "--force", "--path=%s" % path, "--confdir=%s" % path]
60

    
61
  if ignore_hostname:
62
    cmd.append("--ignore-hostname")
63
  if dry_run:
64
    cmd.append("--dry-run")
65
  if no_verify:
66
    cmd.append("--no-verify")
67
  if downgrade:
68
    cmd.append("--downgrade")
69

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

    
75

    
76
class TestCfgupgrade(unittest.TestCase):
77
  def setUp(self):
78
    self.tmpdir = tempfile.mkdtemp()
79

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

    
91
  def tearDown(self):
92
    shutil.rmtree(self.tmpdir)
93

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

    
97
  def _LoadTestDataConfig(self, filename):
98
    return serializer.LoadJson(testutils.ReadTestData(filename))
99

    
100
  def _CreateValidConfigDir(self):
101
    utils.WriteFile(self.noded_cert_path, data="")
102
    utils.WriteFile(self.known_hosts_path, data="")
103
    utils.WriteFile(self.ss_master_node_path,
104
                    data="node.has.another.name.example.net")
105

    
106
  def testNoConfigDir(self):
107
    self.assertFalse(utils.ListVisibleFiles(self.tmpdir))
108
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
109
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, True, True)
110

    
111
  def testWrongHostname(self):
112
    self._CreateValidConfigDir()
113

    
114
    utils.WriteFile(self.config_path,
115
                    data=serializer.DumpJson(GetMinimalConfig()))
116

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

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

    
123
  def testCorrectHostname(self):
124
    self._CreateValidConfigDir()
125

    
126
    utils.WriteFile(self.config_path,
127
                    data=serializer.DumpJson(GetMinimalConfig()))
128

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

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

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

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

    
149
  def _TestUpgradeFromFile(self, filename, dry_run):
150
    cfg = self._LoadTestDataConfig(filename)
151
    self._TestUpgradeFromData(cfg, dry_run)
152

    
153
  def _TestSimpleUpgrade(self, from_version, dry_run,
154
                         file_storage_dir=None,
155
                         shared_file_storage_dir=None):
156
    cfg = GetMinimalConfig()
157
    cfg["version"] = from_version
158
    cluster = cfg["cluster"]
159

    
160
    if file_storage_dir:
161
      cluster["file_storage_dir"] = file_storage_dir
162
    if shared_file_storage_dir:
163
      cluster["shared_file_storage_dir"] = shared_file_storage_dir
164

    
165
    self._TestUpgradeFromData(cfg, dry_run)
166

    
167
  def _TestUpgradeFromData(self, cfg, dry_run):
168
    assert "version" in cfg
169
    from_version = cfg["version"]
170
    self._CreateValidConfigDir()
171
    utils.WriteFile(self.config_path, data=serializer.DumpJson(cfg))
172

    
173
    self.assertFalse(os.path.isfile(self.rapi_cert_path))
174
    self.assertFalse(os.path.isfile(self.confd_hmac_path))
175
    self.assertFalse(os.path.isfile(self.cds_path))
176

    
177
    _RunUpgrade(self.tmpdir, dry_run, True)
178

    
179
    if dry_run:
180
      expversion = from_version
181
      checkfn = operator.not_
182
    else:
183
      expversion = constants.CONFIG_VERSION
184
      checkfn = operator.truth
185

    
186
    self.assert_(checkfn(os.path.isfile(self.rapi_cert_path)))
187
    self.assert_(checkfn(os.path.isfile(self.confd_hmac_path)))
188
    self.assert_(checkfn(os.path.isfile(self.cds_path)))
189

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

    
193
  def testRapiUsers(self):
194
    self.assertFalse(os.path.exists(self.rapi_users_path))
195
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
196
    self.assertFalse(os.path.exists(os.path.dirname(self.rapi_users_path)))
197

    
198
    utils.WriteFile(self.rapi_users_path_pre24, data="some user\n")
199
    self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), False)
200

    
201
    self.assertTrue(os.path.isdir(os.path.dirname(self.rapi_users_path)))
202
    self.assert_(os.path.islink(self.rapi_users_path_pre24))
203
    self.assert_(os.path.isfile(self.rapi_users_path))
204
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
205
                     self.rapi_users_path)
206
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
207
      self.assertEqual(utils.ReadFile(path), "some user\n")
208

    
209
  def testRapiUsers24AndAbove(self):
210
    self.assertFalse(os.path.exists(self.rapi_users_path))
211
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
212

    
213
    os.mkdir(os.path.dirname(self.rapi_users_path))
214
    utils.WriteFile(self.rapi_users_path, data="other user\n")
215
    self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), False)
216

    
217
    self.assert_(os.path.islink(self.rapi_users_path_pre24))
218
    self.assert_(os.path.isfile(self.rapi_users_path))
219
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
220
                     self.rapi_users_path)
221
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
222
      self.assertEqual(utils.ReadFile(path), "other user\n")
223

    
224
  def testRapiUsersExistingSymlink(self):
225
    self.assertFalse(os.path.exists(self.rapi_users_path))
226
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
227

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

    
232
    self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), False)
233

    
234
    self.assert_(os.path.isfile(self.rapi_users_path) and
235
                 not os.path.islink(self.rapi_users_path))
236
    self.assert_(os.path.islink(self.rapi_users_path_pre24))
237
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
238
                     self.rapi_users_path)
239
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
240
      self.assertEqual(utils.ReadFile(path), "hello world\n")
241

    
242
  def testRapiUsersExistingTarget(self):
243
    self.assertFalse(os.path.exists(self.rapi_users_path))
244
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
245

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

    
250
    self.assertRaises(Exception, self._TestSimpleUpgrade,
251
                      constants.BuildVersion(2, 2, 0), False)
252

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

    
259
  def testRapiUsersDryRun(self):
260
    self.assertFalse(os.path.exists(self.rapi_users_path))
261
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
262

    
263
    utils.WriteFile(self.rapi_users_path_pre24, data="some user\n")
264
    self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
265

    
266
    self.assertFalse(os.path.isdir(os.path.dirname(self.rapi_users_path)))
267
    self.assertTrue(os.path.isfile(self.rapi_users_path_pre24) and
268
                    not os.path.islink(self.rapi_users_path_pre24))
269
    self.assertFalse(os.path.exists(self.rapi_users_path))
270

    
271
  def testRapiUsers24AndAboveDryRun(self):
272
    self.assertFalse(os.path.exists(self.rapi_users_path))
273
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
274

    
275
    os.mkdir(os.path.dirname(self.rapi_users_path))
276
    utils.WriteFile(self.rapi_users_path, data="other user\n")
277
    self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
278

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

    
284
  def testRapiUsersExistingSymlinkDryRun(self):
285
    self.assertFalse(os.path.exists(self.rapi_users_path))
286
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
287

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

    
292
    self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), True)
293

    
294
    self.assertTrue(os.path.islink(self.rapi_users_path_pre24))
295
    self.assertTrue(os.path.isfile(self.rapi_users_path) and
296
                    not os.path.islink(self.rapi_users_path))
297
    self.assertEqual(os.readlink(self.rapi_users_path_pre24),
298
                     self.rapi_users_path)
299
    for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
300
      self.assertEqual(utils.ReadFile(path), "hello world\n")
301

    
302
  def testFileStoragePathsDryRun(self):
303
    self.assertFalse(os.path.exists(self.file_storage_paths))
304

    
305
    self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), True,
306
                            file_storage_dir=self.tmpdir,
307
                            shared_file_storage_dir="/tmp")
308

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

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

    
314
    self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), False,
315
                            file_storage_dir=self.tmpdir,
316
                            shared_file_storage_dir="/tmp")
317

    
318
    lines = utils.ReadFile(self.file_storage_paths).splitlines()
319
    self.assertTrue(lines.pop(0).startswith("# "))
320
    self.assertTrue(lines.pop(0).startswith("# cfgupgrade"))
321
    self.assertEqual(lines.pop(0), self.tmpdir)
322
    self.assertEqual(lines.pop(0), "/tmp")
323
    self.assertFalse(lines)
324
    self.assertEqual(os.stat(self.file_storage_paths).st_mode & 0777,
325
                     0600, msg="Wrong permissions")
326

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

    
330
    self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), False,
331
                            file_storage_dir=None,
332
                            shared_file_storage_dir=self.tmpdir)
333

    
334
    lines = utils.ReadFile(self.file_storage_paths).splitlines()
335
    self.assertTrue(lines.pop(0).startswith("# "))
336
    self.assertTrue(lines.pop(0).startswith("# cfgupgrade"))
337
    self.assertEqual(lines.pop(0), self.tmpdir)
338
    self.assertFalse(lines)
339

    
340
  def testUpgradeFrom_2_0(self):
341
    self._TestSimpleUpgrade(constants.BuildVersion(2, 0, 0), False)
342

    
343
  def testUpgradeFrom_2_1(self):
344
    self._TestSimpleUpgrade(constants.BuildVersion(2, 1, 0), False)
345

    
346
  def testUpgradeFrom_2_2(self):
347
    self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), False)
348

    
349
  def testUpgradeFrom_2_3(self):
350
    self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), False)
351

    
352
  def testUpgradeFrom_2_4(self):
353
    self._TestSimpleUpgrade(constants.BuildVersion(2, 4, 0), False)
354

    
355
  def testUpgradeFrom_2_5(self):
356
    self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), False)
357

    
358
  def testUpgradeFrom_2_6(self):
359
    self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), False)
360

    
361
  def testUpgradeFrom_2_7(self):
362
    self._TestSimpleUpgrade(constants.BuildVersion(2, 7, 0), False)
363

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

    
367
  def testUpgradeFullConfigFrom_2_8(self):
368
    self._TestUpgradeFromFile("cluster_config_2.8.json", False)
369

    
370
  def testUpgradeCurrent(self):
371
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
372

    
373
  def _RunDowngradeUpgrade(self):
374
    oldconf = self._LoadConfig()
375
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
376
    _RunUpgrade(self.tmpdir, False, True)
377
    newconf = self._LoadConfig()
378
    self.assertEqual(oldconf, newconf)
379

    
380
  def testDowngrade(self):
381
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
382
    self._RunDowngradeUpgrade()
383

    
384
  def testDowngradeFullConfig(self):
385
    """Test for upgrade + downgrade combination."""
386
    # This test can work only with the previous version of a configuration!
387
    oldconfname = "cluster_config_2.8.json"
388
    self._TestUpgradeFromFile(oldconfname, False)
389
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
390
    oldconf = self._LoadTestDataConfig(oldconfname)
391
    newconf = self._LoadConfig()
392
    self.assertEqual(oldconf, newconf)
393

    
394
  def testDowngradeFrom_2_9(self):
395
    cfg29_name = "cluster_config_2.9.json"
396
    cfg29 = self._LoadTestDataConfig(cfg29_name)
397
    self._CreateValidConfigDir()
398
    utils.WriteFile(self.config_path, data=serializer.DumpJson(cfg29))
399
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
400
    cfg28 = self._LoadConfig()
401

    
402
    hvparams = cfg28["cluster"]["hvparams"]
403
    for xen_variant in [constants.HT_XEN_PVM, constants.HT_XEN_HVM]:
404
      xen_params = hvparams[xen_variant]
405
      self.assertTrue(constants.HV_XEN_CMD not in xen_params)
406

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

    
412
  def _RunDowngradeTwice(self):
413
    """Make sure that downgrade is idempotent."""
414
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
415
    oldconf = self._LoadConfig()
416
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
417
    newconf = self._LoadConfig()
418
    self.assertEqual(oldconf, newconf)
419

    
420
  def testDowngradeTwice(self):
421
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
422
    self._RunDowngradeTwice()
423

    
424
  def testDowngradeTwiceFullConfigFrom_2_7(self):
425
    self._TestUpgradeFromFile("cluster_config_2.7.json", False)
426
    self._RunDowngradeTwice()
427

    
428
  def testUpgradeDryRunFrom_2_0(self):
429
    self._TestSimpleUpgrade(constants.BuildVersion(2, 0, 0), True)
430

    
431
  def testUpgradeDryRunFrom_2_1(self):
432
    self._TestSimpleUpgrade(constants.BuildVersion(2, 1, 0), True)
433

    
434
  def testUpgradeDryRunFrom_2_2(self):
435
    self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), True)
436

    
437
  def testUpgradeDryRunFrom_2_3(self):
438
    self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
439

    
440
  def testUpgradeDryRunFrom_2_4(self):
441
    self._TestSimpleUpgrade(constants.BuildVersion(2, 4, 0), True)
442

    
443
  def testUpgradeDryRunFrom_2_5(self):
444
    self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), True)
445

    
446
  def testUpgradeDryRunFrom_2_6(self):
447
    self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), True)
448

    
449
  def testUpgradeCurrentDryRun(self):
450
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, True)
451

    
452
  def testDowngradeDryRun(self):
453
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
454
    oldconf = self._LoadConfig()
455
    _RunUpgrade(self.tmpdir, True, True, downgrade=True)
456
    newconf = self._LoadConfig()
457
    self.assertEqual(oldconf["version"], newconf["version"])
458

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