Statistics
| Branch: | Tag: | Revision:

root / test / py / cfgupgrade_unittest.py @ c7a02959

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

    
59

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

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

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

    
79

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
169
    self._TestUpgradeFromData(cfg, dry_run)
170

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
236
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), False)
237

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

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

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

    
254
    self.assertRaises(Exception, self._TestSimpleUpgrade,
255
                      version.BuildVersion(2, 2, 0), False)
256

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

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

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

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

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

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

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

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

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

    
296
    self._TestSimpleUpgrade(version.BuildVersion(2, 2, 0), True)
297

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

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

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

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

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

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

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

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

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

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

    
344
  def testUpgradeFrom_2_0(self):
345
    self._TestSimpleUpgrade(version.BuildVersion(2, 0, 0), False)
346

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

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

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

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

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

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

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

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

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

    
374
  def testUpgradeFullConfigFrom_2_9(self):
375
    self._TestUpgradeFromFile("cluster_config_2.9.json", False)
376

    
377
  def testUpgradeCurrent(self):
378
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
379

    
380
  def _RunDowngradeUpgrade(self):
381
    oldconf = self._LoadConfig()
382
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
383
    _RunUpgrade(self.tmpdir, False, True)
384
    newconf = self._LoadConfig()
385
    self.assertEqual(oldconf, newconf)
386

    
387
  def testDowngrade(self):
388
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
389
    self._RunDowngradeUpgrade()
390

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

    
400
    self.assertEqual(oldconf, newconf)
401

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

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

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

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

    
423
  def testUpgradeDryRunFrom_2_0(self):
424
    self._TestSimpleUpgrade(version.BuildVersion(2, 0, 0), True)
425

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

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

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

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

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

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

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

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

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