Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ e8d47209

History | View | Annotate | Download (28.8 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 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
592 c723c163 Iustin Pop
      op_rename1 = self.RenameInstanceOp(instance, rename)
593 c723c163 Iustin Pop
      op_rename2 = self.RenameInstanceOp(rename, instance)
594 c723c163 Iustin Pop
      op_start1 = self.StartInstanceOp(rename)
595 c723c163 Iustin Pop
      op_start2 = self.StartInstanceOp(instance)
596 c723c163 Iustin Pop
      self.ExecOp(op_stop, op_rename1, op_start1)
597 5178f1bc Iustin Pop
      self._CheckInstanceAlive(rename)
598 c723c163 Iustin Pop
      self.ExecOp(op_stop, op_rename2, op_start2)
599 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
600 5178f1bc Iustin Pop
601 c723c163 Iustin Pop
  def BurnReinstall(self):
602 00f91f29 Iustin Pop
    """Reinstall the instances."""
603 836d59d7 Iustin Pop
    Log("Reinstalling instances")
604 00f91f29 Iustin Pop
    for instance in self.instances:
605 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
606 c723c163 Iustin Pop
      op1 = self.StopInstanceOp(instance)
607 c723c163 Iustin Pop
      op2 = opcodes.OpReinstallInstance(instance_name=instance)
608 836d59d7 Iustin Pop
      Log("reinstall without passing the OS", indent=2)
609 c723c163 Iustin Pop
      op3 = opcodes.OpReinstallInstance(instance_name=instance,
610 c723c163 Iustin Pop
                                        os_type=self.opts.os)
611 836d59d7 Iustin Pop
      Log("reinstall specifying the OS", indent=2)
612 c723c163 Iustin Pop
      op4 = self.StartInstanceOp(instance)
613 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op1, op2, op3, op4)
614 c723c163 Iustin Pop
615 c723c163 Iustin Pop
    self.CommitQueue()
616 c723c163 Iustin Pop
617 5178f1bc Iustin Pop
    for instance in self.instances:
618 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
619 00f91f29 Iustin Pop
620 c723c163 Iustin Pop
  def BurnReboot(self):
621 836d59d7 Iustin Pop
    """Reboot the instances."""
622 836d59d7 Iustin Pop
    Log("Rebooting instances")
623 00f91f29 Iustin Pop
    for instance in self.instances:
624 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
625 c723c163 Iustin Pop
      ops = []
626 00f91f29 Iustin Pop
      for reboot_type in constants.REBOOT_TYPES:
627 00f91f29 Iustin Pop
        op = opcodes.OpRebootInstance(instance_name=instance,
628 00f91f29 Iustin Pop
                                      reboot_type=reboot_type,
629 00f91f29 Iustin Pop
                                      ignore_secondaries=False)
630 836d59d7 Iustin Pop
        Log("reboot with type '%s'" % reboot_type, indent=2)
631 c723c163 Iustin Pop
        ops.append(op)
632 c723c163 Iustin Pop
      self.ExecOrQueue(instance, *ops)
633 c723c163 Iustin Pop
634 c723c163 Iustin Pop
    self.CommitQueue()
635 c723c163 Iustin Pop
636 c723c163 Iustin Pop
    for instance in self.instances:
637 c723c163 Iustin Pop
      self._CheckInstanceAlive(instance)
638 00f91f29 Iustin Pop
639 c723c163 Iustin Pop
  def BurnActivateDisks(self):
640 90e722d1 Iustin Pop
    """Activate and deactivate disks of the instances."""
641 836d59d7 Iustin Pop
    Log("Activating/deactivating disks")
642 90e722d1 Iustin Pop
    for instance in self.instances:
643 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
644 c723c163 Iustin Pop
      op_start = self.StartInstanceOp(instance)
645 90e722d1 Iustin Pop
      op_act = opcodes.OpActivateInstanceDisks(instance_name=instance)
646 90e722d1 Iustin Pop
      op_deact = opcodes.OpDeactivateInstanceDisks(instance_name=instance)
647 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
648 836d59d7 Iustin Pop
      Log("activate disks when online", indent=2)
649 836d59d7 Iustin Pop
      Log("activate disks when offline", indent=2)
650 836d59d7 Iustin Pop
      Log("deactivate disks (when offline)", indent=2)
651 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op_act, op_stop, op_act, op_deact, op_start)
652 c723c163 Iustin Pop
    self.CommitQueue()
653 5178f1bc Iustin Pop
    for instance in self.instances:
654 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
655 90e722d1 Iustin Pop
656 c723c163 Iustin Pop
  def BurnAddRemoveDisks(self):
657 5c22d16e Iustin Pop
    """Add and remove an extra disk for the instances."""
658 836d59d7 Iustin Pop
    Log("Adding and removing disks")
659 5c22d16e Iustin Pop
    for instance in self.instances:
660 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
661 5c22d16e Iustin Pop
      op_add = opcodes.OpSetInstanceParams(\
662 5c22d16e Iustin Pop
        instance_name=instance,
663 5c22d16e Iustin Pop
        disks=[(constants.DDM_ADD, {"size": self.disk_size[0]})])
664 5c22d16e Iustin Pop
      op_rem = opcodes.OpSetInstanceParams(\
665 5c22d16e Iustin Pop
        instance_name=instance, disks=[(constants.DDM_REMOVE, {})])
666 c723c163 Iustin Pop
      op_stop = self.StopInstanceOp(instance)
667 c723c163 Iustin Pop
      op_start = self.StartInstanceOp(instance)
668 836d59d7 Iustin Pop
      Log("adding a disk", indent=2)
669 836d59d7 Iustin Pop
      Log("removing last disk", indent=2)
670 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op_add, op_stop, op_rem, op_start)
671 c723c163 Iustin Pop
    self.CommitQueue()
672 5178f1bc Iustin Pop
    for instance in self.instances:
673 5178f1bc Iustin Pop
      self._CheckInstanceAlive(instance)
674 5c22d16e Iustin Pop
675 c723c163 Iustin Pop
  def BurnAddRemoveNICs(self):
676 5c22d16e Iustin Pop
    """Add and remove an extra NIC for the instances."""
677 836d59d7 Iustin Pop
    Log("Adding and removing NICs")
678 5c22d16e Iustin Pop
    for instance in self.instances:
679 836d59d7 Iustin Pop
      Log("instance %s" % instance, indent=1)
680 5c22d16e Iustin Pop
      op_add = opcodes.OpSetInstanceParams(\
681 5c22d16e Iustin Pop
        instance_name=instance, nics=[(constants.DDM_ADD, {})])
682 5c22d16e Iustin Pop
      op_rem = opcodes.OpSetInstanceParams(\
683 5c22d16e Iustin Pop
        instance_name=instance, nics=[(constants.DDM_REMOVE, {})])
684 836d59d7 Iustin Pop
      Log("adding a NIC", indent=2)
685 836d59d7 Iustin Pop
      Log("removing last NIC", indent=2)
686 c723c163 Iustin Pop
      self.ExecOrQueue(instance, op_add, op_rem)
687 c723c163 Iustin Pop
    self.CommitQueue()
688 5c22d16e Iustin Pop
689 5178f1bc Iustin Pop
  def _CheckInstanceAlive(self, instance):
690 5178f1bc Iustin Pop
    """Check if an instance is alive by doing http checks.
691 5178f1bc Iustin Pop
692 5178f1bc Iustin Pop
    This will try to retrieve the url on the instance /hostname.txt
693 5178f1bc Iustin Pop
    and check that it contains the hostname of the instance. In case
694 5178f1bc Iustin Pop
    we get ECONNREFUSED, we retry up to the net timeout seconds, for
695 5178f1bc Iustin Pop
    any other error we abort.
696 5178f1bc Iustin Pop
697 5178f1bc Iustin Pop
    """
698 5178f1bc Iustin Pop
    if not self.opts.http_check:
699 5178f1bc Iustin Pop
      return
700 5dc626fd Iustin Pop
    end_time = time.time() + self.opts.net_timeout
701 5dc626fd Iustin Pop
    url = None
702 5dc626fd Iustin Pop
    while time.time() < end_time and url is None:
703 5dc626fd Iustin Pop
      try:
704 5dc626fd Iustin Pop
        url = self.url_opener.open("http://%s/hostname.txt" % instance)
705 c723c163 Iustin Pop
      except IOError:
706 5dc626fd Iustin Pop
        # here we can have connection refused, no route to host, etc.
707 5dc626fd Iustin Pop
        time.sleep(1)
708 5dc626fd Iustin Pop
    if url is None:
709 5dc626fd Iustin Pop
      raise InstanceDown(instance, "Cannot contact instance")
710 5178f1bc Iustin Pop
    hostname = url.read().strip()
711 5dc626fd Iustin Pop
    url.close()
712 5178f1bc Iustin Pop
    if hostname != instance:
713 5178f1bc Iustin Pop
      raise InstanceDown(instance, ("Hostname mismatch, expected %s, got %s" %
714 5178f1bc Iustin Pop
                                    (instance, hostname)))
715 5178f1bc Iustin Pop
716 175f44c2 Iustin Pop
  def BurninCluster(self):
717 175f44c2 Iustin Pop
    """Test a cluster intensively.
718 175f44c2 Iustin Pop
719 175f44c2 Iustin Pop
    This will create instances and then start/stop/failover them.
720 175f44c2 Iustin Pop
    It is safe for existing instances but could impact performance.
721 175f44c2 Iustin Pop
722 175f44c2 Iustin Pop
    """
723 175f44c2 Iustin Pop
724 175f44c2 Iustin Pop
    opts = self.opts
725 175f44c2 Iustin Pop
726 836d59d7 Iustin Pop
    Log("Testing global parameters")
727 175f44c2 Iustin Pop
728 bd249e2f Iustin Pop
    if (len(self.nodes) == 1 and
729 2f505cb5 Manuel Franceschini
        opts.disk_template not in (constants.DT_DISKLESS, constants.DT_PLAIN,
730 2f505cb5 Manuel Franceschini
                                   constants.DT_FILE)):
731 836d59d7 Iustin Pop
      Err("When one node is available/selected the disk template must"
732 2f505cb5 Manuel Franceschini
          " be 'diskless', 'file' or 'plain'")
733 175f44c2 Iustin Pop
734 21546b1c Iustin Pop
    has_err = True
735 175f44c2 Iustin Pop
    try:
736 c723c163 Iustin Pop
      self.BurnCreateInstances()
737 175f44c2 Iustin Pop
      if opts.do_replace1 and opts.disk_template in constants.DTS_NET_MIRROR:
738 c723c163 Iustin Pop
        self.BurnReplaceDisks1D8()
739 175f44c2 Iustin Pop
      if (opts.do_replace2 and len(self.nodes) > 2 and
740 175f44c2 Iustin Pop
          opts.disk_template in constants.DTS_NET_MIRROR) :
741 c723c163 Iustin Pop
        self.BurnReplaceDisks2()
742 175f44c2 Iustin Pop
743 aa089b65 Iustin Pop
      if (opts.disk_template != constants.DT_DISKLESS and
744 aa089b65 Iustin Pop
          utils.any(self.disk_growth, lambda n: n > 0)):
745 c723c163 Iustin Pop
        self.BurnGrowDisks()
746 659712c8 Iustin Pop
747 175f44c2 Iustin Pop
      if opts.do_failover and opts.disk_template in constants.DTS_NET_MIRROR:
748 c723c163 Iustin Pop
        self.BurnFailover()
749 175f44c2 Iustin Pop
750 99bdd139 Iustin Pop
      if opts.do_migrate and opts.disk_template == constants.DT_DRBD8:
751 c723c163 Iustin Pop
        self.BurnMigrate()
752 99bdd139 Iustin Pop
753 a5e7be6b Iustin Pop
      if (opts.do_importexport and
754 a5e7be6b Iustin Pop
          opts.disk_template not in (constants.DT_DISKLESS,
755 a5e7be6b Iustin Pop
                                     constants.DT_FILE)):
756 c723c163 Iustin Pop
        self.BurnImportExport()
757 bd5e77f9 Guido Trotter
758 00f91f29 Iustin Pop
      if opts.do_reinstall:
759 c723c163 Iustin Pop
        self.BurnReinstall()
760 00f91f29 Iustin Pop
761 00f91f29 Iustin Pop
      if opts.do_reboot:
762 c723c163 Iustin Pop
        self.BurnReboot()
763 00f91f29 Iustin Pop
764 5c22d16e Iustin Pop
      if opts.do_addremove_disks:
765 c723c163 Iustin Pop
        self.BurnAddRemoveDisks()
766 5c22d16e Iustin Pop
767 5c22d16e Iustin Pop
      if opts.do_addremove_nics:
768 c723c163 Iustin Pop
        self.BurnAddRemoveNICs()
769 5c22d16e Iustin Pop
770 90e722d1 Iustin Pop
      if opts.do_activate_disks:
771 c723c163 Iustin Pop
        self.BurnActivateDisks()
772 90e722d1 Iustin Pop
773 054a8696 Manuel Franceschini
      if opts.rename:
774 c723c163 Iustin Pop
        self.BurnRename()
775 054a8696 Manuel Franceschini
776 eb61f8d3 Iustin Pop
      if opts.do_startstop:
777 c723c163 Iustin Pop
        self.BurnStopStart()
778 eb61f8d3 Iustin Pop
779 21546b1c Iustin Pop
      has_err = False
780 175f44c2 Iustin Pop
    finally:
781 21546b1c Iustin Pop
      if has_err:
782 21546b1c Iustin Pop
        Log("Error detected: opcode buffer follows:\n\n")
783 21546b1c Iustin Pop
        Log(self.GetFeedbackBuf())
784 21546b1c Iustin Pop
        Log("\n\n")
785 320eda24 Iustin Pop
      if not self.opts.keep_instances:
786 c723c163 Iustin Pop
        self.BurnRemove()
787 175f44c2 Iustin Pop
788 175f44c2 Iustin Pop
    return 0
789 a8083063 Iustin Pop
790 01b69ec5 Michael Hanselmann
791 a8083063 Iustin Pop
def main():
792 3ecf6786 Iustin Pop
  """Main function"""
793 3ecf6786 Iustin Pop
794 175f44c2 Iustin Pop
  burner = Burner()
795 a4af651e Iustin Pop
  return burner.BurninCluster()
796 a8083063 Iustin Pop
797 01b69ec5 Michael Hanselmann
798 a8083063 Iustin Pop
if __name__ == "__main__":
799 3ecf6786 Iustin Pop
  main()