Statistics
| Branch: | Tag: | Revision:

root / test / py / cfgupgrade_unittest.py @ 41044e04

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 _RunUpgrade(path, dry_run, no_verify, ignore_hostname=True,
41
                downgrade=False):
42
  cmd = [sys.executable, "%s/tools/cfgupgrade" % testutils.GetSourceDir(),
43
         "--debug", "--force", "--path=%s" % path, "--confdir=%s" % path]
44

    
45
  if ignore_hostname:
46
    cmd.append("--ignore-hostname")
47
  if dry_run:
48
    cmd.append("--dry-run")
49
  if no_verify:
50
    cmd.append("--no-verify")
51
  if downgrade:
52
    cmd.append("--downgrade")
53

    
54
  result = utils.RunCmd(cmd, cwd=os.getcwd())
55
  if result.failed:
56
    raise Exception("cfgupgrade failed: %s, output %r" %
57
                    (result.fail_reason, result.output))
58

    
59

    
60
class TestCfgupgrade(unittest.TestCase):
61
  def setUp(self):
62
    self.tmpdir = tempfile.mkdtemp()
63

    
64
    self.config_path = utils.PathJoin(self.tmpdir, "config.data")
65
    self.noded_cert_path = utils.PathJoin(self.tmpdir, "server.pem")
66
    self.rapi_cert_path = utils.PathJoin(self.tmpdir, "rapi.pem")
67
    self.rapi_users_path = utils.PathJoin(self.tmpdir, "rapi", "users")
68
    self.rapi_users_path_pre24 = utils.PathJoin(self.tmpdir, "rapi_users")
69
    self.known_hosts_path = utils.PathJoin(self.tmpdir, "known_hosts")
70
    self.confd_hmac_path = utils.PathJoin(self.tmpdir, "hmac.key")
71
    self.cds_path = utils.PathJoin(self.tmpdir, "cluster-domain-secret")
72
    self.ss_master_node_path = utils.PathJoin(self.tmpdir, "ssconf_master_node")
73
    self.file_storage_paths = utils.PathJoin(self.tmpdir, "file-storage-paths")
74

    
75
  def tearDown(self):
76
    shutil.rmtree(self.tmpdir)
77

    
78
  def _LoadConfig(self):
79
    return serializer.LoadJson(utils.ReadFile(self.config_path))
80

    
81
  def _LoadTestDataConfig(self, filename):
82
    return serializer.LoadJson(testutils.ReadTestData(filename))
83

    
84
  def _CreateValidConfigDir(self):
85
    utils.WriteFile(self.noded_cert_path, data="")
86
    utils.WriteFile(self.known_hosts_path, data="")
87
    utils.WriteFile(self.ss_master_node_path,
88
                    data="node.has.another.name.example.net")
89

    
90
  def testNoConfigDir(self):
91
    self.assertFalse(utils.ListVisibleFiles(self.tmpdir))
92
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
93
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, True, True)
94

    
95
  def testWrongHostname(self):
96
    self._CreateValidConfigDir()
97

    
98
    utils.WriteFile(self.config_path, data=serializer.DumpJson({
99
      "version": constants.CONFIG_VERSION,
100
      "cluster": {},
101
      "instances": {},
102
      "nodegroups": {},
103
      }))
104

    
105
    hostname = netutils.GetHostname().name
106
    assert hostname != utils.ReadOneLineFile(self.ss_master_node_path)
107

    
108
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True,
109
                      ignore_hostname=False)
110

    
111
  def testCorrectHostname(self):
112
    self._CreateValidConfigDir()
113

    
114
    utils.WriteFile(self.config_path, data=serializer.DumpJson({
115
      "version": constants.CONFIG_VERSION,
116
      "cluster": {},
117
      "instances": {},
118
      "nodegroups": {},
119
      }))
120

    
121
    utils.WriteFile(self.ss_master_node_path,
122
                    data="%s\n" % netutils.GetHostname().name)
123

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

    
126
  def testInconsistentConfig(self):
127
    self._CreateValidConfigDir()
128
    # There should be no "config_version"
129
    cfg = {
130
      "version": 0,
131
      "cluster": {
132
        "config_version": 0,
133
        },
134
      "instances": {},
135
      "nodegroups": {},
136
      }
137
    utils.WriteFile(self.config_path, data=serializer.DumpJson(cfg))
138
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
139

    
140
  def testInvalidConfig(self):
141
    self._CreateValidConfigDir()
142
    # Missing version from config
143
    utils.WriteFile(self.config_path, data=serializer.DumpJson({}))
144
    self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
145

    
146
  def _TestUpgradeFromFile(self, filename, dry_run):
147
    cfg = self._LoadTestDataConfig(filename)
148
    self._TestUpgradeFromData(cfg, dry_run)
149

    
150
  def _TestSimpleUpgrade(self, from_version, dry_run,
151
                         file_storage_dir=None,
152
                         shared_file_storage_dir=None):
153
    cluster = {}
154

    
155
    if file_storage_dir:
156
      cluster["file_storage_dir"] = file_storage_dir
157
    if shared_file_storage_dir:
158
      cluster["shared_file_storage_dir"] = shared_file_storage_dir
159

    
160
    cfg = {
161
      "version": from_version,
162
      "cluster": cluster,
163
      "instances": {},
164
      "nodegroups": {},
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 testUpgradeCurrent(self):
369
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
370

    
371
  def _RunDowngradeUpgrade(self):
372
    oldconf = self._LoadConfig()
373
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
374
    _RunUpgrade(self.tmpdir, False, True)
375
    newconf = self._LoadConfig()
376
    self.assertEqual(oldconf, newconf)
377

    
378
  def testDowngrade(self):
379
    self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
380
    self._RunDowngradeUpgrade()
381

    
382
  def testDowngradeFullConfig(self):
383
    """Test for upgrade + downgrade combination."""
384
    # This test can work only with the previous version of a configuration!
385
    # For 2.7, downgrading returns the original file only if group policies
386
    # don't override instance specs, so we need to use an ad-hoc configuration.
387
    oldconfname = "cluster_config_downgraded_2.7.json"
388
    self._TestUpgradeFromFile(oldconfname, False)
389
    _RunUpgrade(self.tmpdir, False, True, downgrade=True)
390
    oldconf = self._LoadTestDataConfig(oldconfname)
391
    newconf = self._LoadConfig()
392
    self.assertEqual(oldconf, newconf)
393

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

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

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

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

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

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

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

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

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

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

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

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

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

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