4 # Copyright (C) 2010, 2012, 2013 Google Inc.
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.
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.
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
22 """Script for testing tools/cfgupgrade"""
31 from ganeti import constants
32 from ganeti import utils
33 from ganeti import serializer
34 from ganeti import netutils
39 def GetMinimalConfig():
41 "version": constants.CONFIG_VERSION,
43 "master_node": "node1-uuid"
56 def _RunUpgrade(path, dry_run, no_verify, ignore_hostname=True,
58 cmd = [sys.executable, "%s/tools/cfgupgrade" % testutils.GetSourceDir(),
59 "--debug", "--force", "--path=%s" % path, "--confdir=%s" % path]
62 cmd.append("--ignore-hostname")
64 cmd.append("--dry-run")
66 cmd.append("--no-verify")
68 cmd.append("--downgrade")
70 result = utils.RunCmd(cmd, cwd=os.getcwd())
72 raise Exception("cfgupgrade failed: %s, output %r" %
73 (result.fail_reason, result.output))
76 class TestCfgupgrade(unittest.TestCase):
78 self.tmpdir = tempfile.mkdtemp()
80 self.config_path = utils.PathJoin(self.tmpdir, "config.data")
81 self.noded_cert_path = utils.PathJoin(self.tmpdir, "server.pem")
82 self.rapi_cert_path = utils.PathJoin(self.tmpdir, "rapi.pem")
83 self.rapi_users_path = utils.PathJoin(self.tmpdir, "rapi", "users")
84 self.rapi_users_path_pre24 = utils.PathJoin(self.tmpdir, "rapi_users")
85 self.known_hosts_path = utils.PathJoin(self.tmpdir, "known_hosts")
86 self.confd_hmac_path = utils.PathJoin(self.tmpdir, "hmac.key")
87 self.cds_path = utils.PathJoin(self.tmpdir, "cluster-domain-secret")
88 self.ss_master_node_path = utils.PathJoin(self.tmpdir, "ssconf_master_node")
89 self.file_storage_paths = utils.PathJoin(self.tmpdir, "file-storage-paths")
92 shutil.rmtree(self.tmpdir)
94 def _LoadConfig(self):
95 return serializer.LoadJson(utils.ReadFile(self.config_path))
97 def _LoadTestDataConfig(self, filename):
98 return serializer.LoadJson(testutils.ReadTestData(filename))
100 def _CreateValidConfigDir(self):
101 utils.WriteFile(self.noded_cert_path, data="")
102 utils.WriteFile(self.known_hosts_path, data="")
103 utils.WriteFile(self.ss_master_node_path,
104 data="node.has.another.name.example.net")
106 def testNoConfigDir(self):
107 self.assertFalse(utils.ListVisibleFiles(self.tmpdir))
108 self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
109 self.assertRaises(Exception, _RunUpgrade, self.tmpdir, True, True)
111 def testWrongHostname(self):
112 self._CreateValidConfigDir()
114 utils.WriteFile(self.config_path,
115 data=serializer.DumpJson(GetMinimalConfig()))
117 hostname = netutils.GetHostname().name
118 assert hostname != utils.ReadOneLineFile(self.ss_master_node_path)
120 self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True,
121 ignore_hostname=False)
123 def testCorrectHostname(self):
124 self._CreateValidConfigDir()
126 utils.WriteFile(self.config_path,
127 data=serializer.DumpJson(GetMinimalConfig()))
129 utils.WriteFile(self.ss_master_node_path,
130 data="%s\n" % netutils.GetHostname().name)
132 _RunUpgrade(self.tmpdir, False, True, ignore_hostname=False)
134 def testInconsistentConfig(self):
135 self._CreateValidConfigDir()
136 # There should be no "config_version"
137 cfg = GetMinimalConfig()
139 cfg["cluster"]["config_version"] = 0
140 utils.WriteFile(self.config_path, data=serializer.DumpJson(cfg))
141 self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
143 def testInvalidConfig(self):
144 self._CreateValidConfigDir()
145 # Missing version from config
146 utils.WriteFile(self.config_path, data=serializer.DumpJson({}))
147 self.assertRaises(Exception, _RunUpgrade, self.tmpdir, False, True)
149 def _TestUpgradeFromFile(self, filename, dry_run):
150 cfg = self._LoadTestDataConfig(filename)
151 self._TestUpgradeFromData(cfg, dry_run)
153 def _TestSimpleUpgrade(self, from_version, dry_run,
154 file_storage_dir=None,
155 shared_file_storage_dir=None):
156 cfg = GetMinimalConfig()
157 cfg["version"] = from_version
158 cluster = cfg["cluster"]
161 cluster["file_storage_dir"] = file_storage_dir
162 if shared_file_storage_dir:
163 cluster["shared_file_storage_dir"] = shared_file_storage_dir
165 self._TestUpgradeFromData(cfg, dry_run)
167 def _TestUpgradeFromData(self, cfg, dry_run):
168 assert "version" in cfg
169 from_version = cfg["version"]
170 self._CreateValidConfigDir()
171 utils.WriteFile(self.config_path, data=serializer.DumpJson(cfg))
173 self.assertFalse(os.path.isfile(self.rapi_cert_path))
174 self.assertFalse(os.path.isfile(self.confd_hmac_path))
175 self.assertFalse(os.path.isfile(self.cds_path))
177 _RunUpgrade(self.tmpdir, dry_run, True)
180 expversion = from_version
181 checkfn = operator.not_
183 expversion = constants.CONFIG_VERSION
184 checkfn = operator.truth
186 self.assert_(checkfn(os.path.isfile(self.rapi_cert_path)))
187 self.assert_(checkfn(os.path.isfile(self.confd_hmac_path)))
188 self.assert_(checkfn(os.path.isfile(self.cds_path)))
190 newcfg = self._LoadConfig()
191 self.assertEqual(newcfg["version"], expversion)
193 def testRapiUsers(self):
194 self.assertFalse(os.path.exists(self.rapi_users_path))
195 self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
196 self.assertFalse(os.path.exists(os.path.dirname(self.rapi_users_path)))
198 utils.WriteFile(self.rapi_users_path_pre24, data="some user\n")
199 self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), False)
201 self.assertTrue(os.path.isdir(os.path.dirname(self.rapi_users_path)))
202 self.assert_(os.path.islink(self.rapi_users_path_pre24))
203 self.assert_(os.path.isfile(self.rapi_users_path))
204 self.assertEqual(os.readlink(self.rapi_users_path_pre24),
205 self.rapi_users_path)
206 for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
207 self.assertEqual(utils.ReadFile(path), "some user\n")
209 def testRapiUsers24AndAbove(self):
210 self.assertFalse(os.path.exists(self.rapi_users_path))
211 self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
213 os.mkdir(os.path.dirname(self.rapi_users_path))
214 utils.WriteFile(self.rapi_users_path, data="other user\n")
215 self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), False)
217 self.assert_(os.path.islink(self.rapi_users_path_pre24))
218 self.assert_(os.path.isfile(self.rapi_users_path))
219 self.assertEqual(os.readlink(self.rapi_users_path_pre24),
220 self.rapi_users_path)
221 for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
222 self.assertEqual(utils.ReadFile(path), "other user\n")
224 def testRapiUsersExistingSymlink(self):
225 self.assertFalse(os.path.exists(self.rapi_users_path))
226 self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
228 os.mkdir(os.path.dirname(self.rapi_users_path))
229 os.symlink(self.rapi_users_path, self.rapi_users_path_pre24)
230 utils.WriteFile(self.rapi_users_path, data="hello world\n")
232 self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), False)
234 self.assert_(os.path.isfile(self.rapi_users_path) and
235 not os.path.islink(self.rapi_users_path))
236 self.assert_(os.path.islink(self.rapi_users_path_pre24))
237 self.assertEqual(os.readlink(self.rapi_users_path_pre24),
238 self.rapi_users_path)
239 for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
240 self.assertEqual(utils.ReadFile(path), "hello world\n")
242 def testRapiUsersExistingTarget(self):
243 self.assertFalse(os.path.exists(self.rapi_users_path))
244 self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
246 os.mkdir(os.path.dirname(self.rapi_users_path))
247 utils.WriteFile(self.rapi_users_path, data="other user\n")
248 utils.WriteFile(self.rapi_users_path_pre24, data="hello world\n")
250 self.assertRaises(Exception, self._TestSimpleUpgrade,
251 constants.BuildVersion(2, 2, 0), False)
253 for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
254 self.assert_(os.path.isfile(path) and not os.path.islink(path))
255 self.assertEqual(utils.ReadFile(self.rapi_users_path), "other user\n")
256 self.assertEqual(utils.ReadFile(self.rapi_users_path_pre24),
259 def testRapiUsersDryRun(self):
260 self.assertFalse(os.path.exists(self.rapi_users_path))
261 self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
263 utils.WriteFile(self.rapi_users_path_pre24, data="some user\n")
264 self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
266 self.assertFalse(os.path.isdir(os.path.dirname(self.rapi_users_path)))
267 self.assertTrue(os.path.isfile(self.rapi_users_path_pre24) and
268 not os.path.islink(self.rapi_users_path_pre24))
269 self.assertFalse(os.path.exists(self.rapi_users_path))
271 def testRapiUsers24AndAboveDryRun(self):
272 self.assertFalse(os.path.exists(self.rapi_users_path))
273 self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
275 os.mkdir(os.path.dirname(self.rapi_users_path))
276 utils.WriteFile(self.rapi_users_path, data="other user\n")
277 self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
279 self.assertTrue(os.path.isfile(self.rapi_users_path) and
280 not os.path.islink(self.rapi_users_path))
281 self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
282 self.assertEqual(utils.ReadFile(self.rapi_users_path), "other user\n")
284 def testRapiUsersExistingSymlinkDryRun(self):
285 self.assertFalse(os.path.exists(self.rapi_users_path))
286 self.assertFalse(os.path.exists(self.rapi_users_path_pre24))
288 os.mkdir(os.path.dirname(self.rapi_users_path))
289 os.symlink(self.rapi_users_path, self.rapi_users_path_pre24)
290 utils.WriteFile(self.rapi_users_path, data="hello world\n")
292 self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), True)
294 self.assertTrue(os.path.islink(self.rapi_users_path_pre24))
295 self.assertTrue(os.path.isfile(self.rapi_users_path) and
296 not os.path.islink(self.rapi_users_path))
297 self.assertEqual(os.readlink(self.rapi_users_path_pre24),
298 self.rapi_users_path)
299 for path in [self.rapi_users_path, self.rapi_users_path_pre24]:
300 self.assertEqual(utils.ReadFile(path), "hello world\n")
302 def testFileStoragePathsDryRun(self):
303 self.assertFalse(os.path.exists(self.file_storage_paths))
305 self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), True,
306 file_storage_dir=self.tmpdir,
307 shared_file_storage_dir="/tmp")
309 self.assertFalse(os.path.exists(self.file_storage_paths))
311 def testFileStoragePathsBoth(self):
312 self.assertFalse(os.path.exists(self.file_storage_paths))
314 self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), False,
315 file_storage_dir=self.tmpdir,
316 shared_file_storage_dir="/tmp")
318 lines = utils.ReadFile(self.file_storage_paths).splitlines()
319 self.assertTrue(lines.pop(0).startswith("# "))
320 self.assertTrue(lines.pop(0).startswith("# cfgupgrade"))
321 self.assertEqual(lines.pop(0), self.tmpdir)
322 self.assertEqual(lines.pop(0), "/tmp")
323 self.assertFalse(lines)
324 self.assertEqual(os.stat(self.file_storage_paths).st_mode & 0777,
325 0600, msg="Wrong permissions")
327 def testFileStoragePathsSharedOnly(self):
328 self.assertFalse(os.path.exists(self.file_storage_paths))
330 self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), False,
331 file_storage_dir=None,
332 shared_file_storage_dir=self.tmpdir)
334 lines = utils.ReadFile(self.file_storage_paths).splitlines()
335 self.assertTrue(lines.pop(0).startswith("# "))
336 self.assertTrue(lines.pop(0).startswith("# cfgupgrade"))
337 self.assertEqual(lines.pop(0), self.tmpdir)
338 self.assertFalse(lines)
340 def testUpgradeFrom_2_0(self):
341 self._TestSimpleUpgrade(constants.BuildVersion(2, 0, 0), False)
343 def testUpgradeFrom_2_1(self):
344 self._TestSimpleUpgrade(constants.BuildVersion(2, 1, 0), False)
346 def testUpgradeFrom_2_2(self):
347 self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), False)
349 def testUpgradeFrom_2_3(self):
350 self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), False)
352 def testUpgradeFrom_2_4(self):
353 self._TestSimpleUpgrade(constants.BuildVersion(2, 4, 0), False)
355 def testUpgradeFrom_2_5(self):
356 self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), False)
358 def testUpgradeFrom_2_6(self):
359 self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), False)
361 def testUpgradeFrom_2_7(self):
362 self._TestSimpleUpgrade(constants.BuildVersion(2, 7, 0), False)
364 def testUpgradeFullConfigFrom_2_7(self):
365 self._TestUpgradeFromFile("cluster_config_2.7.json", False)
367 def testUpgradeFullConfigFrom_2_8(self):
368 self._TestUpgradeFromFile("cluster_config_2.8.json", False)
370 def testUpgradeCurrent(self):
371 self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
373 def _RunDowngradeUpgrade(self):
374 oldconf = self._LoadConfig()
375 _RunUpgrade(self.tmpdir, False, True, downgrade=True)
376 _RunUpgrade(self.tmpdir, False, True)
377 newconf = self._LoadConfig()
378 self.assertEqual(oldconf, newconf)
380 def testDowngrade(self):
381 self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
382 self._RunDowngradeUpgrade()
384 def testDowngradeFullConfig(self):
385 """Test for upgrade + downgrade combination."""
386 # This test can work only with the previous version of a configuration!
387 oldconfname = "cluster_config_2.8.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)
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()
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)
407 def testDowngradeTwice(self):
408 self._TestSimpleUpgrade(constants.CONFIG_VERSION, False)
409 self._RunDowngradeTwice()
411 def testDowngradeTwiceFullConfigFrom_2_7(self):
412 self._TestUpgradeFromFile("cluster_config_2.7.json", False)
413 self._RunDowngradeTwice()
415 def testUpgradeDryRunFrom_2_0(self):
416 self._TestSimpleUpgrade(constants.BuildVersion(2, 0, 0), True)
418 def testUpgradeDryRunFrom_2_1(self):
419 self._TestSimpleUpgrade(constants.BuildVersion(2, 1, 0), True)
421 def testUpgradeDryRunFrom_2_2(self):
422 self._TestSimpleUpgrade(constants.BuildVersion(2, 2, 0), True)
424 def testUpgradeDryRunFrom_2_3(self):
425 self._TestSimpleUpgrade(constants.BuildVersion(2, 3, 0), True)
427 def testUpgradeDryRunFrom_2_4(self):
428 self._TestSimpleUpgrade(constants.BuildVersion(2, 4, 0), True)
430 def testUpgradeDryRunFrom_2_5(self):
431 self._TestSimpleUpgrade(constants.BuildVersion(2, 5, 0), True)
433 def testUpgradeDryRunFrom_2_6(self):
434 self._TestSimpleUpgrade(constants.BuildVersion(2, 6, 0), True)
436 def testUpgradeCurrentDryRun(self):
437 self._TestSimpleUpgrade(constants.CONFIG_VERSION, True)
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"])
446 if __name__ == "__main__":
447 testutils.GanetiTestProgram()