Statistics
| Branch: | Tag: | Revision:

root / test / py / cfgupgrade_unittest.py @ b555101c

History | View | Annotate | Download (16.6 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
    },
46
    "instances": {},
47
    "nodegroups": {},
48
    "nodes": {
49
      "node1-uuid": {
50
        "name": "node1",
51
        "uuid": "node1-uuid"
52
      }
53
    },
54
  }
55

    
56

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

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

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

    
76

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
166
    self._TestUpgradeFromData(cfg, dry_run)
167

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
400
  def _RunDowngradeTwice(self):
401
    """Make sure that downgrade is idempotent."""
402
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
403
    oldconf = self._LoadConfig()
404
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
405
    newconf = self._LoadConfig()
406
    self.assertEqual(oldconf, newconf)
407

    
408
  def testDowngradeTwice(self):
409
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
410
    self._RunDowngradeTwice()
411

    
412
  def testDowngradeTwiceFullConfigFrom_2_7(self):
413
    self._TestUpgradeFromFile("cluster_config_2.7.json", False)
414
    self._RunDowngradeTwice()
415

    
416
  def testUpgradeDryRunFrom_2_0(self):
417
    self._TestSimpleUpgrade(constants.BuildVersion(2, 0, 0), True)
418

    
419
  def testUpgradeDryRunFrom_2_1(self):
420
    self._TestSimpleUpgrade(constants.BuildVersion(2, 1, 0), True)
421

    
422
  def testUpgradeDryRunFrom_2_2(self):
423
    self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), True)
424

    
425
  def testUpgradeDryRunFrom_2_3(self):
426
    self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
427

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

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

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

    
437
  def testUpgradeCurrentDryRun(self):
438
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, True)
439

    
440
  def testDowngradeDryRun(self):
441
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
442
    oldconf = self._LoadConfig()
443
    _RunUpgrade(self.tmpdir, True, True, downgrade=True)
444
    newconf = self._LoadConfig()
445
    self.assertEqual(oldconf["version"], newconf["version"])
446

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