Statistics
| Branch: | Tag: | Revision:

root / test / py / cfgupgrade_unittest.py @ 5275a77f

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

    
37
import testutils
38

    
39

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

    
58

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

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

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

    
78

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

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

    
94
  def tearDown(self):
95
    shutil.rmtree(self.tmpdir)
96

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

    
100
  def _LoadTestDataConfig(self, filename):
101
    return serializer.LoadJson(testutils.ReadTestData(filename))
102

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

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

    
114
  def testWrongHostname(self):
115
    self._CreateValidConfigDir()
116

    
117
    utils.WriteFile(self.config_path,
118
                    data=serializer.DumpJson(GetMinimalConfig()))
119

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

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

    
126
  def testCorrectHostname(self):
127
    self._CreateValidConfigDir()
128

    
129
    utils.WriteFile(self.config_path,
130
                    data=serializer.DumpJson(GetMinimalConfig()))
131

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

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

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

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

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

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

    
163
    if file_storage_dir:
164
      cluster["file_storage_dir"] = file_storage_dir
165
    if shared_file_storage_dir:
166
      cluster["shared_file_storage_dir"] = shared_file_storage_dir
167

    
168
    self._TestUpgradeFromData(cfg, dry_run)
169

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

    
176
    self.assertFalse(os.path.isfile(self.rapi_cert_path))
177
    self.assertFalse(os.path.isfile(self.confd_hmac_path))
178
    self.assertFalse(os.path.isfile(self.cds_path))
179

    
180
    _RunUpgrade(self.tmpdir, dry_run, True)
181

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

    
189
    self.assert_(checkfn(os.path.isfile(self.rapi_cert_path)))
190
    self.assert_(checkfn(os.path.isfile(self.confd_hmac_path)))
191
    self.assert_(checkfn(os.path.isfile(self.cds_path)))
192

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

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

    
201
    utils.WriteFile(self.rapi_users_path_pre24, data="some user\n")
202
    self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), False)
203

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

    
212
  def testRapiUsers24AndAbove(self):
213
    self.assertFalse(os.path.exists(self.rapi_users_path))
214
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
215

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

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

    
227
  def testRapiUsersExistingSymlink(self):
228
    self.assertFalse(os.path.exists(self.rapi_users_path))
229
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
230

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

    
235
    self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), False)
236

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

    
245
  def testRapiUsersExistingTarget(self):
246
    self.assertFalse(os.path.exists(self.rapi_users_path))
247
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
248

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

    
253
    self.assertRaises(Exception, self._TestSimpleUpgrade,
254
                      constants.BuildVersion(2, 2, 0), False)
255

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

    
262
  def testRapiUsersDryRun(self):
263
    self.assertFalse(os.path.exists(self.rapi_users_path))
264
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
265

    
266
    utils.WriteFile(self.rapi_users_path_pre24, data="some user\n")
267
    self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
268

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

    
274
  def testRapiUsers24AndAboveDryRun(self):
275
    self.assertFalse(os.path.exists(self.rapi_users_path))
276
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
277

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

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

    
287
  def testRapiUsersExistingSymlinkDryRun(self):
288
    self.assertFalse(os.path.exists(self.rapi_users_path))
289
    self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
290

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

    
295
    self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), True)
296

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

    
305
  def testFileStoragePathsDryRun(self):
306
    self.assertFalse(os.path.exists(self.file_storage_paths))
307

    
308
    self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), True,
309
                            file_storage_dir=self.tmpdir,
310
                            shared_file_storage_dir="/tmp")
311

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

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

    
317
    self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), False,
318
                            file_storage_dir=self.tmpdir,
319
                            shared_file_storage_dir="/tmp")
320

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

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

    
333
    self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), False,
334
                            file_storage_dir=None,
335
                            shared_file_storage_dir=self.tmpdir)
336

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

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

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

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

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

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

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

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

    
364
  def testUpgradeFrom_2_7(self):
365
    self._TestSimpleUpgrade(constants.BuildVersion(2, 7, 0), False)
366

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

    
370
  def testUpgradeFullConfigFrom_2_8(self):
371
    self._TestUpgradeFromFile("cluster_config_2.8.json", False)
372

    
373
  def testUpgradeCurrent(self):
374
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
375

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

    
383
  def testDowngrade(self):
384
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
385
    self._RunDowngradeUpgrade()
386

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

    
396
    # downgrade from 2.10 to 2.9 does not add physical_id to disks, which is ok
397
    for inst in oldconf["instances"].values():
398
      for disk in inst["disks"]:
399
        del disk["physical_id"]
400

    
401
    self.assertEqual(oldconf, newconf)
402

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

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

    
416
  def testDowngradeTwice(self):
417
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
418
    self._RunDowngradeTwice()
419

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

    
424
  def testUpgradeDryRunFrom_2_0(self):
425
    self._TestSimpleUpgrade(constants.BuildVersion(2, 0, 0), True)
426

    
427
  def testUpgradeDryRunFrom_2_1(self):
428
    self._TestSimpleUpgrade(constants.BuildVersion(2, 1, 0), True)
429

    
430
  def testUpgradeDryRunFrom_2_2(self):
431
    self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), True)
432

    
433
  def testUpgradeDryRunFrom_2_3(self):
434
    self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
435

    
436
  def testUpgradeDryRunFrom_2_4(self):
437
    self._TestSimpleUpgrade(constants.BuildVersion(2, 4, 0), True)
438

    
439
  def testUpgradeDryRunFrom_2_5(self):
440
    self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), True)
441

    
442
  def testUpgradeDryRunFrom_2_6(self):
443
    self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), True)
444

    
445
  def testUpgradeCurrentDryRun(self):
446
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, True)
447

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

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