Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 1094acda

History | View | Annotate | Download (28.9 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 01b69ec5 Michael Hanselmann
# Copyright (C) 2006, 2007 Google Inc.
5 01b69ec5 Michael Hanselmann
#
6 01b69ec5 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 01b69ec5 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 01b69ec5 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 01b69ec5 Michael Hanselmann
# (at your option) any later version.
10 01b69ec5 Michael Hanselmann
#
11 01b69ec5 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 01b69ec5 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 01b69ec5 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 01b69ec5 Michael Hanselmann
# General Public License for more details.
15 01b69ec5 Michael Hanselmann
#
16 01b69ec5 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 01b69ec5 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 01b69ec5 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 01b69ec5 Michael Hanselmann
# 02110-1301, USA.
20 01b69ec5 Michael Hanselmann
21 01b69ec5 Michael Hanselmann
22 01b69ec5 Michael Hanselmann
"""Burnin program
23 01b69ec5 Michael Hanselmann
24 01b69ec5 Michael Hanselmann
"""
25 175f44c2 Iustin Pop
26 bd5e77f9 Guido Trotter
import os
27 a8083063 Iustin Pop
import sys
28 a8083063 Iustin Pop
import optparse
29 e2212007 Iustin Pop
import time
30 5178f1bc Iustin Pop
import socket
31 5dc626fd Iustin Pop
import urllib
32 175f44c2 Iustin Pop
from itertools import izip, islice, cycle
33 21546b1c Iustin Pop
from cStringIO import StringIO
34 a8083063 Iustin Pop
35 a8083063 Iustin Pop
from ganeti import opcodes
36 a8083063 Iustin Pop
from ganeti import constants
37 a8083063 Iustin Pop
from ganeti import cli
38 9f13fc7a Iustin Pop
from ganeti import errors
39 9f13fc7a Iustin Pop
from ganeti import utils
40 a8083063 Iustin Pop
41 01b69ec5 Michael Hanselmann
42 9f13fc7a Iustin Pop
USAGE = ("\tburnin -o OS_NAME [options...] instance_name ...")
43 a8083063 Iustin Pop
44 01b69ec5 Michael Hanselmann
45 5178f1bc Iustin Pop
class InstanceDown(Exception):
46 5178f1bc Iustin Pop
  """The checked instance was not up"""
47 5178f1bc Iustin Pop
48 5178f1bc Iustin Pop
49 a8083063 Iustin Pop
def Usage():
50 a8083063 Iustin Pop
  """Shows program usage information and exits the program."""
51 a8083063 Iustin Pop
52 a8083063 Iustin Pop
  print >> sys.stderr, "Usage:"
53 a8083063 Iustin Pop
  print >> sys.stderr, USAGE
54 a8083063 Iustin Pop
  sys.exit(2)
55 a8083063 Iustin Pop
56 01b69ec5 Michael Hanselmann
57 836d59d7 Iustin Pop
def Log(msg, indent=0):
58 3ecf6786 Iustin Pop
  """Simple function that prints out its argument.
59 3ecf6786 Iustin Pop
60 3ecf6786 Iustin Pop
  """
61 836d59d7 Iustin Pop
  headers = {
62 836d59d7 Iustin Pop
    0: "- ",
63 836d59d7 Iustin Pop
    1: "* ",
64 836d59d7 Iustin Pop
    2: ""
65 836d59d7 Iustin Pop
    }
66 836d59d7 Iustin Pop
  sys.stdout.write("%*s%s%s\n" % (2*indent, "",
67 836d59d7 Iustin Pop
                                   headers.get(indent, "  "), msg))
68 84cc52ab Michael Hanselmann
  sys.stdout.flush()
69 a8083063 Iustin Pop
70 836d59d7 Iustin Pop
def Err(msg, exit_code=1):
71 836d59d7 Iustin Pop
  """Simple error logging that prints to stderr.
72 836d59d7 Iustin Pop
73 836d59d7 Iustin Pop
  """
74 836d59d7 Iustin Pop
  sys.stderr.write(msg + "\n")
75 836d59d7 Iustin Pop
  sys.stderr.flush()
76 836d59d7 Iustin Pop
  sys.exit(exit_code)
77 01b69ec5 Michael Hanselmann
78 5dc626fd Iustin Pop
79 5dc626fd Iustin Pop
class SimpleOpener(urllib.FancyURLopener):
80 5dc626fd Iustin Pop
  """A simple url opener"""
81 5dc626fd Iustin Pop
82 5dc626fd Iustin Pop
  def prompt_user_passwd(self, host, realm, clear_cache = 0):
83 5dc626fd Iustin Pop
    """No-interaction version of prompt_user_passwd."""
84 5dc626fd Iustin Pop
    return None, None
85 5dc626fd Iustin Pop
86 5dc626fd Iustin Pop
  def http_error_default(self, url, fp, errcode, errmsg, headers):
87 5dc626fd Iustin Pop
    """Custom error handling"""
88 5dc626fd Iustin Pop
    # make sure sockets are not left in CLOSE_WAIT, this is similar
89 5dc626fd Iustin Pop
    # but with a different exception to the BasicURLOpener class
90 5dc626fd Iustin Pop
    _ = fp.read() # throw away data
91 5dc626fd Iustin Pop
    fp.close()
92 5dc626fd Iustin Pop
    raise InstanceDown("HTTP error returned: code %s, msg %s" %
93 5dc626fd Iustin Pop
                       (errcode, errmsg))
94 5dc626fd Iustin Pop
95 5dc626fd Iustin Pop
96 175f44c2 Iustin Pop
class Burner(object):
97 175f44c2 Iustin Pop
  """Burner class."""
98 175f44c2 Iustin Pop
99 175f44c2 Iustin Pop
  def __init__(self):
100 175f44c2 Iustin Pop
    """Constructor."""
101 82d9caef Iustin Pop
    utils.SetupLogging(constants.LOG_BURNIN, debug=False, stderr_logging=True)
102 5dc626fd Iustin Pop
    self.url_opener = SimpleOpener()
103 21546b1c Iustin Pop
    self._feed_buf = StringIO()
104 175f44c2 Iustin Pop
    self.nodes = []
105 175f44c2 Iustin Pop
    self.instances = []
106 175f44c2 Iustin Pop
    self.to_rem = []
107 c723c163 Iustin Pop
    self.queued_ops = []
108 175f44c2 Iustin Pop
    self.opts = None
109 175f44c2 Iustin Pop
    self.ParseOptions()
110 320eda24 Iustin Pop
    self.cl = cli.GetClient()
111 175f44c2 Iustin Pop
    self.GetState()
112 175f44c2 Iustin Pop
113 21546b1c Iustin Pop
  def ClearFeedbackBuf(self):
114 21546b1c Iustin Pop
    """Clear the feedback buffer."""
115 21546b1c Iustin Pop
    self._feed_buf.truncate(0)
116 21546b1c Iustin Pop
117 21546b1c Iustin Pop
  def GetFeedbackBuf(self):
118 21546b1c Iustin Pop
    """Return the contents of the buffer."""
119 21546b1c Iustin Pop
    return self._feed_buf.getvalue()
120 21546b1c Iustin Pop
121 21546b1c Iustin Pop
  def Feedback(self, msg):
122 21546b1c Iustin Pop
    """Acumulate feedback in our buffer."""
123 e17188f4 Iustin Pop
    self._feed_buf.write("%s %s\n" % (time.ctime(utils.MergeTime(msg[0])),
124 e17188f4 Iustin Pop
                                      msg[2]))
125 d7b47a77 Iustin Pop
    if self.opts.verbose:
126 836d59d7 Iustin Pop
      Log(msg, indent=3)
127 21546b1c Iustin Pop
128 c723c163 Iustin Pop
  def ExecOp(self, *ops):
129 c723c163 Iustin Pop
    """Execute one or more opcodes and manage the exec buffer.
130 c723c163 Iustin Pop
131 c723c163 Iustin Pop
    @result: if only opcode has been passed, we return its result;
132 c723c163 Iustin Pop
        otherwise we return the list of results
133 c723c163 Iustin Pop
134 c723c163 Iustin Pop
    """
135 c723c163 Iustin Pop
    job_id = cli.SendJob(ops, cl=self.cl)
136 c723c163 Iustin Pop
    results = cli.PollJob(job_id, cl=self.cl, feedback_fn=self.Feedback)
137 c723c163 Iustin Pop
    if len(ops) == 1:
138 c723c163 Iustin Pop
      return results[0]
139 c723c163 Iustin Pop
    else:
140 c723c163 Iustin Pop
      return results
141 c723c163 Iustin Pop
142 c723c163 Iustin Pop
  def ExecOrQueue(self, name, *ops):
143 21546b1c Iustin Pop
    """Execute an opcode and manage the exec buffer."""
144 c723c163 Iustin Pop
    if self.opts.parallel:
145 c723c163 Iustin Pop
      self.queued_ops.append((ops, name))
146 c723c163 Iustin Pop
    else:
147 c723c163 Iustin Pop
      return self.ExecOp(*ops)
148 c723c163 Iustin Pop
149 c723c163 Iustin Pop
  def CommitQueue(self):
150 c723c163 Iustin Pop
    """Execute all submitted opcodes in case of parallel burnin"""
151 c723c163 Iustin Pop
    if not self.opts.parallel:
152 c723c163 Iustin Pop
      return
153 c723c163 Iustin Pop
154 c723c163 Iustin Pop
    try:
155 c723c163 Iustin Pop
      results = self.ExecJobSet(self.queued_ops)
156 c723c163 Iustin Pop
    finally:
157 c723c163 Iustin Pop
      self.queued_ops = []
158 c723c163 Iustin Pop
    return results
159 ec5c88dc Iustin Pop
160 ec5c88dc Iustin Pop
  def ExecJobSet(self, jobs):
161 ec5c88dc Iustin Pop
    """Execute a set of jobs and return once all are done.
162 ec5c88dc Iustin Pop
163 ec5c88dc Iustin Pop
    The method will return the list of results, if all jobs are
164 c723c163 Iustin Pop
    successful. Otherwise, OpExecError will be raised from within
165 ec5c88dc Iustin Pop
    cli.py.
166 ec5c88dc Iustin Pop
167 ec5c88dc Iustin Pop
    """
168 ec5c88dc Iustin Pop
    self.ClearFeedbackBuf()
169 c723c163 Iustin Pop
    job_ids = [cli.SendJob(row[0], cl=self.cl) for row in jobs]
170 c723c163 Iustin Pop
    Log("Submitted job ID(s) %s" % ", ".join(job_ids), indent=1)
171 ec5c88dc Iustin Pop
    results = []
172 c723c163 Iustin Pop
    for jid, (_, iname) in zip(job_ids, jobs):
173 c723c163 Iustin Pop
      Log("waiting for job %s for %s" % (jid, iname), indent=2)
174 ec5c88dc Iustin Pop
      results.append(cli.PollJob(jid, cl=self.cl, feedback_fn=self.Feedback))
175 ec5c88dc Iustin Pop
176 ec5c88dc Iustin Pop
    return results
177 21546b1c Iustin Pop
178 175f44c2 Iustin Pop
  def ParseOptions(self):
179 175f44c2 Iustin Pop
    """Parses the command line options.
180 175f44c2 Iustin Pop
181 175f44c2 Iustin Pop
    In case of command line errors, it will show the usage and exit the
182 175f44c2 Iustin Pop
    program.
183 175f44c2 Iustin Pop
184 175f44c2 Iustin Pop
    """
185 175f44c2 Iustin Pop
186 175f44c2 Iustin Pop
    parser = optparse.OptionParser(usage="\n%s" % USAGE,
187 175f44c2 Iustin Pop
                                   version="%%prog (ganeti) %s" %
188 175f44c2 Iustin Pop
                                   constants.RELEASE_VERSION,
189 175f44c2 Iustin Pop
                                   option_class=cli.CliOption)
190 175f44c2 Iustin Pop
191 175f44c2 Iustin Pop
    parser.add_option("-o", "--os", dest="os", default=None,
192 175f44c2 Iustin Pop
                      help="OS to use during burnin",
193 175f44c2 Iustin Pop
                      metavar="<OS>")
194 08db7c5c Iustin Pop
    parser.add_option("--disk-size", dest="disk_size",
195 08db7c5c Iustin Pop
                      help="Disk size (determines disk count)",
196 08db7c5c Iustin Pop
                      default="128m", type="string", metavar="<size,size,...>")
197 08db7c5c Iustin Pop
    parser.add_option("--disk-growth", dest="disk_growth", help="Disk growth",
198 f768530c Iustin Pop
                      default="128m", type="string", metavar="<size,size,...>")
199 5e767b34 Iustin Pop
    parser.add_option("--mem-size", dest="mem_size", help="Memory size",
200 5e767b34 Iustin Pop
                      default=128, type="unit", metavar="<size>")
201 175f44c2 Iustin Pop
    parser.add_option("-v", "--verbose",
202 175f44c2 Iustin Pop
                      action="store_true", dest="verbose", default=False,
203 175f44c2 Iustin Pop
                      help="print command execution messages to stdout")
204 175f44c2 Iustin Pop
    parser.add_option("--no-replace1", dest="do_replace1",
205 175f44c2 Iustin Pop
                      help="Skip disk replacement with the same secondary",
206 175f44c2 Iustin Pop
                      action="store_false", default=True)
207 175f44c2 Iustin Pop
    parser.add_option("--no-replace2", dest="do_replace2",
208 175f44c2 Iustin Pop
                      help="Skip disk replacement with a different secondary",
209 175f44c2 Iustin Pop
                      action="store_false", default=True)
210 175f44c2 Iustin Pop
    parser.add_option("--no-failover", dest="do_failover",
211 175f44c2 Iustin Pop
                      help="Skip instance failovers", action="store_false",
212 175f44c2 Iustin Pop
                      default=True)
213 99bdd139 Iustin Pop
    parser.add_option("--no-migrate", dest="do_migrate",
214 99bdd139 Iustin Pop
                      help="Skip instance live migration",
215 99bdd139 Iustin Pop
                      action="store_false", default=True)
216 bd5e77f9 Guido Trotter
    parser.add_option("--no-importexport", dest="do_importexport",
217 bd5e77f9 Guido Trotter
                      help="Skip instance export/import", action="store_false",
218 bd5e77f9 Guido Trotter
                      default=True)
219 d4844f0f Guido Trotter
    parser.add_option("--no-startstop", dest="do_startstop",
220 d4844f0f Guido Trotter
                      help="Skip instance stop/start", action="store_false",
221 d4844f0f Guido Trotter
                      default=True)
222 00f91f29 Iustin Pop
    parser.add_option("--no-reinstall", dest="do_reinstall",
223 00f91f29 Iustin Pop
                      help="Skip instance reinstall", action="store_false",
224 00f91f29 Iustin Pop
                      default=True)
225 00f91f29 Iustin Pop
    parser.add_option("--no-reboot", dest="do_reboot",
226 00f91f29 Iustin Pop
                      help="Skip instance reboot", action="store_false",
227 00f91f29 Iustin Pop
                      default=True)
228 90e722d1 Iustin Pop
    parser.add_option("--no-activate-disks", dest="do_activate_disks",
229 90e722d1 Iustin Pop
                      help="Skip disk activation/deactivation",
230 90e722d1 Iustin Pop
                      action="store_false", default=True)
231 5c22d16e Iustin Pop
    parser.add_option("--no-add-disks", dest="do_addremove_disks",
232 5c22d16e Iustin Pop
                      help="Skip disk addition/removal",
233 5c22d16e Iustin Pop
                      action="store_false", default=True)
234 5c22d16e Iustin Pop
    parser.add_option("--no-add-nics", dest="do_addremove_nics",
235 5c22d16e Iustin Pop
                      help="Skip NIC addition/removal",
236 5c22d16e Iustin Pop
                      action="store_false", default=True)
237 b518a14a Iustin Pop
    parser.add_option("--no-nics", dest="nics",
238 b518a14a Iustin Pop
                      help="No network interfaces", action="store_const",
239 b518a14a Iustin Pop
                      const=[], default=[{}])
240 054a8696 Manuel Franceschini
    parser.add_option("--rename", dest="rename", default=None,
241 054a8696 Manuel Franceschini
                      help="Give one unused instance name which is taken"
242 054a8696 Manuel Franceschini
                           " to start the renaming sequence",
243 054a8696 Manuel Franceschini
                      metavar="<instance_name>")
244 175f44c2 Iustin Pop
    parser.add_option("-t", "--disk-template", dest="disk_template",
245 2f505cb5 Manuel Franceschini
                      choices=("diskless", "file", "plain", "drbd"),
246 f9193417 Iustin Pop
                      default="drbd",
247 2f505cb5 Manuel Franceschini
                      help="Disk template (diskless, file, plain or drbd)"
248 2f505cb5 Manuel Franceschini
                            " [drbd]")
249 175f44c2 Iustin Pop
    parser.add_option("-n", "--nodes", dest="nodes", default="",
250 175f44c2 Iustin Pop
                      help="Comma separated list of nodes to perform"
251 175f44c2 Iustin Pop
                      " the burnin on (defaults to all nodes)")
252 1325da74 Iustin Pop
    parser.add_option("-I", "--iallocator", dest="iallocator",
253 b91bde14 Iustin Pop
                      default=None, type="string",
254 b91bde14 Iustin Pop
                      help="Perform the allocation using an iallocator"
255 b91bde14 Iustin Pop
                      " instead of fixed node spread (node restrictions no"
256 b91bde14 Iustin Pop
                      " longer apply, therefore -n/--nodes must not be used")
257 ec5c88dc Iustin Pop
    parser.add_option("-p", "--parallel", default=False, action="store_true",
258 ec5c88dc Iustin Pop
                      dest="parallel",
259 ec5c88dc Iustin Pop
                      help="Enable parallelization of some operations in"
260 ec5c88dc Iustin Pop
                      " order to speed burnin or to test granular locking")
261 5178f1bc Iustin Pop
    parser.add_option("--net-timeout", default=15, type="int",
262 5178f1bc Iustin Pop
                      dest="net_timeout",
263 5178f1bc Iustin Pop
                      help="The instance check network timeout in seconds"
264 5178f1bc Iustin Pop
                      " (defaults to 15 seconds)")
265 5178f1bc Iustin Pop
    parser.add_option("-C", "--http-check", default=False, action="store_true",
266 5178f1bc Iustin Pop
                      dest="http_check",
267 5178f1bc Iustin Pop
                      help="Enable checking of instance status via http,"
268 5178f1bc Iustin Pop
                      " looking for /hostname.txt that should contain the"
269 5178f1bc Iustin Pop
                      " name of the instance")
270 320eda24 Iustin Pop
    parser.add_option("-K", "--keep-instances", default=False,
271 320eda24 Iustin Pop
                      action="store_true",
272 320eda24 Iustin Pop
                      dest="keep_instances",
273 320eda24 Iustin Pop
                      help="Leave instances on the cluster after burnin,"
274 320eda24 Iustin Pop
                      " for investigation in case of errors or simply"
275 320eda24 Iustin Pop
                      " to use them")
276 5178f1bc Iustin Pop
277 175f44c2 Iustin Pop
278 175f44c2 Iustin Pop
    options, args = parser.parse_args()
279 175f44c2 Iustin Pop
    if len(args) < 1 or options.os is None:
280 175f44c2 Iustin Pop
      Usage()
281 175f44c2 Iustin Pop
282 f9193417 Iustin Pop
    supported_disk_templates = (constants.DT_DISKLESS,
283 2f505cb5 Manuel Franceschini
                                constants.DT_FILE,
284 f9193417 Iustin Pop
                                constants.DT_PLAIN,
285 12c3449a Michael Hanselmann
                                constants.DT_DRBD8)
286 12c3449a Michael Hanselmann
    if options.disk_template not in supported_disk_templates:
287 836d59d7 Iustin Pop
      Err("Unknown disk template '%s'" % options.disk_template)
288 175f44c2 Iustin Pop
289 b518a14a Iustin Pop
    if options.disk_template == constants.DT_DISKLESS:
290 b518a14a Iustin Pop
      disk_size = disk_growth = []
291 5178f1bc Iustin Pop
      options.do_addremove_disks = False
292 b518a14a Iustin Pop
    else:
293 b518a14a Iustin Pop
      disk_size = [utils.ParseUnit(v) for v in options.disk_size.split(",")]
294 b518a14a Iustin Pop
      disk_growth = [utils.ParseUnit(v)
295 b518a14a Iustin Pop
                     for v in options.disk_growth.split(",")]
296 b518a14a Iustin Pop
      if len(disk_growth) != len(disk_size):
297 836d59d7 Iustin Pop
        Err("Wrong disk sizes/growth combination")
298 08db7c5c Iustin Pop
    if ((disk_size and options.disk_template == constants.DT_DISKLESS) or
299 08db7c5c Iustin Pop
        (not disk_size and options.disk_template != constants.DT_DISKLESS)):
300 836d59d7 Iustin Pop
      Err("Wrong disk count/disk template combination")
301 08db7c5c Iustin Pop
302 08db7c5c Iustin Pop
    self.disk_size = disk_size
303 08db7c5c Iustin Pop
    self.disk_growth = disk_growth
304 08db7c5c Iustin Pop
    self.disk_count = len(disk_size)
305 08db7c5c Iustin Pop
306 b91bde14 Iustin Pop
    if options.nodes and options.iallocator:
307 836d59d7 Iustin Pop
      Err("Give either the nodes option or the iallocator option, not both")
308 b91bde14 Iustin Pop
309 175f44c2 Iustin Pop
    self.opts = options
310 175f44c2 Iustin Pop
    self.instances = args
311 338e51e8 Iustin Pop
    self.bep = {
312 338e51e8 Iustin Pop
      constants.BE_MEMORY: options.mem_size,
313 338e51e8 Iustin Pop
      constants.BE_VCPUS: 1,
314 338e51e8 Iustin Pop
      }
315 338e51e8 Iustin Pop
    self.hvp = {}
316 175f44c2 Iustin Pop
317 5178f1bc Iustin Pop
    socket.setdefaulttimeout(options.net_timeout)
318 5178f1bc Iustin Pop
319 175f44c2 Iustin Pop
  def GetState(self):
320 175f44c2 Iustin Pop
    """Read the cluster state from the config."""
321 175f44c2 Iustin Pop
    if self.opts.nodes:
322 175f44c2 Iustin Pop
      names = self.opts.nodes.split(",")
323 175f44c2 Iustin Pop
    else:
324 175f44c2 Iustin Pop
      names = []
325 175f44c2 Iustin Pop
    try:
326 e8d47209 Iustin Pop
      op = opcodes.OpQueryNodes(output_fields=["name", "offline", "drained"],
327 ec79568d Iustin Pop
                                names=names, use_locking=True)
328 21546b1c Iustin Pop
      result = self.ExecOp(op)
329 175f44c2 Iustin Pop
    except errors.GenericError, err:
330 175f44c2 Iustin Pop
      err_code, msg = cli.FormatError(err)
331 836d59d7 Iustin Pop
      Err(msg, exit_code=err_code)
332 e8d47209 Iustin Pop
    self.nodes = [data[0] for data in result if not (data[1] or data[2])]
333 175f44c2 Iustin Pop
334 1f9430d6 Iustin Pop
    result = self.ExecOp(opcodes.OpDiagnoseOS(output_fields=["name", "valid"],
335 1f9430d6 Iustin Pop
                                              names=[]))
336 175f44c2 Iustin Pop
337 175f44c2 Iustin Pop
    if not result:
338 836d59d7 Iustin Pop
      Err("Can't get the OS list")
339 175f44c2 Iustin Pop
340 175f44c2 Iustin Pop
    # filter non-valid OS-es
341 1f9430d6 Iustin Pop
    os_set = [val[0] for val in result if val[1]]
342 175f44c2 Iustin Pop
343 175f44c2 Iustin Pop
    if self.opts.os not in os_set:
344 836d59d7 Iustin Pop
      Err("OS '%s' not found" % self.opts.os)
345 175f44c2 Iustin Pop
346 c723c163 Iustin Pop
  def BurnCreateInstances(self):
347 175f44c2 Iustin Pop
    """Create the given instances.
348 175f44c2 Iustin Pop
349 175f44c2 Iustin Pop
    """
350 175f44c2 Iustin Pop
    self.to_rem = []
351 175f44c2 Iustin Pop
    mytor = izip(cycle(self.nodes),
352 175f44c2 Iustin Pop
                 islice(cycle(self.nodes), 1, None),
353 175f44c2 Iustin Pop
                 self.instances)
354 338e51e8 Iustin Pop
355 836d59d7 Iustin Pop
    Log("Creating instances")
356 175f44c2 Iustin Pop
    for pnode, snode, instance in mytor:
357 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
358 b91bde14 Iustin Pop
      if self.opts.iallocator:
359 b91bde14 Iustin Pop
        pnode = snode = None
360 836d59d7 Iustin Pop
        msg = "with iallocator %s" % self.opts.iallocator
361 6d54548e Guido Trotter
      elif self.opts.disk_template not in constants.DTS_NET_MIRROR:
362 6d54548e Guido Trotter
        snode = None
363 836d59d7 Iustin Pop
        msg = "on %s" % pnode
364 6d54548e Guido Trotter
      else:
365 836d59d7 Iustin Pop
        msg = "on %s, %s" % (pnode, snode)
366 836d59d7 Iustin Pop
367 836d59d7 Iustin Pop
      Log(msg, indent=2)
368 6d54548e Guido Trotter
369 175f44c2 Iustin Pop
      op = opcodes.OpCreateInstance(instance_name=instance,
370 08db7c5c Iustin Pop
                                    disks = [ {"size": size}
371 08db7c5c Iustin Pop
                                              for size in self.disk_size],
372 175f44c2 Iustin Pop
                                    disk_template=self.opts.disk_template,
373 b518a14a Iustin Pop
                                    nics=self.opts.nics,
374 a8083063 Iustin Pop
                                    mode=constants.INSTANCE_CREATE,
375 175f44c2 Iustin Pop
                                    os_type=self.opts.os,
376 175f44c2 Iustin Pop
                                    pnode=pnode,
377 175f44c2 Iustin Pop
                                    snode=snode,
378 a8083063 Iustin Pop
                                    start=True,
379 e9f745aa Iustin Pop
                                    ip_check=True,
380 4501af56 Iustin Pop
                                    wait_for_sync=True,
381 2f505cb5 Manuel Franceschini
                                    file_driver="loop",
382 b91bde14 Iustin Pop
                                    file_storage_dir=None,
383 6e2dc934 Alexander Schreiber
                                    iallocator=self.opts.iallocator,
384 338e51e8 Iustin Pop
                                    beparams=self.bep,
385 338e51e8 Iustin Pop
                                    hvparams=self.hvp,
386 338e51e8 Iustin Pop
                                    )
387 6e2dc934 Alexander Schreiber
388 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op)
389 c723c163 Iustin Pop
      self.to_rem.append(instance)
390 c723c163 Iustin Pop
391 c723c163 Iustin Pop
    self.CommitQueue()
392 175f44c2 Iustin Pop
393 5178f1bc Iustin Pop
    for instance in self.instances:
394 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
395 5178f1bc Iustin Pop
396 c723c163 Iustin Pop
  def BurnGrowDisks(self):
397 659712c8 Iustin Pop
    """Grow both the os and the swap disks by the requested amount, if any."""
398 836d59d7 Iustin Pop
    Log("Growing disks")
399 659712c8 Iustin Pop
    for instance in self.instances:
400 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
401 08db7c5c Iustin Pop
      for idx, growth in enumerate(self.disk_growth):
402 659712c8 Iustin Pop
        if growth > 0:
403 08db7c5c Iustin Pop
          op = opcodes.OpGrowDisk(instance_name=instance, disk=idx,
404 6605411d Iustin Pop
                                  amount=growth, wait_for_sync=True)
405 836d59d7 Iustin Pop
          Log("increase disk/%s by %s MB" % (idx, growth), indent=2)
406 c723c163 Iustin Pop
          self.ExecOrQueue(instance, op)
407 c723c163 Iustin Pop
    self.CommitQueue()
408 659712c8 Iustin Pop
409 c723c163 Iustin Pop
  def BurnReplaceDisks1D8(self):
410 175f44c2 Iustin Pop
    """Replace disks on primary and secondary for drbd8."""
411 836d59d7 Iustin Pop
    Log("Replacing disks on the same nodes")
412 175f44c2 Iustin Pop
    for instance in self.instances:
413 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
414 c723c163 Iustin Pop
      ops = []
415 175f44c2 Iustin Pop
      for mode in constants.REPLACE_DISK_SEC, constants.REPLACE_DISK_PRI:
416 175f44c2 Iustin Pop
        op = opcodes.OpReplaceDisks(instance_name=instance,
417 175f44c2 Iustin Pop
                                    mode=mode,
418 08db7c5c Iustin Pop
                                    disks=[i for i in range(self.disk_count)])
419 836d59d7 Iustin Pop
        Log("run %s" % mode, indent=2)
420 c723c163 Iustin Pop
        ops.append(op)
421 c723c163 Iustin Pop
      self.ExecOrQueue(instance, *ops)
422 c723c163 Iustin Pop
    self.CommitQueue()
423 175f44c2 Iustin Pop
424 c723c163 Iustin Pop
  def BurnReplaceDisks2(self):
425 175f44c2 Iustin Pop
    """Replace secondary node."""
426 836d59d7 Iustin Pop
    Log("Changing the secondary node")
427 cfacfd6e Iustin Pop
    mode = constants.REPLACE_DISK_CHG
428 175f44c2 Iustin Pop
429 175f44c2 Iustin Pop
    mytor = izip(islice(cycle(self.nodes), 2, None),
430 175f44c2 Iustin Pop
                 self.instances)
431 175f44c2 Iustin Pop
    for tnode, instance in mytor:
432 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
433 b6e82a65 Iustin Pop
      if self.opts.iallocator:
434 b6e82a65 Iustin Pop
        tnode = None
435 836d59d7 Iustin Pop
        msg = "with iallocator %s" % self.opts.iallocator
436 836d59d7 Iustin Pop
      else:
437 836d59d7 Iustin Pop
        msg = tnode
438 175f44c2 Iustin Pop
      op = opcodes.OpReplaceDisks(instance_name=instance,
439 175f44c2 Iustin Pop
                                  mode=mode,
440 175f44c2 Iustin Pop
                                  remote_node=tnode,
441 b6e82a65 Iustin Pop
                                  iallocator=self.opts.iallocator,
442 08db7c5c Iustin Pop
                                  disks=[i for i in range(self.disk_count)])
443 836d59d7 Iustin Pop
      Log("run %s %s" % (mode, msg), indent=2)
444 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op)
445 c723c163 Iustin Pop
    self.CommitQueue()
446 175f44c2 Iustin Pop
447 c723c163 Iustin Pop
  def BurnFailover(self):
448 175f44c2 Iustin Pop
    """Failover the instances."""
449 836d59d7 Iustin Pop
    Log("Failing over instances")
450 175f44c2 Iustin Pop
    for instance in self.instances:
451 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
452 175f44c2 Iustin Pop
      op = opcodes.OpFailoverInstance(instance_name=instance,
453 175f44c2 Iustin Pop
                                      ignore_consistency=False)
454 175f44c2 Iustin Pop
455 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op)
456 c723c163 Iustin Pop
    self.CommitQueue()
457 5178f1bc Iustin Pop
    for instance in self.instances:
458 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
459 175f44c2 Iustin Pop
460 c723c163 Iustin Pop
  def BurnMigrate(self):
461 99bdd139 Iustin Pop
    """Migrate the instances."""
462 801cda94 Iustin Pop
    Log("Migrating instances")
463 99bdd139 Iustin Pop
    for instance in self.instances:
464 801cda94 Iustin Pop
      Log("instance %s" % instance, indent=1)
465 c723c163 Iustin Pop
      op1 = opcodes.OpMigrateInstance(instance_name=instance, live=True,
466 c723c163 Iustin Pop
                                      cleanup=False)
467 99bdd139 Iustin Pop
468 c723c163 Iustin Pop
      op2 = opcodes.OpMigrateInstance(instance_name=instance, live=True,
469 c723c163 Iustin Pop
                                      cleanup=True)
470 c723c163 Iustin Pop
      Log("migration and migration cleanup", indent=2)
471 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op1, op2)
472 c723c163 Iustin Pop
    self.CommitQueue()
473 99bdd139 Iustin Pop
474 c723c163 Iustin Pop
  def BurnImportExport(self):
475 bd5e77f9 Guido Trotter
    """Export the instance, delete it, and import it back.
476 bd5e77f9 Guido Trotter
477 bd5e77f9 Guido Trotter
    """
478 836d59d7 Iustin Pop
    Log("Exporting and re-importing instances")
479 bd5e77f9 Guido Trotter
    mytor = izip(cycle(self.nodes),
480 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 1, None),
481 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 2, None),
482 bd5e77f9 Guido Trotter
                 self.instances)
483 bd5e77f9 Guido Trotter
484 bd5e77f9 Guido Trotter
    for pnode, snode, enode, instance in mytor:
485 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
486 c723c163 Iustin Pop
      # read the full name of the instance
487 c723c163 Iustin Pop
      nam_op = opcodes.OpQueryInstances(output_fields=["name"],
488 ec79568d Iustin Pop
                                        names=[instance], use_locking=True)
489 c723c163 Iustin Pop
      full_name = self.ExecOp(nam_op)[0][0]
490 c723c163 Iustin Pop
491 f9af35c8 Guido Trotter
      if self.opts.iallocator:
492 f9af35c8 Guido Trotter
        pnode = snode = None
493 836d59d7 Iustin Pop
        import_log_msg = ("import from %s"
494 836d59d7 Iustin Pop
                          " with iallocator %s" %
495 836d59d7 Iustin Pop
                          (enode, self.opts.iallocator))
496 f9af35c8 Guido Trotter
      elif self.opts.disk_template not in constants.DTS_NET_MIRROR:
497 f9af35c8 Guido Trotter
        snode = None
498 836d59d7 Iustin Pop
        import_log_msg = ("import from %s to %s" %
499 836d59d7 Iustin Pop
                          (enode, pnode))
500 f9af35c8 Guido Trotter
      else:
501 836d59d7 Iustin Pop
        import_log_msg = ("import from %s to %s, %s" %
502 836d59d7 Iustin Pop
                          (enode, pnode, snode))
503 f9af35c8 Guido Trotter
504 bd5e77f9 Guido Trotter
      exp_op = opcodes.OpExportInstance(instance_name=instance,
505 bd5e77f9 Guido Trotter
                                           target_node=enode,
506 bd5e77f9 Guido Trotter
                                           shutdown=True)
507 5c54b832 Iustin Pop
      rem_op = opcodes.OpRemoveInstance(instance_name=instance,
508 5c54b832 Iustin Pop
                                        ignore_failures=True)
509 bd5e77f9 Guido Trotter
      imp_dir = os.path.join(constants.EXPORT_DIR, full_name)
510 bd5e77f9 Guido Trotter
      imp_op = opcodes.OpCreateInstance(instance_name=instance,
511 0ca35d45 Guido Trotter
                                        disks = [ {"size": size}
512 0ca35d45 Guido Trotter
                                                  for size in self.disk_size],
513 bd5e77f9 Guido Trotter
                                        disk_template=self.opts.disk_template,
514 b518a14a Iustin Pop
                                        nics=self.opts.nics,
515 bd5e77f9 Guido Trotter
                                        mode=constants.INSTANCE_IMPORT,
516 bd5e77f9 Guido Trotter
                                        src_node=enode,
517 bd5e77f9 Guido Trotter
                                        src_path=imp_dir,
518 bd5e77f9 Guido Trotter
                                        pnode=pnode,
519 bd5e77f9 Guido Trotter
                                        snode=snode,
520 bd5e77f9 Guido Trotter
                                        start=True,
521 bd5e77f9 Guido Trotter
                                        ip_check=True,
522 bd5e77f9 Guido Trotter
                                        wait_for_sync=True,
523 96bb2f71 Manuel Franceschini
                                        file_storage_dir=None,
524 0ca35d45 Guido Trotter
                                        file_driver="loop",
525 6e2dc934 Alexander Schreiber
                                        iallocator=self.opts.iallocator,
526 338e51e8 Iustin Pop
                                        beparams=self.bep,
527 338e51e8 Iustin Pop
                                        hvparams=self.hvp,
528 338e51e8 Iustin Pop
                                        )
529 6e2dc934 Alexander Schreiber
530 4a7ff493 Guido Trotter
      erem_op = opcodes.OpRemoveExport(instance_name=instance)
531 bd5e77f9 Guido Trotter
532 836d59d7 Iustin Pop
      Log("export to node %s" % enode, indent=2)
533 836d59d7 Iustin Pop
      Log("remove instance", indent=2)
534 836d59d7 Iustin Pop
      Log(import_log_msg, indent=2)
535 836d59d7 Iustin Pop
      Log("remove export", indent=2)
536 c723c163 Iustin Pop
      self.ExecOrQueue(instance, exp_op, rem_op, imp_op, erem_op)
537 bd5e77f9 Guido Trotter
538 c723c163 Iustin Pop
    self.CommitQueue()
539 5178f1bc Iustin Pop
    for instance in self.instances:
540 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
541 5178f1bc Iustin Pop
542 c723c163 Iustin Pop
  def StopInstanceOp(self, instance):
543 054a8696 Manuel Franceschini
    """Stop given instance."""
544 c723c163 Iustin Pop
    return opcodes.OpShutdownInstance(instance_name=instance)
545 054a8696 Manuel Franceschini
546 c723c163 Iustin Pop
  def StartInstanceOp(self, instance):
547 054a8696 Manuel Franceschini
    """Start given instance."""
548 c723c163 Iustin Pop
    return opcodes.OpStartupInstance(instance_name=instance, force=False)
549 054a8696 Manuel Franceschini
550 c723c163 Iustin Pop
  def RenameInstanceOp(self, instance, instance_new):
551 054a8696 Manuel Franceschini
    """Rename instance."""
552 c723c163 Iustin Pop
    return opcodes.OpRenameInstance(instance_name=instance,
553 c723c163 Iustin Pop
                                    new_name=instance_new)
554 054a8696 Manuel Franceschini
555 c723c163 Iustin Pop
  def BurnStopStart(self):
556 175f44c2 Iustin Pop
    """Stop/start the instances."""
557 836d59d7 Iustin Pop
    Log("Stopping and starting instances")
558 175f44c2 Iustin Pop
    for instance in self.instances:
559 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
560 c723c163 Iustin Pop
      op1 = self.StopInstanceOp(instance)
561 c723c163 Iustin Pop
      op2 = self.StartInstanceOp(instance)
562 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op1, op2)
563 c723c163 Iustin Pop
564 c723c163 Iustin Pop
    self.CommitQueue()
565 175f44c2 Iustin Pop
566 5178f1bc Iustin Pop
    for instance in self.instances:
567 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
568 5178f1bc Iustin Pop
569 c723c163 Iustin Pop
  def BurnRemove(self):
570 175f44c2 Iustin Pop
    """Remove the instances."""
571 836d59d7 Iustin Pop
    Log("Removing instances")
572 175f44c2 Iustin Pop
    for instance in self.to_rem:
573 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
574 5c54b832 Iustin Pop
      op = opcodes.OpRemoveInstance(instance_name=instance,
575 5c54b832 Iustin Pop
                                    ignore_failures=True)
576 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op)
577 c723c163 Iustin Pop
578 c723c163 Iustin Pop
    self.CommitQueue()
579 c723c163 Iustin Pop
580 c723c163 Iustin Pop
  def BurnRename(self):
581 c723c163 Iustin Pop
    """Rename the instances.
582 175f44c2 Iustin Pop
583 c723c163 Iustin Pop
    Note that this function will not execute in parallel, since we
584 c723c163 Iustin Pop
    only have one target for rename.
585 c723c163 Iustin Pop
586 c723c163 Iustin Pop
    """
587 836d59d7 Iustin Pop
    Log("Renaming instances")
588 054a8696 Manuel Franceschini
    rename = self.opts.rename
589 054a8696 Manuel Franceschini
    for instance in self.instances:
590 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
591 2e39ab98 Iustin Pop
      op_stop1 = self.StopInstanceOp(instance)
592 2e39ab98 Iustin Pop
      op_stop2 = self.StopInstanceOp(rename)
593 c723c163 Iustin Pop
      op_rename1 = self.RenameInstanceOp(instance, rename)
594 c723c163 Iustin Pop
      op_rename2 = self.RenameInstanceOp(rename, instance)
595 c723c163 Iustin Pop
      op_start1 = self.StartInstanceOp(rename)
596 c723c163 Iustin Pop
      op_start2 = self.StartInstanceOp(instance)
597 2e39ab98 Iustin Pop
      self.ExecOp(op_stop1, op_rename1, op_start1)
598 5178f1bc Iustin Pop
      self._CheckInstanceAlive(rename)
599 2e39ab98 Iustin Pop
      self.ExecOp(op_stop2, op_rename2, op_start2)
600 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
601 5178f1bc Iustin Pop
602 c723c163 Iustin Pop
  def BurnReinstall(self):
603 00f91f29 Iustin Pop
    """Reinstall the instances."""
604 836d59d7 Iustin Pop
    Log("Reinstalling instances")
605 00f91f29 Iustin Pop
    for instance in self.instances:
606 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
607 c723c163 Iustin Pop
      op1 = self.StopInstanceOp(instance)
608 c723c163 Iustin Pop
      op2 = opcodes.OpReinstallInstance(instance_name=instance)
609 836d59d7 Iustin Pop
      Log("reinstall without passing the OS", indent=2)
610 c723c163 Iustin Pop
      op3 = opcodes.OpReinstallInstance(instance_name=instance,
611 c723c163 Iustin Pop
                                        os_type=self.opts.os)
612 836d59d7 Iustin Pop
      Log("reinstall specifying the OS", indent=2)
613 c723c163 Iustin Pop
      op4 = self.StartInstanceOp(instance)
614 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op1, op2, op3, op4)
615 c723c163 Iustin Pop
616 c723c163 Iustin Pop
    self.CommitQueue()
617 c723c163 Iustin Pop
618 5178f1bc Iustin Pop
    for instance in self.instances:
619 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
620 00f91f29 Iustin Pop
621 c723c163 Iustin Pop
  def BurnReboot(self):
622 836d59d7 Iustin Pop
    """Reboot the instances."""
623 836d59d7 Iustin Pop
    Log("Rebooting instances")
624 00f91f29 Iustin Pop
    for instance in self.instances:
625 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
626 c723c163 Iustin Pop
      ops = []
627 00f91f29 Iustin Pop
      for reboot_type in constants.REBOOT_TYPES:
628 00f91f29 Iustin Pop
        op = opcodes.OpRebootInstance(instance_name=instance,
629 00f91f29 Iustin Pop
                                      reboot_type=reboot_type,
630 00f91f29 Iustin Pop
                                      ignore_secondaries=False)
631 836d59d7 Iustin Pop
        Log("reboot with type '%s'" % reboot_type, indent=2)
632 c723c163 Iustin Pop
        ops.append(op)
633 c723c163 Iustin Pop
      self.ExecOrQueue(instance, *ops)
634 c723c163 Iustin Pop
635 c723c163 Iustin Pop
    self.CommitQueue()
636 c723c163 Iustin Pop
637 c723c163 Iustin Pop
    for instance in self.instances:
638 c723c163 Iustin Pop
      self._CheckInstanceAlive(instance)
639 00f91f29 Iustin Pop
640 c723c163 Iustin Pop
  def BurnActivateDisks(self):
641 90e722d1 Iustin Pop
    """Activate and deactivate disks of the instances."""
642 836d59d7 Iustin Pop
    Log("Activating/deactivating disks")
643 90e722d1 Iustin Pop
    for instance in self.instances:
644 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
645 c723c163 Iustin Pop
      op_start = self.StartInstanceOp(instance)
646 90e722d1 Iustin Pop
      op_act = opcodes.OpActivateInstanceDisks(instance_name=instance)
647 90e722d1 Iustin Pop
      op_deact = opcodes.OpDeactivateInstanceDisks(instance_name=instance)
648 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
649 836d59d7 Iustin Pop
      Log("activate disks when online", indent=2)
650 836d59d7 Iustin Pop
      Log("activate disks when offline", indent=2)
651 836d59d7 Iustin Pop
      Log("deactivate disks (when offline)", indent=2)
652 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op_act, op_stop, op_act, op_deact, op_start)
653 c723c163 Iustin Pop
    self.CommitQueue()
654 5178f1bc Iustin Pop
    for instance in self.instances:
655 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
656 90e722d1 Iustin Pop
657 c723c163 Iustin Pop
  def BurnAddRemoveDisks(self):
658 5c22d16e Iustin Pop
    """Add and remove an extra disk for the instances."""
659 836d59d7 Iustin Pop
    Log("Adding and removing disks")
660 5c22d16e Iustin Pop
    for instance in self.instances:
661 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
662 5c22d16e Iustin Pop
      op_add = opcodes.OpSetInstanceParams(\
663 5c22d16e Iustin Pop
        instance_name=instance,
664 5c22d16e Iustin Pop
        disks=[(constants.DDM_ADD, {"size": self.disk_size[0]})])
665 5c22d16e Iustin Pop
      op_rem = opcodes.OpSetInstanceParams(\
666 5c22d16e Iustin Pop
        instance_name=instance, disks=[(constants.DDM_REMOVE, {})])
667 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
668 c723c163 Iustin Pop
      op_start = self.StartInstanceOp(instance)
669 836d59d7 Iustin Pop
      Log("adding a disk", indent=2)
670 836d59d7 Iustin Pop
      Log("removing last disk", indent=2)
671 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op_add, op_stop, op_rem, op_start)
672 c723c163 Iustin Pop
    self.CommitQueue()
673 5178f1bc Iustin Pop
    for instance in self.instances:
674 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
675 5c22d16e Iustin Pop
676 c723c163 Iustin Pop
  def BurnAddRemoveNICs(self):
677 5c22d16e Iustin Pop
    """Add and remove an extra NIC for the instances."""
678 836d59d7 Iustin Pop
    Log("Adding and removing NICs")
679 5c22d16e Iustin Pop
    for instance in self.instances:
680 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
681 5c22d16e Iustin Pop
      op_add = opcodes.OpSetInstanceParams(\
682 5c22d16e Iustin Pop
        instance_name=instance, nics=[(constants.DDM_ADD, {})])
683 5c22d16e Iustin Pop
      op_rem = opcodes.OpSetInstanceParams(\
684 5c22d16e Iustin Pop
        instance_name=instance, nics=[(constants.DDM_REMOVE, {})])
685 836d59d7 Iustin Pop
      Log("adding a NIC", indent=2)
686 836d59d7 Iustin Pop
      Log("removing last NIC", indent=2)
687 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op_add, op_rem)
688 c723c163 Iustin Pop
    self.CommitQueue()
689 5c22d16e Iustin Pop
690 5178f1bc Iustin Pop
  def _CheckInstanceAlive(self, instance):
691 5178f1bc Iustin Pop
    """Check if an instance is alive by doing http checks.
692 5178f1bc Iustin Pop
693 5178f1bc Iustin Pop
    This will try to retrieve the url on the instance /hostname.txt
694 5178f1bc Iustin Pop
    and check that it contains the hostname of the instance. In case
695 5178f1bc Iustin Pop
    we get ECONNREFUSED, we retry up to the net timeout seconds, for
696 5178f1bc Iustin Pop
    any other error we abort.
697 5178f1bc Iustin Pop
698 5178f1bc Iustin Pop
    """
699 5178f1bc Iustin Pop
    if not self.opts.http_check:
700 5178f1bc Iustin Pop
      return
701 5dc626fd Iustin Pop
    end_time = time.time() + self.opts.net_timeout
702 5dc626fd Iustin Pop
    url = None
703 5dc626fd Iustin Pop
    while time.time() < end_time and url is None:
704 5dc626fd Iustin Pop
      try:
705 5dc626fd Iustin Pop
        url = self.url_opener.open("http://%s/hostname.txt" % instance)
706 c723c163 Iustin Pop
      except IOError:
707 5dc626fd Iustin Pop
        # here we can have connection refused, no route to host, etc.
708 5dc626fd Iustin Pop
        time.sleep(1)
709 5dc626fd Iustin Pop
    if url is None:
710 5dc626fd Iustin Pop
      raise InstanceDown(instance, "Cannot contact instance")
711 5178f1bc Iustin Pop
    hostname = url.read().strip()
712 5dc626fd Iustin Pop
    url.close()
713 5178f1bc Iustin Pop
    if hostname != instance:
714 5178f1bc Iustin Pop
      raise InstanceDown(instance, ("Hostname mismatch, expected %s, got %s" %
715 5178f1bc Iustin Pop
                                    (instance, hostname)))
716 5178f1bc Iustin Pop
717 175f44c2 Iustin Pop
  def BurninCluster(self):
718 175f44c2 Iustin Pop
    """Test a cluster intensively.
719 175f44c2 Iustin Pop
720 175f44c2 Iustin Pop
    This will create instances and then start/stop/failover them.
721 175f44c2 Iustin Pop
    It is safe for existing instances but could impact performance.
722 175f44c2 Iustin Pop
723 175f44c2 Iustin Pop
    """
724 175f44c2 Iustin Pop
725 175f44c2 Iustin Pop
    opts = self.opts
726 175f44c2 Iustin Pop
727 836d59d7 Iustin Pop
    Log("Testing global parameters")
728 175f44c2 Iustin Pop
729 bd249e2f Iustin Pop
    if (len(self.nodes) == 1 and
730 2f505cb5 Manuel Franceschini
        opts.disk_template not in (constants.DT_DISKLESS, constants.DT_PLAIN,
731 2f505cb5 Manuel Franceschini
                                   constants.DT_FILE)):
732 836d59d7 Iustin Pop
      Err("When one node is available/selected the disk template must"
733 2f505cb5 Manuel Franceschini
          " be 'diskless', 'file' or 'plain'")
734 175f44c2 Iustin Pop
735 21546b1c Iustin Pop
    has_err = True
736 175f44c2 Iustin Pop
    try:
737 c723c163 Iustin Pop
      self.BurnCreateInstances()
738 175f44c2 Iustin Pop
      if opts.do_replace1 and opts.disk_template in constants.DTS_NET_MIRROR:
739 c723c163 Iustin Pop
        self.BurnReplaceDisks1D8()
740 175f44c2 Iustin Pop
      if (opts.do_replace2 and len(self.nodes) > 2 and
741 175f44c2 Iustin Pop
          opts.disk_template in constants.DTS_NET_MIRROR) :
742 c723c163 Iustin Pop
        self.BurnReplaceDisks2()
743 175f44c2 Iustin Pop
744 aa089b65 Iustin Pop
      if (opts.disk_template != constants.DT_DISKLESS and
745 aa089b65 Iustin Pop
          utils.any(self.disk_growth, lambda n: n > 0)):
746 c723c163 Iustin Pop
        self.BurnGrowDisks()
747 659712c8 Iustin Pop
748 175f44c2 Iustin Pop
      if opts.do_failover and opts.disk_template in constants.DTS_NET_MIRROR:
749 c723c163 Iustin Pop
        self.BurnFailover()
750 175f44c2 Iustin Pop
751 99bdd139 Iustin Pop
      if opts.do_migrate and opts.disk_template == constants.DT_DRBD8:
752 c723c163 Iustin Pop
        self.BurnMigrate()
753 99bdd139 Iustin Pop
754 a5e7be6b Iustin Pop
      if (opts.do_importexport and
755 a5e7be6b Iustin Pop
          opts.disk_template not in (constants.DT_DISKLESS,
756 a5e7be6b Iustin Pop
                                     constants.DT_FILE)):
757 c723c163 Iustin Pop
        self.BurnImportExport()
758 bd5e77f9 Guido Trotter
759 00f91f29 Iustin Pop
      if opts.do_reinstall:
760 c723c163 Iustin Pop
        self.BurnReinstall()
761 00f91f29 Iustin Pop
762 00f91f29 Iustin Pop
      if opts.do_reboot:
763 c723c163 Iustin Pop
        self.BurnReboot()
764 00f91f29 Iustin Pop
765 5c22d16e Iustin Pop
      if opts.do_addremove_disks:
766 c723c163 Iustin Pop
        self.BurnAddRemoveDisks()
767 5c22d16e Iustin Pop
768 5c22d16e Iustin Pop
      if opts.do_addremove_nics:
769 c723c163 Iustin Pop
        self.BurnAddRemoveNICs()
770 5c22d16e Iustin Pop
771 90e722d1 Iustin Pop
      if opts.do_activate_disks:
772 c723c163 Iustin Pop
        self.BurnActivateDisks()
773 90e722d1 Iustin Pop
774 054a8696 Manuel Franceschini
      if opts.rename:
775 c723c163 Iustin Pop
        self.BurnRename()
776 054a8696 Manuel Franceschini
777 eb61f8d3 Iustin Pop
      if opts.do_startstop:
778 c723c163 Iustin Pop
        self.BurnStopStart()
779 eb61f8d3 Iustin Pop
780 21546b1c Iustin Pop
      has_err = False
781 175f44c2 Iustin Pop
    finally:
782 21546b1c Iustin Pop
      if has_err:
783 21546b1c Iustin Pop
        Log("Error detected: opcode buffer follows:\n\n")
784 21546b1c Iustin Pop
        Log(self.GetFeedbackBuf())
785 21546b1c Iustin Pop
        Log("\n\n")
786 320eda24 Iustin Pop
      if not self.opts.keep_instances:
787 c723c163 Iustin Pop
        self.BurnRemove()
788 175f44c2 Iustin Pop
789 175f44c2 Iustin Pop
    return 0
790 a8083063 Iustin Pop
791 01b69ec5 Michael Hanselmann
792 a8083063 Iustin Pop
def main():
793 3ecf6786 Iustin Pop
  """Main function"""
794 3ecf6786 Iustin Pop
795 175f44c2 Iustin Pop
  burner = Burner()
796 a4af651e Iustin Pop
  return burner.BurninCluster()
797 a8083063 Iustin Pop
798 01b69ec5 Michael Hanselmann
799 a8083063 Iustin Pop
if __name__ == "__main__":
800 3ecf6786 Iustin Pop
  main()