Statistics
| Branch: | Tag: | Revision:

root / test / py / cfgupgrade_unittest.py @ d5104ca4

History | View | Annotate | Download (16.8 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
from ganeti.utils import version
37

    
38
import testutils
39

    
40

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

    
62

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

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

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

    
82

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

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

    
98
  def tearDown(self):
99
    shutil.rmtree(self.tmpdir)
100

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

    
104
  def _LoadTestDataConfig(self, filename):
105
    return serializer.LoadJson(testutils.ReadTestData(filename))
106

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

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

    
118
  def testWrongHostname(self):
119
    self._CreateValidConfigDir()
120

    
121
    utils.WriteFile(self.config_path,
122
                    data=serializer.DumpJson(GetMinimalConfig()))
123

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

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

    
130
  def testCorrectHostname(self):
131
    self._CreateValidConfigDir()
132

    
133
    utils.WriteFile(self.config_path,
134
                    data=serializer.DumpJson(GetMinimalConfig()))
135

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

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

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

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

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

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

    
167
    if file_storage_dir:
168
      cluster["file_storage_dir"] = file_storage_dir
169
    if shared_file_storage_dir:
170
      cluster["shared_file_storage_dir"] = shared_file_storage_dir
171

    
172
    self._TestUpgradeFromData(cfg, dry_run)
173

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

    
180
    self.assertFalse(os.path.isfile(self.rapi_cert_path))
181
    self.assertFalse(os.path.isfile(self.confd_hmac_path))
182
    self.assertFalse(os.path.isfile(self.cds_path))
183

    
184
    _RunUpgrade(self.tmpdir, dry_run, True)
185

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

    
193
    self.assert_(checkfn(os.path.isfile(self.rapi_cert_path)))
194
    self.assert_(checkfn(os.path.isfile(self.confd_hmac_path)))
195
    self.assert_(checkfn(os.path.isfile(self.cds_path)))
196

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

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

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

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

    
216
  def testRapiUsers24AndAbove(self):
217
    self.assertFalse(os.path.exists(self.rapi_users_path))
218
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
219

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

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

    
231
  def testRapiUsersExistingSymlink(self):
232
    self.assertFalse(os.path.exists(self.rapi_users_path))
233
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
234

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

    
239
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), False)
240

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

    
249
  def testRapiUsersExistingTarget(self):
250
    self.assertFalse(os.path.exists(self.rapi_users_path))
251
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
252

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

    
257
    self.assertRaises(Exception, self._TestSimpleUpgrade,
258
                      version.BuildVersion(2, 2, 0), False)
259

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

    
266
  def testRapiUsersDryRun(self):
267
    self.assertFalse(os.path.exists(self.rapi_users_path))
268
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
269

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

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

    
278
  def testRapiUsers24AndAboveDryRun(self):
279
    self.assertFalse(os.path.exists(self.rapi_users_path))
280
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
281

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

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

    
291
  def testRapiUsersExistingSymlinkDryRun(self):
292
    self.assertFalse(os.path.exists(self.rapi_users_path))
293
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
294

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

    
299
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), True)
300

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

    
309
  def testFileStoragePathsDryRun(self):
310
    self.assertFalse(os.path.exists(self.file_storage_paths))
311

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

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

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

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

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

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

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

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

    
347
  def testUpgradeFrom_2_0(self):
348
    self._TestSimpleUpgrade(version.BuildVersion(2, 0, 0), False)
349

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

    
353
  def testUpgradeFrom_2_2(self):
354
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), False)
355

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

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

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

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

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

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

    
374
  def testUpgradeFullConfigFrom_2_8(self):
375
    self._TestUpgradeFromFile("cluster_config_2.8.json", False)
376

    
377
  def testUpgradeFullConfigFrom_2_9(self):
378
    self._TestUpgradeFromFile("cluster_config_2.9.json", False)
379

    
380
  def testUpgradeCurrent(self):
381
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
382

    
383
  def _RunDowngradeUpgrade(self):
384
    oldconf = self._LoadConfig()
385
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
386
    _RunUpgrade(self.tmpdir, False, True)
387
    newconf = self._LoadConfig()
388
    self.assertEqual(oldconf, newconf)
389

    
390
  def testDowngrade(self):
391
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
392
    self._RunDowngradeUpgrade()
393

    
394
  def testDowngradeFullConfig(self):
395
    """Test for upgrade + downgrade combination."""
396
    # This test can work only with the previous version of a configuration!
397
    oldconfname = "cluster_config_2.10.json"
398
    self._TestUpgradeFromFile(oldconfname, False)
399
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
400
    oldconf = self._LoadTestDataConfig(oldconfname)
401
    newconf = self._LoadConfig()
402

    
403
    self.assertEqual(oldconf, newconf)
404

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

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

    
418
  def testDowngradeTwice(self):
419
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
420
    self._RunDowngradeTwice()
421

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

    
426
  def testUpgradeDryRunFrom_2_0(self):
427
    self._TestSimpleUpgrade(version.BuildVersion(2, 0, 0), True)
428

    
429
  def testUpgradeDryRunFrom_2_1(self):
430
    self._TestSimpleUpgrade(version.BuildVersion(2, 1, 0), True)
431

    
432
  def testUpgradeDryRunFrom_2_2(self):
433
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), True)
434

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

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

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

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

    
447
  def testUpgradeCurrentDryRun(self):
448
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, True)
449

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

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