Statistics
| Branch: | Tag: | Revision:

root / test / py / cfgupgrade_unittest.py @ c777c5fc

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
import json
31

    
32
from ganeti import constants
33
from ganeti import utils
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
      "default_iallocator_params": {},
49
      "ndparams": {},
50
      "candidate_certs": {},
51
    },
52
    "instances": {},
53
    "networks": {},
54
    "nodegroups": {},
55
    "nodes": {
56
      "node1-uuid": {
57
        "name": "node1",
58
        "uuid": "node1-uuid"
59
      }
60
    },
61
  }
62

    
63

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

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

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

    
83

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
173
    self._TestUpgradeFromData(cfg, dry_run)
174

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
398
  def testDowngradeFullConfig(self):
399
    """Test for upgrade + downgrade combination."""
400
    # This test can work only with the previous version of a configuration!
401
    oldconfname = "cluster_config_2.11.json"
402
    self._TestUpgradeFromFile(oldconfname, False)
403
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
404
    oldconf = self._LoadTestDataConfig(oldconfname)
405
    newconf = self._LoadConfig()
406
    old = open('/tmp/old', 'w')
407
    old.write(json.dumps(oldconf))
408
    old.close()
409
    new = open('/tmp/new', 'w')
410
    new.write(json.dumps(newconf))
411
    new.close()
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()