Statistics
| Branch: | Tag: | Revision:

root / qa / ganeti-qa.py @ f9b76ed4

History | View | Annotate | Download (30 kB)

1 f89d59b9 Iustin Pop
#!/usr/bin/python -u
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 50ef6a41 Bernardo Dal Seno
# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 cec9845c Michael Hanselmann
"""Script for doing QA on Ganeti.
23 94508060 Michael Hanselmann

24 94508060 Michael Hanselmann
"""
25 a8083063 Iustin Pop
26 b459a848 Andrea Spadaccini
# pylint: disable=C0103
27 3582eef6 Iustin Pop
# due to invalid name
28 3582eef6 Iustin Pop
29 5fdf8491 Bernardo Dal Seno
import copy
30 c68d1f43 Michael Hanselmann
import datetime
31 c68d1f43 Michael Hanselmann
import optparse
32 5fdf8491 Bernardo Dal Seno
import sys
33 a8083063 Iustin Pop
34 cec9845c Michael Hanselmann
import qa_cluster
35 cec9845c Michael Hanselmann
import qa_config
36 cec9845c Michael Hanselmann
import qa_daemon
37 cec9845c Michael Hanselmann
import qa_env
38 83180411 Bernardo Dal Seno
import qa_error
39 30131294 Adeodato Simo
import qa_group
40 cec9845c Michael Hanselmann
import qa_instance
41 a5877534 Michele Tartara
import qa_monitoring
42 ea7693c1 Helga Velroyen
import qa_network
43 cec9845c Michael Hanselmann
import qa_node
44 8947cf2b Michael Hanselmann
import qa_os
45 09470dd8 Michael Hanselmann
import qa_job
46 a47f574c Oleksiy Mishchenko
import qa_rapi
47 d74c2ca1 Michael Hanselmann
import qa_tags
48 1672a0d1 Michael Hanselmann
import qa_utils
49 a8083063 Iustin Pop
50 725ec2f1 René Nussbaumer
from ganeti import utils
51 8ad0da1e Iustin Pop
from ganeti import rapi # pylint: disable=W0611
52 f3fd2c9d Adeodato Simo
from ganeti import constants
53 35ff270b Bernardo Dal Seno
from ganeti import pathutils
54 2a7c3583 Michael Hanselmann
55 35ff270b Bernardo Dal Seno
from ganeti.http.auth import ParsePasswordFile
56 b459a848 Andrea Spadaccini
import ganeti.rapi.client # pylint: disable=W0611
57 fc3f75dd Iustin Pop
from ganeti.rapi.client import UsesRapiClient
58 725ec2f1 René Nussbaumer
59 a8083063 Iustin Pop
60 7d88f255 Iustin Pop
def _FormatHeader(line, end=72):
61 f89d59b9 Iustin Pop
  """Fill a line up to the end column.
62 f89d59b9 Iustin Pop

63 f89d59b9 Iustin Pop
  """
64 f89d59b9 Iustin Pop
  line = "---- " + line + " "
65 21bf2e2e Andrea Spadaccini
  line += "-" * (end - len(line))
66 f89d59b9 Iustin Pop
  line = line.rstrip()
67 f89d59b9 Iustin Pop
  return line
68 f89d59b9 Iustin Pop
69 f89d59b9 Iustin Pop
70 7d88f255 Iustin Pop
def _DescriptionOf(fn):
71 7d88f255 Iustin Pop
  """Computes the description of an item.
72 a8083063 Iustin Pop

73 a8083063 Iustin Pop
  """
74 cec9845c Michael Hanselmann
  if fn.__doc__:
75 cec9845c Michael Hanselmann
    desc = fn.__doc__.splitlines()[0].strip()
76 a8083063 Iustin Pop
  else:
77 f89d59b9 Iustin Pop
    desc = "%r" % fn
78 a8083063 Iustin Pop
79 7d88f255 Iustin Pop
  return desc.rstrip(".")
80 7d88f255 Iustin Pop
81 2932dc44 Michael Hanselmann
82 741c6d91 Michael Hanselmann
def RunTest(fn, *args, **kwargs):
83 7d88f255 Iustin Pop
  """Runs a test after printing a header.
84 7d88f255 Iustin Pop

85 7d88f255 Iustin Pop
  """
86 a8083063 Iustin Pop
87 f89d59b9 Iustin Pop
  tstart = datetime.datetime.now()
88 a8083063 Iustin Pop
89 7d88f255 Iustin Pop
  desc = _DescriptionOf(fn)
90 7d88f255 Iustin Pop
91 f89d59b9 Iustin Pop
  print
92 f89d59b9 Iustin Pop
  print _FormatHeader("%s start %s" % (tstart, desc))
93 f89d59b9 Iustin Pop
94 f89d59b9 Iustin Pop
  try:
95 741c6d91 Michael Hanselmann
    retval = fn(*args, **kwargs)
96 f89d59b9 Iustin Pop
    return retval
97 f89d59b9 Iustin Pop
  finally:
98 f89d59b9 Iustin Pop
    tstop = datetime.datetime.now()
99 f89d59b9 Iustin Pop
    tdelta = tstop - tstart
100 f89d59b9 Iustin Pop
    print _FormatHeader("%s time=%s %s" % (tstop, tdelta, desc))
101 a8083063 Iustin Pop
102 a8083063 Iustin Pop
103 741c6d91 Michael Hanselmann
def RunTestIf(testnames, fn, *args, **kwargs):
104 7d88f255 Iustin Pop
  """Runs a test conditionally.
105 7d88f255 Iustin Pop

106 7d88f255 Iustin Pop
  @param testnames: either a single test name in the configuration
107 7d88f255 Iustin Pop
      file, or a list of testnames (which will be AND-ed together)
108 7d88f255 Iustin Pop

109 7d88f255 Iustin Pop
  """
110 7d88f255 Iustin Pop
  if qa_config.TestEnabled(testnames):
111 741c6d91 Michael Hanselmann
    RunTest(fn, *args, **kwargs)
112 7d88f255 Iustin Pop
  else:
113 7d88f255 Iustin Pop
    tstart = datetime.datetime.now()
114 7d88f255 Iustin Pop
    desc = _DescriptionOf(fn)
115 c072e788 Michael Hanselmann
    # TODO: Formatting test names when non-string names are involved
116 7d88f255 Iustin Pop
    print _FormatHeader("%s skipping %s, test(s) %s disabled" %
117 7d88f255 Iustin Pop
                        (tstart, desc, testnames))
118 7d88f255 Iustin Pop
119 7d88f255 Iustin Pop
120 b1ffe1eb Michael Hanselmann
def RunEnvTests():
121 b1ffe1eb Michael Hanselmann
  """Run several environment tests.
122 a8083063 Iustin Pop

123 a8083063 Iustin Pop
  """
124 7d88f255 Iustin Pop
  RunTestIf("env", qa_env.TestSshConnection)
125 7d88f255 Iustin Pop
  RunTestIf("env", qa_env.TestIcmpPing)
126 7d88f255 Iustin Pop
  RunTestIf("env", qa_env.TestGanetiCommands)
127 a8083063 Iustin Pop
128 94508060 Michael Hanselmann
129 35ff270b Bernardo Dal Seno
def _LookupRapiSecret(rapi_user):
130 35ff270b Bernardo Dal Seno
  """Find the RAPI secret for the given user.
131 35ff270b Bernardo Dal Seno

132 35ff270b Bernardo Dal Seno
  @param rapi_user: Login user
133 35ff270b Bernardo Dal Seno
  @return: Login secret for the user
134 35ff270b Bernardo Dal Seno

135 35ff270b Bernardo Dal Seno
  """
136 35ff270b Bernardo Dal Seno
  CTEXT = "{CLEARTEXT}"
137 35ff270b Bernardo Dal Seno
  master = qa_config.GetMasterNode()
138 35ff270b Bernardo Dal Seno
  cmd = ["cat", qa_utils.MakeNodePath(master, pathutils.RAPI_USERS_FILE)]
139 35ff270b Bernardo Dal Seno
  file_content = qa_utils.GetCommandOutput(master.primary,
140 35ff270b Bernardo Dal Seno
                                           utils.ShellQuoteArgs(cmd))
141 35ff270b Bernardo Dal Seno
  users = ParsePasswordFile(file_content)
142 35ff270b Bernardo Dal Seno
  entry = users.get(rapi_user)
143 35ff270b Bernardo Dal Seno
  if not entry:
144 35ff270b Bernardo Dal Seno
    raise qa_error.Error("User %s not found in RAPI users file" % rapi_user)
145 35ff270b Bernardo Dal Seno
  secret = entry.password
146 35ff270b Bernardo Dal Seno
  if secret.upper().startswith(CTEXT):
147 35ff270b Bernardo Dal Seno
    secret = secret[len(CTEXT):]
148 35ff270b Bernardo Dal Seno
  elif secret.startswith("{"):
149 35ff270b Bernardo Dal Seno
    raise qa_error.Error("Unsupported password schema for RAPI user %s:"
150 35ff270b Bernardo Dal Seno
                         " not a clear text password" % rapi_user)
151 35ff270b Bernardo Dal Seno
  return secret
152 35ff270b Bernardo Dal Seno
153 35ff270b Bernardo Dal Seno
154 35ff270b Bernardo Dal Seno
def SetupCluster(rapi_user):
155 b1ffe1eb Michael Hanselmann
  """Initializes the cluster.
156 a8083063 Iustin Pop

157 725ec2f1 René Nussbaumer
  @param rapi_user: Login user for RAPI
158 35ff270b Bernardo Dal Seno
  @return: Login secret for RAPI
159 725ec2f1 René Nussbaumer

160 b1ffe1eb Michael Hanselmann
  """
161 35ff270b Bernardo Dal Seno
  rapi_secret = utils.GenerateSecret()
162 7d88f255 Iustin Pop
  RunTestIf("create-cluster", qa_cluster.TestClusterInit,
163 7d88f255 Iustin Pop
            rapi_user, rapi_secret)
164 6a0f22e1 Bernardo Dal Seno
  if not qa_config.TestEnabled("create-cluster"):
165 6a0f22e1 Bernardo Dal Seno
    # If the cluster is already in place, we assume that exclusive-storage is
166 6a0f22e1 Bernardo Dal Seno
    # already set according to the configuration
167 6a0f22e1 Bernardo Dal Seno
    qa_config.SetExclusiveStorage(qa_config.get("exclusive-storage", False))
168 35ff270b Bernardo Dal Seno
    if qa_rapi.Enabled():
169 35ff270b Bernardo Dal Seno
      # To support RAPI on an existing cluster we have to find out the secret
170 35ff270b Bernardo Dal Seno
      rapi_secret = _LookupRapiSecret(rapi_user)
171 288d6440 Michael Hanselmann
172 288d6440 Michael Hanselmann
  # Test on empty cluster
173 288d6440 Michael Hanselmann
  RunTestIf("node-list", qa_node.TestNodeList)
174 288d6440 Michael Hanselmann
  RunTestIf("instance-list", qa_instance.TestInstanceList)
175 09470dd8 Michael Hanselmann
  RunTestIf("job-list", qa_job.TestJobList)
176 288d6440 Michael Hanselmann
177 7d88f255 Iustin Pop
  RunTestIf("create-cluster", qa_node.TestNodeAddAll)
178 7d88f255 Iustin Pop
  if not qa_config.TestEnabled("create-cluster"):
179 8e671b7c Iustin Pop
    # consider the nodes are already there
180 8e671b7c Iustin Pop
    qa_node.MarkNodeAddedAll()
181 8201b996 Iustin Pop
182 7d88f255 Iustin Pop
  RunTestIf("test-jobqueue", qa_cluster.TestJobqueue)
183 cd04f8c2 Michael Hanselmann
184 8201b996 Iustin Pop
  # enable the watcher (unconditionally)
185 8201b996 Iustin Pop
  RunTest(qa_daemon.TestResumeWatcher)
186 8201b996 Iustin Pop
187 288d6440 Michael Hanselmann
  RunTestIf("node-list", qa_node.TestNodeList)
188 288d6440 Michael Hanselmann
189 2214cf14 Michael Hanselmann
  # Test listing fields
190 2214cf14 Michael Hanselmann
  RunTestIf("node-list", qa_node.TestNodeListFields)
191 2214cf14 Michael Hanselmann
  RunTestIf("instance-list", qa_instance.TestInstanceListFields)
192 09470dd8 Michael Hanselmann
  RunTestIf("job-list", qa_job.TestJobListFields)
193 0fdf247d Michael Hanselmann
  RunTestIf("instance-export", qa_instance.TestBackupListFields)
194 2214cf14 Michael Hanselmann
195 7d88f255 Iustin Pop
  RunTestIf("node-info", qa_node.TestNodeInfo)
196 b1ffe1eb Michael Hanselmann
197 35ff270b Bernardo Dal Seno
  return rapi_secret
198 35ff270b Bernardo Dal Seno
199 b1ffe1eb Michael Hanselmann
200 b1ffe1eb Michael Hanselmann
def RunClusterTests():
201 b1ffe1eb Michael Hanselmann
  """Runs tests related to gnt-cluster.
202 180bdd1f Michael Hanselmann

203 b1ffe1eb Michael Hanselmann
  """
204 7d88f255 Iustin Pop
  for test, fn in [
205 92cb4940 Andrea Spadaccini
    ("create-cluster", qa_cluster.TestClusterInitDisk),
206 7d88f255 Iustin Pop
    ("cluster-renew-crypto", qa_cluster.TestClusterRenewCrypto),
207 7d88f255 Iustin Pop
    ("cluster-verify", qa_cluster.TestClusterVerify),
208 7d88f255 Iustin Pop
    ("cluster-reserved-lvs", qa_cluster.TestClusterReservedLvs),
209 9738ca94 Iustin Pop
    # TODO: add more cluster modify tests
210 1e7acc3b Iustin Pop
    ("cluster-modify", qa_cluster.TestClusterModifyEmpty),
211 b3f3aa3d Bernardo Dal Seno
    ("cluster-modify", qa_cluster.TestClusterModifyIPolicy),
212 b3f3aa3d Bernardo Dal Seno
    ("cluster-modify", qa_cluster.TestClusterModifyISpecs),
213 7d88f255 Iustin Pop
    ("cluster-modify", qa_cluster.TestClusterModifyBe),
214 92cb4940 Andrea Spadaccini
    ("cluster-modify", qa_cluster.TestClusterModifyDisk),
215 2dae8d64 Helga Velroyen
    ("cluster-modify", qa_cluster.TestClusterModifyDiskTemplates),
216 7d88f255 Iustin Pop
    ("cluster-rename", qa_cluster.TestClusterRename),
217 7d88f255 Iustin Pop
    ("cluster-info", qa_cluster.TestClusterVersion),
218 7d88f255 Iustin Pop
    ("cluster-info", qa_cluster.TestClusterInfo),
219 7d88f255 Iustin Pop
    ("cluster-info", qa_cluster.TestClusterGetmaster),
220 3e8b5a9c Iustin Pop
    ("cluster-redist-conf", qa_cluster.TestClusterRedistConf),
221 db41409c Michael Hanselmann
    (["cluster-copyfile", qa_config.NoVirtualCluster],
222 db41409c Michael Hanselmann
     qa_cluster.TestClusterCopyfile),
223 7d88f255 Iustin Pop
    ("cluster-command", qa_cluster.TestClusterCommand),
224 7d88f255 Iustin Pop
    ("cluster-burnin", qa_cluster.TestClusterBurnin),
225 7d88f255 Iustin Pop
    ("cluster-master-failover", qa_cluster.TestClusterMasterFailover),
226 ff699aa9 Michael Hanselmann
    ("cluster-master-failover",
227 ff699aa9 Michael Hanselmann
     qa_cluster.TestClusterMasterFailoverWithDrainedQueue),
228 c0464536 Michael Hanselmann
    (["cluster-oob", qa_config.NoVirtualCluster],
229 c0464536 Michael Hanselmann
     qa_cluster.TestClusterOob),
230 301adaae Michael Hanselmann
    (qa_rapi.Enabled, qa_rapi.TestVersion),
231 301adaae Michael Hanselmann
    (qa_rapi.Enabled, qa_rapi.TestEmptyCluster),
232 301adaae Michael Hanselmann
    (qa_rapi.Enabled, qa_rapi.TestRapiQuery),
233 7d88f255 Iustin Pop
    ]:
234 7d88f255 Iustin Pop
    RunTestIf(test, fn)
235 8947cf2b Michael Hanselmann
236 6d4a1656 Michael Hanselmann
237 65a884ef Iustin Pop
def RunRepairDiskSizes():
238 65a884ef Iustin Pop
  """Run the repair disk-sizes test.
239 65a884ef Iustin Pop

240 65a884ef Iustin Pop
  """
241 65a884ef Iustin Pop
  RunTestIf("cluster-repair-disk-sizes", qa_cluster.TestClusterRepairDiskSizes)
242 65a884ef Iustin Pop
243 65a884ef Iustin Pop
244 b1ffe1eb Michael Hanselmann
def RunOsTests():
245 b1ffe1eb Michael Hanselmann
  """Runs all tests related to gnt-os.
246 5d640672 Michael Hanselmann

247 b1ffe1eb Michael Hanselmann
  """
248 c9cf3f1a Michael Hanselmann
  os_enabled = ["os", qa_config.NoVirtualCluster]
249 c9cf3f1a Michael Hanselmann
250 301adaae Michael Hanselmann
  if qa_config.TestEnabled(qa_rapi.Enabled):
251 2932dc44 Michael Hanselmann
    rapi_getos = qa_rapi.GetOperatingSystems
252 2932dc44 Michael Hanselmann
  else:
253 2932dc44 Michael Hanselmann
    rapi_getos = None
254 2932dc44 Michael Hanselmann
255 7d88f255 Iustin Pop
  for fn in [
256 7d88f255 Iustin Pop
    qa_os.TestOsList,
257 7d88f255 Iustin Pop
    qa_os.TestOsDiagnose,
258 2932dc44 Michael Hanselmann
    ]:
259 c9cf3f1a Michael Hanselmann
    RunTestIf(os_enabled, fn)
260 2932dc44 Michael Hanselmann
261 2932dc44 Michael Hanselmann
  for fn in [
262 7d88f255 Iustin Pop
    qa_os.TestOsValid,
263 7d88f255 Iustin Pop
    qa_os.TestOsInvalid,
264 7d88f255 Iustin Pop
    qa_os.TestOsPartiallyValid,
265 2932dc44 Michael Hanselmann
    ]:
266 c9cf3f1a Michael Hanselmann
    RunTestIf(os_enabled, fn, rapi_getos)
267 2932dc44 Michael Hanselmann
268 2932dc44 Michael Hanselmann
  for fn in [
269 7d88f255 Iustin Pop
    qa_os.TestOsModifyValid,
270 7d88f255 Iustin Pop
    qa_os.TestOsModifyInvalid,
271 074e139f Michael Hanselmann
    qa_os.TestOsStatesNonExisting,
272 7d88f255 Iustin Pop
    ]:
273 c9cf3f1a Michael Hanselmann
    RunTestIf(os_enabled, fn)
274 b1ffe1eb Michael Hanselmann
275 b1ffe1eb Michael Hanselmann
276 7af293d7 Thomas Thrainer
def RunCommonInstanceTests(instance, inst_nodes):
277 b1ffe1eb Michael Hanselmann
  """Runs a few tests that are common to all disk types.
278 b1ffe1eb Michael Hanselmann

279 b1ffe1eb Michael Hanselmann
  """
280 7d88f255 Iustin Pop
  RunTestIf("instance-shutdown", qa_instance.TestInstanceShutdown, instance)
281 301adaae Michael Hanselmann
  RunTestIf(["instance-shutdown", "instance-console", qa_rapi.Enabled],
282 b82d4c5e Michael Hanselmann
            qa_rapi.TestRapiStoppedInstanceConsole, instance)
283 3016bc1f Michael Hanselmann
  RunTestIf(["instance-shutdown", "instance-modify"],
284 3016bc1f Michael Hanselmann
            qa_instance.TestInstanceStoppedModify, instance)
285 7d88f255 Iustin Pop
  RunTestIf("instance-shutdown", qa_instance.TestInstanceStartup, instance)
286 a8083063 Iustin Pop
287 a7418448 Michael Hanselmann
  # Test shutdown/start via RAPI
288 301adaae Michael Hanselmann
  RunTestIf(["instance-shutdown", qa_rapi.Enabled],
289 a7418448 Michael Hanselmann
            qa_rapi.TestRapiInstanceShutdown, instance)
290 301adaae Michael Hanselmann
  RunTestIf(["instance-shutdown", qa_rapi.Enabled],
291 a7418448 Michael Hanselmann
            qa_rapi.TestRapiInstanceStartup, instance)
292 a7418448 Michael Hanselmann
293 7d88f255 Iustin Pop
  RunTestIf("instance-list", qa_instance.TestInstanceList)
294 283f9d4c Michael Hanselmann
295 7d88f255 Iustin Pop
  RunTestIf("instance-info", qa_instance.TestInstanceInfo, instance)
296 e9e35aaa Michael Hanselmann
297 7d88f255 Iustin Pop
  RunTestIf("instance-modify", qa_instance.TestInstanceModify, instance)
298 301adaae Michael Hanselmann
  RunTestIf(["instance-modify", qa_rapi.Enabled],
299 7d88f255 Iustin Pop
            qa_rapi.TestRapiInstanceModify, instance)
300 c0f74c55 Iustin Pop
301 7d88f255 Iustin Pop
  RunTestIf("instance-console", qa_instance.TestInstanceConsole, instance)
302 301adaae Michael Hanselmann
  RunTestIf(["instance-console", qa_rapi.Enabled],
303 b82d4c5e Michael Hanselmann
            qa_rapi.TestRapiInstanceConsole, instance)
304 4379b1fa Michael Hanselmann
305 090128b6 Christos Stavrakakis
  RunTestIf("instance-device-names", qa_instance.TestInstanceDeviceNames,
306 090128b6 Christos Stavrakakis
            instance)
307 1be35bef Michael Hanselmann
  DOWN_TESTS = qa_config.Either([
308 1be35bef Michael Hanselmann
    "instance-reinstall",
309 1be35bef Michael Hanselmann
    "instance-rename",
310 1be35bef Michael Hanselmann
    "instance-grow-disk",
311 1be35bef Michael Hanselmann
    ])
312 1be35bef Michael Hanselmann
313 4c1a464b Iustin Pop
  # shutdown instance for any 'down' tests
314 4c1a464b Iustin Pop
  RunTestIf(DOWN_TESTS, qa_instance.TestInstanceShutdown, instance)
315 4c1a464b Iustin Pop
316 4c1a464b Iustin Pop
  # now run the 'down' state tests
317 7d88f255 Iustin Pop
  RunTestIf("instance-reinstall", qa_instance.TestInstanceReinstall, instance)
318 301adaae Michael Hanselmann
  RunTestIf(["instance-reinstall", qa_rapi.Enabled],
319 0220d2cf Guido Trotter
            qa_rapi.TestRapiInstanceReinstall, instance)
320 8a4e8898 Michael Hanselmann
321 d0c8c01d Iustin Pop
  if qa_config.TestEnabled("instance-rename"):
322 69bc7a38 Michael Hanselmann
    tgt_instance = qa_config.AcquireInstance()
323 69bc7a38 Michael Hanselmann
    try:
324 b5f33afa Michael Hanselmann
      rename_source = instance.name
325 b5f33afa Michael Hanselmann
      rename_target = tgt_instance.name
326 69bc7a38 Michael Hanselmann
      # perform instance rename to the same name
327 4c1a464b Iustin Pop
      RunTest(qa_instance.TestInstanceRenameAndBack,
328 69bc7a38 Michael Hanselmann
              rename_source, rename_source)
329 301adaae Michael Hanselmann
      RunTestIf(qa_rapi.Enabled, qa_rapi.TestRapiInstanceRenameAndBack,
330 69bc7a38 Michael Hanselmann
                rename_source, rename_source)
331 69bc7a38 Michael Hanselmann
      if rename_target is not None:
332 69bc7a38 Michael Hanselmann
        # perform instance rename to a different name, if we have one configured
333 69bc7a38 Michael Hanselmann
        RunTest(qa_instance.TestInstanceRenameAndBack,
334 930e77d1 Michael Hanselmann
                rename_source, rename_target)
335 301adaae Michael Hanselmann
        RunTestIf(qa_rapi.Enabled, qa_rapi.TestRapiInstanceRenameAndBack,
336 69bc7a38 Michael Hanselmann
                  rename_source, rename_target)
337 69bc7a38 Michael Hanselmann
    finally:
338 6f88e076 Michael Hanselmann
      tgt_instance.Release()
339 4c1a464b Iustin Pop
340 26a5056d Iustin Pop
  RunTestIf(["instance-grow-disk"], qa_instance.TestInstanceGrowDisk, instance)
341 26a5056d Iustin Pop
342 4c1a464b Iustin Pop
  # and now start the instance again
343 4c1a464b Iustin Pop
  RunTestIf(DOWN_TESTS, qa_instance.TestInstanceStartup, instance)
344 4c1a464b Iustin Pop
345 4c1a464b Iustin Pop
  RunTestIf("instance-reboot", qa_instance.TestInstanceReboot, instance)
346 18337ca9 Iustin Pop
347 7d88f255 Iustin Pop
  RunTestIf("tags", qa_tags.TestInstanceTags, instance)
348 d74c2ca1 Michael Hanselmann
349 7af293d7 Thomas Thrainer
  if instance.disk_template == constants.DT_DRBD8:
350 7af293d7 Thomas Thrainer
    RunTestIf("cluster-verify",
351 7af293d7 Thomas Thrainer
              qa_cluster.TestClusterVerifyDisksBrokenDRBD, instance, inst_nodes)
352 1ef6e776 Michael Hanselmann
  RunTestIf("cluster-verify", qa_cluster.TestClusterVerify)
353 d74c2ca1 Michael Hanselmann
354 301adaae Michael Hanselmann
  RunTestIf(qa_rapi.Enabled, qa_rapi.TestInstance, instance)
355 729c4377 Iustin Pop
356 288d6440 Michael Hanselmann
  # Lists instances, too
357 288d6440 Michael Hanselmann
  RunTestIf("node-list", qa_node.TestNodeList)
358 288d6440 Michael Hanselmann
359 09470dd8 Michael Hanselmann
  # Some jobs have been run, let's test listing them
360 09470dd8 Michael Hanselmann
  RunTestIf("job-list", qa_job.TestJobList)
361 09470dd8 Michael Hanselmann
362 729c4377 Iustin Pop
363 729c4377 Iustin Pop
def RunCommonNodeTests():
364 729c4377 Iustin Pop
  """Run a few common node tests.
365 729c4377 Iustin Pop

366 729c4377 Iustin Pop
  """
367 7d88f255 Iustin Pop
  RunTestIf("node-volumes", qa_node.TestNodeVolumes)
368 7d88f255 Iustin Pop
  RunTestIf("node-storage", qa_node.TestNodeStorage)
369 c0464536 Michael Hanselmann
  RunTestIf(["node-oob", qa_config.NoVirtualCluster], qa_node.TestOutOfBand)
370 8e1db003 Michael Hanselmann
371 8d8d650c Michael Hanselmann
372 30131294 Adeodato Simo
def RunGroupListTests():
373 30131294 Adeodato Simo
  """Run tests for listing node groups.
374 30131294 Adeodato Simo

375 30131294 Adeodato Simo
  """
376 7ab8b7d7 Adeodato Simo
  RunTestIf("group-list", qa_group.TestGroupList)
377 7ab8b7d7 Adeodato Simo
  RunTestIf("group-list", qa_group.TestGroupListFields)
378 30131294 Adeodato Simo
379 30131294 Adeodato Simo
380 ea7693c1 Helga Velroyen
def RunNetworkTests():
381 ea7693c1 Helga Velroyen
  """Run tests for network management.
382 ea7693c1 Helga Velroyen

383 ea7693c1 Helga Velroyen
  """
384 ea7693c1 Helga Velroyen
  RunTestIf("network", qa_network.TestNetworkAddRemove)
385 ea7693c1 Helga Velroyen
  RunTestIf("network", qa_network.TestNetworkConnect)
386 ea7693c1 Helga Velroyen
387 ea7693c1 Helga Velroyen
388 66787da5 Adeodato Simo
def RunGroupRwTests():
389 66787da5 Adeodato Simo
  """Run tests for adding/removing/renaming groups.
390 66787da5 Adeodato Simo

391 66787da5 Adeodato Simo
  """
392 66787da5 Adeodato Simo
  RunTestIf("group-rwops", qa_group.TestGroupAddRemoveRename)
393 4b10fb65 Adeodato Simo
  RunTestIf("group-rwops", qa_group.TestGroupAddWithOptions)
394 4b10fb65 Adeodato Simo
  RunTestIf("group-rwops", qa_group.TestGroupModify)
395 301adaae Michael Hanselmann
  RunTestIf(["group-rwops", qa_rapi.Enabled], qa_rapi.TestRapiNodeGroups)
396 fe508a9d Michael Hanselmann
  RunTestIf(["group-rwops", "tags"], qa_tags.TestGroupTags,
397 fe508a9d Michael Hanselmann
            qa_group.GetDefaultGroup())
398 4b10fb65 Adeodato Simo
399 66787da5 Adeodato Simo
400 c99200a3 Bernardo Dal Seno
def RunExportImportTests(instance, inodes):
401 b1ffe1eb Michael Hanselmann
  """Tries to export and import the instance.
402 a8083063 Iustin Pop

403 c99200a3 Bernardo Dal Seno
  @type inodes: list of nodes
404 c99200a3 Bernardo Dal Seno
  @param inodes: current nodes of the instance
405 638a7266 Iustin Pop

406 b1ffe1eb Michael Hanselmann
  """
407 301c3bbb Guido Trotter
  # FIXME: export explicitly bails out on file based storage. other non-lvm
408 301c3bbb Guido Trotter
  # based storage types are untested, though. Also note that import could still
409 301c3bbb Guido Trotter
  # work, but is deeply embedded into the "export" case.
410 301c3bbb Guido Trotter
  if (qa_config.TestEnabled("instance-export") and
411 f9b76ed4 Helga Velroyen
      instance.disk_template not in [constants.DT_FILE,
412 f9b76ed4 Helga Velroyen
                                     constants.DT_SHARED_FILE]):
413 bc696589 Michael Hanselmann
    RunTest(qa_instance.TestInstanceExportNoTarget, instance)
414 bc696589 Michael Hanselmann
415 c99200a3 Bernardo Dal Seno
    pnode = inodes[0]
416 b1ffe1eb Michael Hanselmann
    expnode = qa_config.AcquireNode(exclude=pnode)
417 b1ffe1eb Michael Hanselmann
    try:
418 b1ffe1eb Michael Hanselmann
      name = RunTest(qa_instance.TestInstanceExport, instance, expnode)
419 b1ffe1eb Michael Hanselmann
420 b1ffe1eb Michael Hanselmann
      RunTest(qa_instance.TestBackupList, expnode)
421 b1ffe1eb Michael Hanselmann
422 d0c8c01d Iustin Pop
      if qa_config.TestEnabled("instance-import"):
423 b1ffe1eb Michael Hanselmann
        newinst = qa_config.AcquireInstance()
424 5d640672 Michael Hanselmann
        try:
425 5fa0375e Michael Hanselmann
          RunTest(qa_instance.TestInstanceImport, newinst, pnode,
426 b1ffe1eb Michael Hanselmann
                  expnode, name)
427 51131cad Michael Hanselmann
          # Check if starting the instance works
428 51131cad Michael Hanselmann
          RunTest(qa_instance.TestInstanceStartup, newinst)
429 b1ffe1eb Michael Hanselmann
          RunTest(qa_instance.TestInstanceRemove, newinst)
430 5d640672 Michael Hanselmann
        finally:
431 6f88e076 Michael Hanselmann
          newinst.Release()
432 b1ffe1eb Michael Hanselmann
    finally:
433 565cb4bf Michael Hanselmann
      expnode.Release()
434 5d640672 Michael Hanselmann
435 34ddd63a Guido Trotter
  # FIXME: inter-cluster-instance-move crashes on file based instances :/
436 34ddd63a Guido Trotter
  # See Issue 414.
437 34ddd63a Guido Trotter
  if (qa_config.TestEnabled([qa_rapi.Enabled, "inter-cluster-instance-move"])
438 34ddd63a Guido Trotter
      and instance.disk_template != constants.DT_FILE):
439 5d831182 Michael Hanselmann
    newinst = qa_config.AcquireInstance()
440 5d831182 Michael Hanselmann
    try:
441 c99200a3 Bernardo Dal Seno
      tnode = qa_config.AcquireNode(exclude=inodes)
442 5d831182 Michael Hanselmann
      try:
443 5d831182 Michael Hanselmann
        RunTest(qa_rapi.TestInterClusterInstanceMove, instance, newinst,
444 c99200a3 Bernardo Dal Seno
                inodes, tnode)
445 5d831182 Michael Hanselmann
      finally:
446 565cb4bf Michael Hanselmann
        tnode.Release()
447 5d831182 Michael Hanselmann
    finally:
448 6f88e076 Michael Hanselmann
      newinst.Release()
449 5d831182 Michael Hanselmann
450 283f9d4c Michael Hanselmann
451 b998270c Iustin Pop
def RunDaemonTests(instance):
452 b1ffe1eb Michael Hanselmann
  """Test the ganeti-watcher script.
453 9df6d173 Michael Hanselmann

454 b1ffe1eb Michael Hanselmann
  """
455 8201b996 Iustin Pop
  RunTest(qa_daemon.TestPauseWatcher)
456 e9e35aaa Michael Hanselmann
457 7d88f255 Iustin Pop
  RunTestIf("instance-automatic-restart",
458 b998270c Iustin Pop
            qa_daemon.TestInstanceAutomaticRestart, instance)
459 7d88f255 Iustin Pop
  RunTestIf("instance-consecutive-failures",
460 b998270c Iustin Pop
            qa_daemon.TestInstanceConsecutiveFailures, instance)
461 e9e35aaa Michael Hanselmann
462 8201b996 Iustin Pop
  RunTest(qa_daemon.TestResumeWatcher)
463 8201b996 Iustin Pop
464 9df6d173 Michael Hanselmann
465 c99200a3 Bernardo Dal Seno
def RunHardwareFailureTests(instance, inodes):
466 b1ffe1eb Michael Hanselmann
  """Test cluster internal hardware failure recovery.
467 a8083063 Iustin Pop

468 b1ffe1eb Michael Hanselmann
  """
469 7d88f255 Iustin Pop
  RunTestIf("instance-failover", qa_instance.TestInstanceFailover, instance)
470 301adaae Michael Hanselmann
  RunTestIf(["instance-failover", qa_rapi.Enabled],
471 c0a146a1 Michael Hanselmann
            qa_rapi.TestRapiInstanceFailover, instance)
472 b1ffe1eb Michael Hanselmann
473 7d88f255 Iustin Pop
  RunTestIf("instance-migrate", qa_instance.TestInstanceMigrate, instance)
474 301adaae Michael Hanselmann
  RunTestIf(["instance-migrate", qa_rapi.Enabled],
475 7d88f255 Iustin Pop
            qa_rapi.TestRapiInstanceMigrate, instance)
476 938bde86 Michael Hanselmann
477 d0c8c01d Iustin Pop
  if qa_config.TestEnabled("instance-replace-disks"):
478 c99200a3 Bernardo Dal Seno
    # We just need alternative secondary nodes, hence "- 1"
479 c99200a3 Bernardo Dal Seno
    othernodes = qa_config.AcquireManyNodes(len(inodes) - 1, exclude=inodes)
480 7910e7a5 Michael Hanselmann
    try:
481 301adaae Michael Hanselmann
      RunTestIf(qa_rapi.Enabled, qa_rapi.TestRapiInstanceReplaceDisks, instance)
482 7910e7a5 Michael Hanselmann
      RunTest(qa_instance.TestReplaceDisks,
483 c99200a3 Bernardo Dal Seno
              instance, inodes, othernodes)
484 7910e7a5 Michael Hanselmann
    finally:
485 c99200a3 Bernardo Dal Seno
      qa_config.ReleaseManyNodes(othernodes)
486 c99200a3 Bernardo Dal Seno
    del othernodes
487 7910e7a5 Michael Hanselmann
488 83180411 Bernardo Dal Seno
  if qa_config.TestEnabled("instance-recreate-disks"):
489 83180411 Bernardo Dal Seno
    try:
490 c99200a3 Bernardo Dal Seno
      acquirednodes = qa_config.AcquireManyNodes(len(inodes), exclude=inodes)
491 c99200a3 Bernardo Dal Seno
      othernodes = acquirednodes
492 83180411 Bernardo Dal Seno
    except qa_error.OutOfNodesError:
493 c99200a3 Bernardo Dal Seno
      if len(inodes) > 1:
494 c99200a3 Bernardo Dal Seno
        # If the cluster is not big enough, let's reuse some of the nodes, but
495 c99200a3 Bernardo Dal Seno
        # with different roles. In this way, we can test a DRBD instance even on
496 c99200a3 Bernardo Dal Seno
        # a 3-node cluster.
497 c99200a3 Bernardo Dal Seno
        acquirednodes = [qa_config.AcquireNode(exclude=inodes)]
498 c99200a3 Bernardo Dal Seno
        othernodes = acquirednodes + inodes[:-1]
499 c99200a3 Bernardo Dal Seno
      else:
500 c99200a3 Bernardo Dal Seno
        raise
501 83180411 Bernardo Dal Seno
    try:
502 83180411 Bernardo Dal Seno
      RunTest(qa_instance.TestRecreateDisks,
503 c99200a3 Bernardo Dal Seno
              instance, inodes, othernodes)
504 83180411 Bernardo Dal Seno
    finally:
505 c99200a3 Bernardo Dal Seno
      qa_config.ReleaseManyNodes(acquirednodes)
506 83180411 Bernardo Dal Seno
507 c99200a3 Bernardo Dal Seno
  if len(inodes) >= 2:
508 c99200a3 Bernardo Dal Seno
    RunTestIf("node-evacuate", qa_node.TestNodeEvacuate, inodes[0], inodes[1])
509 c99200a3 Bernardo Dal Seno
    RunTestIf("node-failover", qa_node.TestNodeFailover, inodes[0], inodes[1])
510 52e9bef0 Thomas Thrainer
    RunTestIf("node-migrate", qa_node.TestNodeMigrate, inodes[0], inodes[1])
511 b1ffe1eb Michael Hanselmann
512 b1ffe1eb Michael Hanselmann
513 50ef6a41 Bernardo Dal Seno
def RunExclusiveStorageTests():
514 50ef6a41 Bernardo Dal Seno
  """Test exclusive storage."""
515 50ef6a41 Bernardo Dal Seno
  if not qa_config.TestEnabled("cluster-exclusive-storage"):
516 50ef6a41 Bernardo Dal Seno
    return
517 50ef6a41 Bernardo Dal Seno
518 50ef6a41 Bernardo Dal Seno
  node = qa_config.AcquireNode()
519 50ef6a41 Bernardo Dal Seno
  try:
520 e8b919a1 Bernardo Dal Seno
    old_es = qa_cluster.TestSetExclStorCluster(False)
521 250a9404 Bernardo Dal Seno
    qa_node.TestExclStorSingleNode(node)
522 e8b919a1 Bernardo Dal Seno
523 e8b919a1 Bernardo Dal Seno
    qa_cluster.TestSetExclStorCluster(True)
524 21e2734f Bernardo Dal Seno
    qa_cluster.TestExclStorSharedPv(node)
525 21e2734f Bernardo Dal Seno
526 50ef6a41 Bernardo Dal Seno
    if qa_config.TestEnabled("instance-add-plain-disk"):
527 50ef6a41 Bernardo Dal Seno
      # Make sure that the cluster doesn't have any pre-existing problem
528 50ef6a41 Bernardo Dal Seno
      qa_cluster.AssertClusterVerify()
529 a77e3d33 Michael Hanselmann
530 a77e3d33 Michael Hanselmann
      # Create and allocate instances
531 c99200a3 Bernardo Dal Seno
      instance1 = qa_instance.TestInstanceAddWithPlainDisk([node])
532 a77e3d33 Michael Hanselmann
      try:
533 a77e3d33 Michael Hanselmann
        instance2 = qa_instance.TestInstanceAddWithPlainDisk([node])
534 a77e3d33 Michael Hanselmann
        try:
535 a77e3d33 Michael Hanselmann
          # cluster-verify checks that disks are allocated correctly
536 a77e3d33 Michael Hanselmann
          qa_cluster.AssertClusterVerify()
537 a77e3d33 Michael Hanselmann
538 a77e3d33 Michael Hanselmann
          # Remove instances
539 a77e3d33 Michael Hanselmann
          qa_instance.TestInstanceRemove(instance2)
540 a77e3d33 Michael Hanselmann
          qa_instance.TestInstanceRemove(instance1)
541 a77e3d33 Michael Hanselmann
        finally:
542 6f88e076 Michael Hanselmann
          instance2.Release()
543 a77e3d33 Michael Hanselmann
      finally:
544 6f88e076 Michael Hanselmann
        instance1.Release()
545 a77e3d33 Michael Hanselmann
546 efd58d99 Bernardo Dal Seno
    if qa_config.TestEnabled("instance-add-drbd-disk"):
547 efd58d99 Bernardo Dal Seno
      snode = qa_config.AcquireNode()
548 efd58d99 Bernardo Dal Seno
      try:
549 efd58d99 Bernardo Dal Seno
        qa_cluster.TestSetExclStorCluster(False)
550 c99200a3 Bernardo Dal Seno
        instance = qa_instance.TestInstanceAddWithDrbdDisk([node, snode])
551 a77e3d33 Michael Hanselmann
        try:
552 a77e3d33 Michael Hanselmann
          qa_cluster.TestSetExclStorCluster(True)
553 a77e3d33 Michael Hanselmann
          exp_err = [constants.CV_EINSTANCEUNSUITABLENODE]
554 a77e3d33 Michael Hanselmann
          qa_cluster.AssertClusterVerify(fail=True, errors=exp_err)
555 a77e3d33 Michael Hanselmann
          qa_instance.TestInstanceRemove(instance)
556 a77e3d33 Michael Hanselmann
        finally:
557 6f88e076 Michael Hanselmann
          instance.Release()
558 efd58d99 Bernardo Dal Seno
      finally:
559 565cb4bf Michael Hanselmann
        snode.Release()
560 50ef6a41 Bernardo Dal Seno
    qa_cluster.TestSetExclStorCluster(old_es)
561 50ef6a41 Bernardo Dal Seno
  finally:
562 565cb4bf Michael Hanselmann
    node.Release()
563 50ef6a41 Bernardo Dal Seno
564 50ef6a41 Bernardo Dal Seno
565 ab4832d1 Bernardo Dal Seno
def _BuildSpecDict(par, mn, st, mx):
566 ec996117 Bernardo Dal Seno
  return {
567 7c8ae421 Bernardo Dal Seno
    constants.ISPECS_MINMAX: [{
568 7c8ae421 Bernardo Dal Seno
      constants.ISPECS_MIN: {par: mn},
569 7c8ae421 Bernardo Dal Seno
      constants.ISPECS_MAX: {par: mx},
570 7c8ae421 Bernardo Dal Seno
      }],
571 7c8ae421 Bernardo Dal Seno
    constants.ISPECS_STD: {par: st},
572 ec996117 Bernardo Dal Seno
    }
573 ab4832d1 Bernardo Dal Seno
574 ab4832d1 Bernardo Dal Seno
575 5fdf8491 Bernardo Dal Seno
def _BuildDoubleSpecDict(index, par, mn, st, mx):
576 5fdf8491 Bernardo Dal Seno
  new_spec = {
577 5fdf8491 Bernardo Dal Seno
    constants.ISPECS_MINMAX: [{}, {}],
578 5fdf8491 Bernardo Dal Seno
    }
579 5fdf8491 Bernardo Dal Seno
  if st is not None:
580 5fdf8491 Bernardo Dal Seno
    new_spec[constants.ISPECS_STD] = {par: st}
581 5fdf8491 Bernardo Dal Seno
  new_spec[constants.ISPECS_MINMAX][index] = {
582 5fdf8491 Bernardo Dal Seno
    constants.ISPECS_MIN: {par: mn},
583 5fdf8491 Bernardo Dal Seno
    constants.ISPECS_MAX: {par: mx},
584 5fdf8491 Bernardo Dal Seno
    }
585 5fdf8491 Bernardo Dal Seno
  return new_spec
586 5fdf8491 Bernardo Dal Seno
587 5fdf8491 Bernardo Dal Seno
588 ab4832d1 Bernardo Dal Seno
def TestIPolicyPlainInstance():
589 ab4832d1 Bernardo Dal Seno
  """Test instance policy interaction with instances"""
590 cb178a1e Bernardo Dal Seno
  params = ["memory-size", "cpu-count", "disk-count", "disk-size", "nic-count"]
591 ab4832d1 Bernardo Dal Seno
  if not qa_config.IsTemplateSupported(constants.DT_PLAIN):
592 ab4832d1 Bernardo Dal Seno
    print "Template %s not supported" % constants.DT_PLAIN
593 ab4832d1 Bernardo Dal Seno
    return
594 ab4832d1 Bernardo Dal Seno
595 ab4832d1 Bernardo Dal Seno
  # This test assumes that the group policy is empty
596 ec996117 Bernardo Dal Seno
  (_, old_specs) = qa_cluster.TestClusterSetISpecs()
597 7c8ae421 Bernardo Dal Seno
  # We also assume to have only one min/max bound
598 7c8ae421 Bernardo Dal Seno
  assert len(old_specs[constants.ISPECS_MINMAX]) == 1
599 ab4832d1 Bernardo Dal Seno
  node = qa_config.AcquireNode()
600 ab4832d1 Bernardo Dal Seno
  try:
601 ec996117 Bernardo Dal Seno
    # Log of policy changes, list of tuples:
602 ec996117 Bernardo Dal Seno
    # (full_change, incremental_change, policy_violated)
603 fa84c8a4 Bernardo Dal Seno
    history = []
604 ab4832d1 Bernardo Dal Seno
    instance = qa_instance.TestInstanceAddWithPlainDisk([node])
605 ab4832d1 Bernardo Dal Seno
    try:
606 ab4832d1 Bernardo Dal Seno
      policyerror = [constants.CV_EINSTANCEPOLICY]
607 ab4832d1 Bernardo Dal Seno
      for par in params:
608 46d21495 Bernardo Dal Seno
        (iminval, imaxval) = qa_instance.GetInstanceSpec(instance.name, par)
609 ab4832d1 Bernardo Dal Seno
        # Some specs must be multiple of 4
610 ab4832d1 Bernardo Dal Seno
        new_spec = _BuildSpecDict(par, imaxval + 4, imaxval + 4, imaxval + 4)
611 ec996117 Bernardo Dal Seno
        history.append((None, new_spec, True))
612 ab4832d1 Bernardo Dal Seno
        if iminval > 0:
613 ab4832d1 Bernardo Dal Seno
          # Some specs must be multiple of 4
614 ab4832d1 Bernardo Dal Seno
          if iminval >= 4:
615 ab4832d1 Bernardo Dal Seno
            upper = iminval - 4
616 ab4832d1 Bernardo Dal Seno
          else:
617 ab4832d1 Bernardo Dal Seno
            upper = iminval - 1
618 ab4832d1 Bernardo Dal Seno
          new_spec = _BuildSpecDict(par, 0, upper, upper)
619 ec996117 Bernardo Dal Seno
          history.append((None, new_spec, True))
620 ec996117 Bernardo Dal Seno
        history.append((old_specs, None, False))
621 5fdf8491 Bernardo Dal Seno
622 5fdf8491 Bernardo Dal Seno
      # Test with two instance specs
623 5fdf8491 Bernardo Dal Seno
      double_specs = copy.deepcopy(old_specs)
624 5fdf8491 Bernardo Dal Seno
      double_specs[constants.ISPECS_MINMAX] = \
625 5fdf8491 Bernardo Dal Seno
          double_specs[constants.ISPECS_MINMAX] * 2
626 5fdf8491 Bernardo Dal Seno
      (par1, par2) = params[0:2]
627 5fdf8491 Bernardo Dal Seno
      (_, imaxval1) = qa_instance.GetInstanceSpec(instance.name, par1)
628 5fdf8491 Bernardo Dal Seno
      (_, imaxval2) = qa_instance.GetInstanceSpec(instance.name, par2)
629 5fdf8491 Bernardo Dal Seno
      old_minmax = old_specs[constants.ISPECS_MINMAX][0]
630 5fdf8491 Bernardo Dal Seno
      history.extend([
631 5fdf8491 Bernardo Dal Seno
        (double_specs, None, False),
632 5fdf8491 Bernardo Dal Seno
        # The first min/max limit is being violated
633 5fdf8491 Bernardo Dal Seno
        (None,
634 5fdf8491 Bernardo Dal Seno
         _BuildDoubleSpecDict(0, par1, imaxval1 + 4, imaxval1 + 4,
635 5fdf8491 Bernardo Dal Seno
                              imaxval1 + 4),
636 5fdf8491 Bernardo Dal Seno
         False),
637 5fdf8491 Bernardo Dal Seno
        # Both min/max limits are being violated
638 5fdf8491 Bernardo Dal Seno
        (None,
639 5fdf8491 Bernardo Dal Seno
         _BuildDoubleSpecDict(1, par2, imaxval2 + 4, None, imaxval2 + 4),
640 5fdf8491 Bernardo Dal Seno
         True),
641 5fdf8491 Bernardo Dal Seno
        # The second min/max limit is being violated
642 5fdf8491 Bernardo Dal Seno
        (None,
643 5fdf8491 Bernardo Dal Seno
         _BuildDoubleSpecDict(0, par1,
644 5fdf8491 Bernardo Dal Seno
                              old_minmax[constants.ISPECS_MIN][par1],
645 5fdf8491 Bernardo Dal Seno
                              old_specs[constants.ISPECS_STD][par1],
646 5fdf8491 Bernardo Dal Seno
                              old_minmax[constants.ISPECS_MAX][par1]),
647 5fdf8491 Bernardo Dal Seno
         False),
648 5fdf8491 Bernardo Dal Seno
        (old_specs, None, False),
649 5fdf8491 Bernardo Dal Seno
        ])
650 5fdf8491 Bernardo Dal Seno
651 5fdf8491 Bernardo Dal Seno
      # Apply the changes, and check policy violations after each change
652 5fdf8491 Bernardo Dal Seno
      qa_cluster.AssertClusterVerify()
653 5fdf8491 Bernardo Dal Seno
      for (new_specs, diff_specs, failed) in history:
654 5fdf8491 Bernardo Dal Seno
        qa_cluster.TestClusterSetISpecs(new_specs=new_specs,
655 5fdf8491 Bernardo Dal Seno
                                        diff_specs=diff_specs)
656 5fdf8491 Bernardo Dal Seno
        if failed:
657 5fdf8491 Bernardo Dal Seno
          qa_cluster.AssertClusterVerify(warnings=policyerror)
658 5fdf8491 Bernardo Dal Seno
        else:
659 5fdf8491 Bernardo Dal Seno
          qa_cluster.AssertClusterVerify()
660 5fdf8491 Bernardo Dal Seno
661 ab4832d1 Bernardo Dal Seno
      qa_instance.TestInstanceRemove(instance)
662 ab4832d1 Bernardo Dal Seno
    finally:
663 46d21495 Bernardo Dal Seno
      instance.Release()
664 fa84c8a4 Bernardo Dal Seno
665 fa84c8a4 Bernardo Dal Seno
    # Now we replay the same policy changes, and we expect that the instance
666 fa84c8a4 Bernardo Dal Seno
    # cannot be created for the cases where we had a policy violation above
667 ec996117 Bernardo Dal Seno
    for (new_specs, diff_specs, failed) in history:
668 ec996117 Bernardo Dal Seno
      qa_cluster.TestClusterSetISpecs(new_specs=new_specs,
669 ec996117 Bernardo Dal Seno
                                      diff_specs=diff_specs)
670 fa84c8a4 Bernardo Dal Seno
      if failed:
671 fa84c8a4 Bernardo Dal Seno
        qa_instance.TestInstanceAddWithPlainDisk([node], fail=True)
672 fa84c8a4 Bernardo Dal Seno
      # Instance creation with no policy violation has been tested already
673 ab4832d1 Bernardo Dal Seno
  finally:
674 46d21495 Bernardo Dal Seno
    node.Release()
675 ab4832d1 Bernardo Dal Seno
676 ab4832d1 Bernardo Dal Seno
677 98bdd169 Bernardo Dal Seno
def IsExclusiveStorageInstanceTestEnabled():
678 98bdd169 Bernardo Dal Seno
  test_name = "exclusive-storage-instance-tests"
679 98bdd169 Bernardo Dal Seno
  if qa_config.TestEnabled(test_name):
680 98bdd169 Bernardo Dal Seno
    vgname = qa_config.get("vg-name", constants.DEFAULT_VG)
681 98bdd169 Bernardo Dal Seno
    vgscmd = utils.ShellQuoteArgs([
682 98bdd169 Bernardo Dal Seno
      "vgs", "--noheadings", "-o", "pv_count", vgname,
683 98bdd169 Bernardo Dal Seno
      ])
684 98bdd169 Bernardo Dal Seno
    nodes = qa_config.GetConfig()["nodes"]
685 98bdd169 Bernardo Dal Seno
    for node in nodes:
686 98bdd169 Bernardo Dal Seno
      try:
687 98bdd169 Bernardo Dal Seno
        pvnum = int(qa_utils.GetCommandOutput(node.primary, vgscmd))
688 98bdd169 Bernardo Dal Seno
      except Exception, e:
689 98bdd169 Bernardo Dal Seno
        msg = ("Cannot get the number of PVs on %s, needed by '%s': %s" %
690 98bdd169 Bernardo Dal Seno
               (node.primary, test_name, e))
691 98bdd169 Bernardo Dal Seno
        raise qa_error.Error(msg)
692 98bdd169 Bernardo Dal Seno
      if pvnum < 2:
693 98bdd169 Bernardo Dal Seno
        raise qa_error.Error("Node %s has not enough PVs (%s) to run '%s'" %
694 98bdd169 Bernardo Dal Seno
                             (node.primary, pvnum, test_name))
695 98bdd169 Bernardo Dal Seno
    res = True
696 98bdd169 Bernardo Dal Seno
  else:
697 98bdd169 Bernardo Dal Seno
    res = False
698 98bdd169 Bernardo Dal Seno
  return res
699 98bdd169 Bernardo Dal Seno
700 98bdd169 Bernardo Dal Seno
701 deadfa13 Bernardo Dal Seno
def RunInstanceTests():
702 deadfa13 Bernardo Dal Seno
  """Create and exercise instances."""
703 02cff8aa Bernardo Dal Seno
  instance_tests = [
704 02cff8aa Bernardo Dal Seno
    ("instance-add-plain-disk", constants.DT_PLAIN,
705 02cff8aa Bernardo Dal Seno
     qa_instance.TestInstanceAddWithPlainDisk, 1),
706 02cff8aa Bernardo Dal Seno
    ("instance-add-drbd-disk", constants.DT_DRBD8,
707 02cff8aa Bernardo Dal Seno
     qa_instance.TestInstanceAddWithDrbdDisk, 2),
708 02cff8aa Bernardo Dal Seno
    ("instance-add-diskless", constants.DT_DISKLESS,
709 02cff8aa Bernardo Dal Seno
     qa_instance.TestInstanceAddDiskless, 1),
710 02cff8aa Bernardo Dal Seno
    ("instance-add-file", constants.DT_FILE,
711 f9b76ed4 Helga Velroyen
     qa_instance.TestInstanceAddFile, 1),
712 f9b76ed4 Helga Velroyen
    ("instance-add-shared-file", constants.DT_SHARED_FILE,
713 f9b76ed4 Helga Velroyen
     qa_instance.TestInstanceAddSharedFile, 1),
714 02cff8aa Bernardo Dal Seno
    ]
715 deadfa13 Bernardo Dal Seno
716 deadfa13 Bernardo Dal Seno
  for (test_name, templ, create_fun, num_nodes) in instance_tests:
717 deadfa13 Bernardo Dal Seno
    if (qa_config.TestEnabled(test_name) and
718 deadfa13 Bernardo Dal Seno
        qa_config.IsTemplateSupported(templ)):
719 deadfa13 Bernardo Dal Seno
      inodes = qa_config.AcquireManyNodes(num_nodes)
720 deadfa13 Bernardo Dal Seno
      try:
721 deadfa13 Bernardo Dal Seno
        instance = RunTest(create_fun, inodes)
722 a77e3d33 Michael Hanselmann
        try:
723 a77e3d33 Michael Hanselmann
          RunTestIf("cluster-epo", qa_cluster.TestClusterEpo)
724 a77e3d33 Michael Hanselmann
          RunDaemonTests(instance)
725 a77e3d33 Michael Hanselmann
          for node in inodes:
726 a77e3d33 Michael Hanselmann
            RunTestIf("haskell-confd", qa_node.TestNodeListDrbd, node)
727 a77e3d33 Michael Hanselmann
          if len(inodes) > 1:
728 a77e3d33 Michael Hanselmann
            RunTestIf("group-rwops", qa_group.TestAssignNodesIncludingSplit,
729 a77e3d33 Michael Hanselmann
                      constants.INITIAL_NODE_GROUP_NAME,
730 aecba21e Michael Hanselmann
                      inodes[0].primary, inodes[1].primary)
731 a77e3d33 Michael Hanselmann
          if qa_config.TestEnabled("instance-convert-disk"):
732 a77e3d33 Michael Hanselmann
            RunTest(qa_instance.TestInstanceShutdown, instance)
733 a77e3d33 Michael Hanselmann
            RunTest(qa_instance.TestInstanceConvertDiskToPlain,
734 a77e3d33 Michael Hanselmann
                    instance, inodes)
735 a77e3d33 Michael Hanselmann
            RunTest(qa_instance.TestInstanceStartup, instance)
736 a365b47f Bernardo Dal Seno
          RunTestIf("instance-modify-disks",
737 a365b47f Bernardo Dal Seno
                    qa_instance.TestInstanceModifyDisks, instance)
738 7af293d7 Thomas Thrainer
          RunCommonInstanceTests(instance, inodes)
739 d0a44ec0 Klaus Aehlig
          if qa_config.TestEnabled("instance-modify-primary"):
740 d0a44ec0 Klaus Aehlig
            othernode = qa_config.AcquireNode()
741 d0a44ec0 Klaus Aehlig
            RunTest(qa_instance.TestInstanceModifyPrimaryAndBack,
742 d0a44ec0 Klaus Aehlig
                    instance, inodes[0], othernode)
743 d0a44ec0 Klaus Aehlig
            othernode.Release()
744 a77e3d33 Michael Hanselmann
          RunGroupListTests()
745 a77e3d33 Michael Hanselmann
          RunExportImportTests(instance, inodes)
746 a77e3d33 Michael Hanselmann
          RunHardwareFailureTests(instance, inodes)
747 a77e3d33 Michael Hanselmann
          RunRepairDiskSizes()
748 a77e3d33 Michael Hanselmann
          RunTest(qa_instance.TestInstanceRemove, instance)
749 a77e3d33 Michael Hanselmann
        finally:
750 6f88e076 Michael Hanselmann
          instance.Release()
751 deadfa13 Bernardo Dal Seno
        del instance
752 deadfa13 Bernardo Dal Seno
      finally:
753 deadfa13 Bernardo Dal Seno
        qa_config.ReleaseManyNodes(inodes)
754 deadfa13 Bernardo Dal Seno
      qa_cluster.AssertClusterVerify()
755 b1ffe1eb Michael Hanselmann
756 b1ffe1eb Michael Hanselmann
757 a5877534 Michele Tartara
def RunMonitoringTests():
758 a5877534 Michele Tartara
  if qa_config.TestEnabled("mon-collector"):
759 a5877534 Michele Tartara
    RunTest(qa_monitoring.TestInstStatusCollector)
760 a5877534 Michele Tartara
761 a5877534 Michele Tartara
762 f7e6f3c8 Iustin Pop
def RunQa():
763 f7e6f3c8 Iustin Pop
  """Main QA body.
764 b1ffe1eb Michael Hanselmann

765 b1ffe1eb Michael Hanselmann
  """
766 725ec2f1 René Nussbaumer
  rapi_user = "ganeti-qa"
767 725ec2f1 René Nussbaumer
768 b1ffe1eb Michael Hanselmann
  RunEnvTests()
769 35ff270b Bernardo Dal Seno
  rapi_secret = SetupCluster(rapi_user)
770 2771835c Michael Hanselmann
771 0fe54825 Bernardo Dal Seno
  if qa_rapi.Enabled():
772 0fe54825 Bernardo Dal Seno
    # Load RAPI certificate
773 0fe54825 Bernardo Dal Seno
    qa_rapi.Setup(rapi_user, rapi_secret)
774 2771835c Michael Hanselmann
775 b1ffe1eb Michael Hanselmann
  RunClusterTests()
776 b1ffe1eb Michael Hanselmann
  RunOsTests()
777 4b62db14 Michael Hanselmann
778 7d88f255 Iustin Pop
  RunTestIf("tags", qa_tags.TestClusterTags)
779 d74c2ca1 Michael Hanselmann
780 729c4377 Iustin Pop
  RunCommonNodeTests()
781 30131294 Adeodato Simo
  RunGroupListTests()
782 66787da5 Adeodato Simo
  RunGroupRwTests()
783 ea7693c1 Helga Velroyen
  RunNetworkTests()
784 729c4377 Iustin Pop
785 6f058bf2 Bernardo Dal Seno
  # The master shouldn't be readded or put offline; "delay" needs a non-master
786 6f058bf2 Bernardo Dal Seno
  # node to test
787 d0cb68cb Michael Hanselmann
  pnode = qa_config.AcquireNode(exclude=qa_config.GetMasterNode())
788 d0cb68cb Michael Hanselmann
  try:
789 7d88f255 Iustin Pop
    RunTestIf("node-readd", qa_node.TestNodeReadd, pnode)
790 7d88f255 Iustin Pop
    RunTestIf("node-modify", qa_node.TestNodeModify, pnode)
791 5a85b99e Michael Hanselmann
    RunTestIf("delay", qa_cluster.TestDelay, pnode)
792 d0cb68cb Michael Hanselmann
  finally:
793 565cb4bf Michael Hanselmann
    pnode.Release()
794 102b115b Michael Hanselmann
795 a36f690c Bernardo Dal Seno
  # Make sure the cluster is clean before running instance tests
796 a36f690c Bernardo Dal Seno
  qa_cluster.AssertClusterVerify()
797 a36f690c Bernardo Dal Seno
798 b1ffe1eb Michael Hanselmann
  pnode = qa_config.AcquireNode()
799 b1ffe1eb Michael Hanselmann
  try:
800 7d88f255 Iustin Pop
    RunTestIf("tags", qa_tags.TestNodeTags, pnode)
801 d74c2ca1 Michael Hanselmann
802 a47f574c Oleksiy Mishchenko
    if qa_rapi.Enabled():
803 a47f574c Oleksiy Mishchenko
      RunTest(qa_rapi.TestNode, pnode)
804 a47f574c Oleksiy Mishchenko
805 8cb70e56 Michael Hanselmann
      if qa_config.TestEnabled("instance-add-plain-disk"):
806 924e95f9 Michael Hanselmann
        for use_client in [True, False]:
807 924e95f9 Michael Hanselmann
          rapi_instance = RunTest(qa_rapi.TestRapiInstanceAdd, pnode,
808 924e95f9 Michael Hanselmann
                                  use_client)
809 a77e3d33 Michael Hanselmann
          try:
810 a77e3d33 Michael Hanselmann
            if qa_config.TestEnabled("instance-plain-rapi-common-tests"):
811 7af293d7 Thomas Thrainer
              RunCommonInstanceTests(rapi_instance, [pnode])
812 a77e3d33 Michael Hanselmann
            RunTest(qa_rapi.TestRapiInstanceRemove, rapi_instance, use_client)
813 a77e3d33 Michael Hanselmann
          finally:
814 6f88e076 Michael Hanselmann
            rapi_instance.Release()
815 924e95f9 Michael Hanselmann
          del rapi_instance
816 8cb70e56 Michael Hanselmann
817 6f058bf2 Bernardo Dal Seno
  finally:
818 565cb4bf Michael Hanselmann
    pnode.Release()
819 6f058bf2 Bernardo Dal Seno
820 deadfa13 Bernardo Dal Seno
  config_list = [
821 deadfa13 Bernardo Dal Seno
    ("default-instance-tests", lambda: None, lambda _: None),
822 98bdd169 Bernardo Dal Seno
    (IsExclusiveStorageInstanceTestEnabled,
823 deadfa13 Bernardo Dal Seno
     lambda: qa_cluster.TestSetExclStorCluster(True),
824 deadfa13 Bernardo Dal Seno
     qa_cluster.TestSetExclStorCluster),
825 27eba428 Bernardo Dal Seno
  ]
826 deadfa13 Bernardo Dal Seno
  for (conf_name, setup_conf_f, restore_conf_f) in config_list:
827 deadfa13 Bernardo Dal Seno
    if qa_config.TestEnabled(conf_name):
828 deadfa13 Bernardo Dal Seno
      oldconf = setup_conf_f()
829 deadfa13 Bernardo Dal Seno
      RunInstanceTests()
830 deadfa13 Bernardo Dal Seno
      restore_conf_f(oldconf)
831 c7e54e1d Agata Murawska
832 6f058bf2 Bernardo Dal Seno
  pnode = qa_config.AcquireNode()
833 6f058bf2 Bernardo Dal Seno
  try:
834 7d88f255 Iustin Pop
    if qa_config.TestEnabled(["instance-add-plain-disk", "instance-export"]):
835 3b01286e Michael Hanselmann
      for shutdown in [False, True]:
836 c99200a3 Bernardo Dal Seno
        instance = RunTest(qa_instance.TestInstanceAddWithPlainDisk, [pnode])
837 7d7609a3 Michael Hanselmann
        try:
838 a77e3d33 Michael Hanselmann
          expnode = qa_config.AcquireNode(exclude=pnode)
839 a77e3d33 Michael Hanselmann
          try:
840 a77e3d33 Michael Hanselmann
            if shutdown:
841 a77e3d33 Michael Hanselmann
              # Stop instance before exporting and removing it
842 a77e3d33 Michael Hanselmann
              RunTest(qa_instance.TestInstanceShutdown, instance)
843 a77e3d33 Michael Hanselmann
            RunTest(qa_instance.TestInstanceExportWithRemove, instance, expnode)
844 a77e3d33 Michael Hanselmann
            RunTest(qa_instance.TestBackupList, expnode)
845 a77e3d33 Michael Hanselmann
          finally:
846 565cb4bf Michael Hanselmann
            expnode.Release()
847 7d7609a3 Michael Hanselmann
        finally:
848 6f88e076 Michael Hanselmann
          instance.Release()
849 3b01286e Michael Hanselmann
        del expnode
850 3b01286e Michael Hanselmann
        del instance
851 a36f690c Bernardo Dal Seno
      qa_cluster.AssertClusterVerify()
852 a8083063 Iustin Pop
853 6f058bf2 Bernardo Dal Seno
  finally:
854 565cb4bf Michael Hanselmann
    pnode.Release()
855 6f058bf2 Bernardo Dal Seno
856 50ef6a41 Bernardo Dal Seno
  RunExclusiveStorageTests()
857 ab4832d1 Bernardo Dal Seno
  RunTestIf(["cluster-instance-policy", "instance-add-plain-disk"],
858 ab4832d1 Bernardo Dal Seno
            TestIPolicyPlainInstance)
859 50ef6a41 Bernardo Dal Seno
860 2ef21e6e Bernardo Dal Seno
  RunTestIf(
861 2ef21e6e Bernardo Dal Seno
    "instance-add-restricted-by-disktemplates",
862 2ef21e6e Bernardo Dal Seno
    qa_instance.TestInstanceCreationRestrictedByDiskTemplates)
863 2ef21e6e Bernardo Dal Seno
864 6f058bf2 Bernardo Dal Seno
  # Test removing instance with offline drbd secondary
865 04b5f222 Michael Hanselmann
  if qa_config.TestEnabled(["instance-remove-drbd-offline",
866 04b5f222 Michael Hanselmann
                            "instance-add-drbd-disk"]):
867 6f058bf2 Bernardo Dal Seno
    # Make sure the master is not put offline
868 6f058bf2 Bernardo Dal Seno
    snode = qa_config.AcquireNode(exclude=qa_config.GetMasterNode())
869 6f058bf2 Bernardo Dal Seno
    try:
870 6f058bf2 Bernardo Dal Seno
      pnode = qa_config.AcquireNode(exclude=snode)
871 c7e54e1d Agata Murawska
      try:
872 a36f690c Bernardo Dal Seno
        instance = qa_instance.TestInstanceAddWithDrbdDisk([pnode, snode])
873 f006f110 Bernardo Dal Seno
        set_offline = lambda node: qa_node.MakeNodeOffline(node, "yes")
874 f006f110 Bernardo Dal Seno
        set_online = lambda node: qa_node.MakeNodeOffline(node, "no")
875 f006f110 Bernardo Dal Seno
        RunTest(qa_instance.TestRemoveInstanceOfflineNode, instance, snode,
876 f006f110 Bernardo Dal Seno
                set_offline, set_online)
877 c7e54e1d Agata Murawska
      finally:
878 565cb4bf Michael Hanselmann
        pnode.Release()
879 6f058bf2 Bernardo Dal Seno
    finally:
880 565cb4bf Michael Hanselmann
      snode.Release()
881 f006f110 Bernardo Dal Seno
    qa_cluster.AssertClusterVerify()
882 a8083063 Iustin Pop
883 a5877534 Michele Tartara
  RunMonitoringTests()
884 a5877534 Michele Tartara
885 7d88f255 Iustin Pop
  RunTestIf("create-cluster", qa_node.TestNodeRemoveAll)
886 a8083063 Iustin Pop
887 7d88f255 Iustin Pop
  RunTestIf("cluster-destroy", qa_cluster.TestClusterDestroy)
888 a8083063 Iustin Pop
889 cec9845c Michael Hanselmann
890 fc3f75dd Iustin Pop
@UsesRapiClient
891 f7e6f3c8 Iustin Pop
def main():
892 f7e6f3c8 Iustin Pop
  """Main program.
893 f7e6f3c8 Iustin Pop

894 f7e6f3c8 Iustin Pop
  """
895 f7e6f3c8 Iustin Pop
  parser = optparse.OptionParser(usage="%prog [options] <config-file>")
896 d0c8c01d Iustin Pop
  parser.add_option("--yes-do-it", dest="yes_do_it",
897 5ae4945a Iustin Pop
                    action="store_true",
898 5ae4945a Iustin Pop
                    help="Really execute the tests")
899 c5cd9637 Michael Hanselmann
  (opts, args) = parser.parse_args()
900 f7e6f3c8 Iustin Pop
901 f7e6f3c8 Iustin Pop
  if len(args) == 1:
902 f7e6f3c8 Iustin Pop
    (config_file, ) = args
903 f7e6f3c8 Iustin Pop
  else:
904 f7e6f3c8 Iustin Pop
    parser.error("Wrong number of arguments.")
905 f7e6f3c8 Iustin Pop
906 c5cd9637 Michael Hanselmann
  if not opts.yes_do_it:
907 f7e6f3c8 Iustin Pop
    print ("Executing this script irreversibly destroys any Ganeti\n"
908 f7e6f3c8 Iustin Pop
           "configuration on all nodes involved. If you really want\n"
909 f7e6f3c8 Iustin Pop
           "to start testing, supply the --yes-do-it option.")
910 f7e6f3c8 Iustin Pop
    sys.exit(1)
911 f7e6f3c8 Iustin Pop
912 f7e6f3c8 Iustin Pop
  qa_config.Load(config_file)
913 f7e6f3c8 Iustin Pop
914 aecba21e Michael Hanselmann
  primary = qa_config.GetMasterNode().primary
915 710bc88c Iustin Pop
  qa_utils.StartMultiplexer(primary)
916 710bc88c Iustin Pop
  print ("SSH command for primary node: %s" %
917 710bc88c Iustin Pop
         utils.ShellQuoteArgs(qa_utils.GetSSHCommand(primary, "")))
918 710bc88c Iustin Pop
  print ("SSH command for other nodes: %s" %
919 710bc88c Iustin Pop
         utils.ShellQuoteArgs(qa_utils.GetSSHCommand("NODE", "")))
920 f7e6f3c8 Iustin Pop
  try:
921 f7e6f3c8 Iustin Pop
    RunQa()
922 f7e6f3c8 Iustin Pop
  finally:
923 f7e6f3c8 Iustin Pop
    qa_utils.CloseMultiplexers()
924 f7e6f3c8 Iustin Pop
925 d0c8c01d Iustin Pop
if __name__ == "__main__":
926 cec9845c Michael Hanselmann
  main()