Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 6605411d

History | View | Annotate | Download (17.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 175f44c2 Iustin Pop
from itertools import izip, islice, cycle
31 21546b1c Iustin Pop
from cStringIO import StringIO
32 a8083063 Iustin Pop
33 a8083063 Iustin Pop
from ganeti import opcodes
34 a8083063 Iustin Pop
from ganeti import mcpu
35 a8083063 Iustin Pop
from ganeti import constants
36 a8083063 Iustin Pop
from ganeti import cli
37 a8083063 Iustin Pop
from ganeti import logger
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 a8083063 Iustin Pop
def Usage():
46 a8083063 Iustin Pop
  """Shows program usage information and exits the program."""
47 a8083063 Iustin Pop
48 a8083063 Iustin Pop
  print >> sys.stderr, "Usage:"
49 a8083063 Iustin Pop
  print >> sys.stderr, USAGE
50 a8083063 Iustin Pop
  sys.exit(2)
51 a8083063 Iustin Pop
52 01b69ec5 Michael Hanselmann
53 21546b1c Iustin Pop
def Log(msg):
54 3ecf6786 Iustin Pop
  """Simple function that prints out its argument.
55 3ecf6786 Iustin Pop
56 3ecf6786 Iustin Pop
  """
57 3ecf6786 Iustin Pop
  print msg
58 84cc52ab Michael Hanselmann
  sys.stdout.flush()
59 a8083063 Iustin Pop
60 01b69ec5 Michael Hanselmann
61 175f44c2 Iustin Pop
class Burner(object):
62 175f44c2 Iustin Pop
  """Burner class."""
63 175f44c2 Iustin Pop
64 175f44c2 Iustin Pop
  def __init__(self):
65 175f44c2 Iustin Pop
    """Constructor."""
66 59f187eb Iustin Pop
    logger.SetupLogging(constants.LOG_BURNIN, debug=False, stderr_logging=True)
67 21546b1c Iustin Pop
    self._feed_buf = StringIO()
68 175f44c2 Iustin Pop
    self.nodes = []
69 175f44c2 Iustin Pop
    self.instances = []
70 175f44c2 Iustin Pop
    self.to_rem = []
71 175f44c2 Iustin Pop
    self.opts = None
72 ec5c88dc Iustin Pop
    self.cl = cli.GetClient()
73 175f44c2 Iustin Pop
    self.ParseOptions()
74 175f44c2 Iustin Pop
    self.GetState()
75 175f44c2 Iustin Pop
76 21546b1c Iustin Pop
  def ClearFeedbackBuf(self):
77 21546b1c Iustin Pop
    """Clear the feedback buffer."""
78 21546b1c Iustin Pop
    self._feed_buf.truncate(0)
79 21546b1c Iustin Pop
80 21546b1c Iustin Pop
  def GetFeedbackBuf(self):
81 21546b1c Iustin Pop
    """Return the contents of the buffer."""
82 21546b1c Iustin Pop
    return self._feed_buf.getvalue()
83 21546b1c Iustin Pop
84 21546b1c Iustin Pop
  def Feedback(self, msg):
85 21546b1c Iustin Pop
    """Acumulate feedback in our buffer."""
86 e17188f4 Iustin Pop
    self._feed_buf.write("%s %s\n" % (time.ctime(utils.MergeTime(msg[0])),
87 e17188f4 Iustin Pop
                                      msg[2]))
88 d7b47a77 Iustin Pop
    if self.opts.verbose:
89 d7b47a77 Iustin Pop
      Log(msg)
90 21546b1c Iustin Pop
91 21546b1c Iustin Pop
  def ExecOp(self, op):
92 21546b1c Iustin Pop
    """Execute an opcode and manage the exec buffer."""
93 21546b1c Iustin Pop
    self.ClearFeedbackBuf()
94 ec5c88dc Iustin Pop
    return cli.SubmitOpCode(op, feedback_fn=self.Feedback, cl=self.cl)
95 ec5c88dc Iustin Pop
96 ec5c88dc Iustin Pop
  def ExecJobSet(self, jobs):
97 ec5c88dc Iustin Pop
    """Execute a set of jobs and return once all are done.
98 ec5c88dc Iustin Pop
99 ec5c88dc Iustin Pop
    The method will return the list of results, if all jobs are
100 ec5c88dc Iustin Pop
    successfull. Otherwise, OpExecError will be raised from within
101 ec5c88dc Iustin Pop
    cli.py.
102 ec5c88dc Iustin Pop
103 ec5c88dc Iustin Pop
    """
104 ec5c88dc Iustin Pop
    self.ClearFeedbackBuf()
105 ec5c88dc Iustin Pop
    job_ids = [cli.SendJob(job, cl=self.cl) for job in jobs]
106 ec5c88dc Iustin Pop
    Log("- Submitted job IDs %s" % ", ".join(job_ids))
107 ec5c88dc Iustin Pop
    results = []
108 ec5c88dc Iustin Pop
    for jid in job_ids:
109 ec5c88dc Iustin Pop
      Log("- Waiting for job %s" % jid)
110 ec5c88dc Iustin Pop
      results.append(cli.PollJob(jid, cl=self.cl, feedback_fn=self.Feedback))
111 ec5c88dc Iustin Pop
112 ec5c88dc Iustin Pop
    return results
113 21546b1c Iustin Pop
114 175f44c2 Iustin Pop
  def ParseOptions(self):
115 175f44c2 Iustin Pop
    """Parses the command line options.
116 175f44c2 Iustin Pop
117 175f44c2 Iustin Pop
    In case of command line errors, it will show the usage and exit the
118 175f44c2 Iustin Pop
    program.
119 175f44c2 Iustin Pop
120 175f44c2 Iustin Pop
    """
121 175f44c2 Iustin Pop
122 175f44c2 Iustin Pop
    parser = optparse.OptionParser(usage="\n%s" % USAGE,
123 175f44c2 Iustin Pop
                                   version="%%prog (ganeti) %s" %
124 175f44c2 Iustin Pop
                                   constants.RELEASE_VERSION,
125 175f44c2 Iustin Pop
                                   option_class=cli.CliOption)
126 175f44c2 Iustin Pop
127 175f44c2 Iustin Pop
    parser.add_option("-o", "--os", dest="os", default=None,
128 175f44c2 Iustin Pop
                      help="OS to use during burnin",
129 175f44c2 Iustin Pop
                      metavar="<OS>")
130 175f44c2 Iustin Pop
    parser.add_option("--os-size", dest="os_size", help="Disk size",
131 175f44c2 Iustin Pop
                      default=4 * 1024, type="unit", metavar="<size>")
132 659712c8 Iustin Pop
    parser.add_option("--os-growth", dest="sda_growth", help="Disk growth",
133 659712c8 Iustin Pop
                      default=1024, type="unit", metavar="<size>")
134 175f44c2 Iustin Pop
    parser.add_option("--swap-size", dest="swap_size", help="Swap size",
135 175f44c2 Iustin Pop
                      default=4 * 1024, type="unit", metavar="<size>")
136 659712c8 Iustin Pop
    parser.add_option("--swap-growth", dest="sdb_growth", help="Swap growth",
137 659712c8 Iustin Pop
                      default=1024, type="unit", metavar="<size>")
138 5e767b34 Iustin Pop
    parser.add_option("--mem-size", dest="mem_size", help="Memory size",
139 5e767b34 Iustin Pop
                      default=128, type="unit", metavar="<size>")
140 175f44c2 Iustin Pop
    parser.add_option("-v", "--verbose",
141 175f44c2 Iustin Pop
                      action="store_true", dest="verbose", default=False,
142 175f44c2 Iustin Pop
                      help="print command execution messages to stdout")
143 175f44c2 Iustin Pop
    parser.add_option("--no-replace1", dest="do_replace1",
144 175f44c2 Iustin Pop
                      help="Skip disk replacement with the same secondary",
145 175f44c2 Iustin Pop
                      action="store_false", default=True)
146 175f44c2 Iustin Pop
    parser.add_option("--no-replace2", dest="do_replace2",
147 175f44c2 Iustin Pop
                      help="Skip disk replacement with a different secondary",
148 175f44c2 Iustin Pop
                      action="store_false", default=True)
149 175f44c2 Iustin Pop
    parser.add_option("--no-failover", dest="do_failover",
150 175f44c2 Iustin Pop
                      help="Skip instance failovers", action="store_false",
151 175f44c2 Iustin Pop
                      default=True)
152 bd5e77f9 Guido Trotter
    parser.add_option("--no-importexport", dest="do_importexport",
153 bd5e77f9 Guido Trotter
                      help="Skip instance export/import", action="store_false",
154 bd5e77f9 Guido Trotter
                      default=True)
155 d4844f0f Guido Trotter
    parser.add_option("--no-startstop", dest="do_startstop",
156 d4844f0f Guido Trotter
                      help="Skip instance stop/start", action="store_false",
157 d4844f0f Guido Trotter
                      default=True)
158 054a8696 Manuel Franceschini
    parser.add_option("--rename", dest="rename", default=None,
159 054a8696 Manuel Franceschini
                      help="Give one unused instance name which is taken"
160 054a8696 Manuel Franceschini
                           " to start the renaming sequence",
161 054a8696 Manuel Franceschini
                      metavar="<instance_name>")
162 175f44c2 Iustin Pop
    parser.add_option("-t", "--disk-template", dest="disk_template",
163 2f505cb5 Manuel Franceschini
                      choices=("diskless", "file", "plain", "drbd"),
164 f9193417 Iustin Pop
                      default="drbd",
165 2f505cb5 Manuel Franceschini
                      help="Disk template (diskless, file, plain or drbd)"
166 2f505cb5 Manuel Franceschini
                            " [drbd]")
167 175f44c2 Iustin Pop
    parser.add_option("-n", "--nodes", dest="nodes", default="",
168 175f44c2 Iustin Pop
                      help="Comma separated list of nodes to perform"
169 175f44c2 Iustin Pop
                      " the burnin on (defaults to all nodes)")
170 b91bde14 Iustin Pop
    parser.add_option("--iallocator", dest="iallocator",
171 b91bde14 Iustin Pop
                      default=None, type="string",
172 b91bde14 Iustin Pop
                      help="Perform the allocation using an iallocator"
173 b91bde14 Iustin Pop
                      " instead of fixed node spread (node restrictions no"
174 b91bde14 Iustin Pop
                      " longer apply, therefore -n/--nodes must not be used")
175 ec5c88dc Iustin Pop
    parser.add_option("-p", "--parallel", default=False, action="store_true",
176 ec5c88dc Iustin Pop
                      dest="parallel",
177 ec5c88dc Iustin Pop
                      help="Enable parallelization of some operations in"
178 ec5c88dc Iustin Pop
                      " order to speed burnin or to test granular locking")
179 175f44c2 Iustin Pop
180 175f44c2 Iustin Pop
    options, args = parser.parse_args()
181 175f44c2 Iustin Pop
    if len(args) < 1 or options.os is None:
182 175f44c2 Iustin Pop
      Usage()
183 175f44c2 Iustin Pop
184 f9193417 Iustin Pop
    supported_disk_templates = (constants.DT_DISKLESS,
185 2f505cb5 Manuel Franceschini
                                constants.DT_FILE,
186 f9193417 Iustin Pop
                                constants.DT_PLAIN,
187 12c3449a Michael Hanselmann
                                constants.DT_DRBD8)
188 12c3449a Michael Hanselmann
    if options.disk_template not in supported_disk_templates:
189 21546b1c Iustin Pop
      Log("Unknown disk template '%s'" % options.disk_template)
190 175f44c2 Iustin Pop
      sys.exit(1)
191 175f44c2 Iustin Pop
192 b91bde14 Iustin Pop
    if options.nodes and options.iallocator:
193 b91bde14 Iustin Pop
      Log("Give either the nodes option or the iallocator option, not both")
194 b91bde14 Iustin Pop
      sys.exit(1)
195 b91bde14 Iustin Pop
196 175f44c2 Iustin Pop
    self.opts = options
197 175f44c2 Iustin Pop
    self.instances = args
198 338e51e8 Iustin Pop
    self.bep = {
199 338e51e8 Iustin Pop
      constants.BE_MEMORY: options.mem_size,
200 338e51e8 Iustin Pop
      constants.BE_VCPUS: 1,
201 338e51e8 Iustin Pop
      }
202 338e51e8 Iustin Pop
    self.hvp = {}
203 175f44c2 Iustin Pop
204 175f44c2 Iustin Pop
  def GetState(self):
205 175f44c2 Iustin Pop
    """Read the cluster state from the config."""
206 175f44c2 Iustin Pop
    if self.opts.nodes:
207 175f44c2 Iustin Pop
      names = self.opts.nodes.split(",")
208 175f44c2 Iustin Pop
    else:
209 175f44c2 Iustin Pop
      names = []
210 175f44c2 Iustin Pop
    try:
211 175f44c2 Iustin Pop
      op = opcodes.OpQueryNodes(output_fields=["name"], names=names)
212 21546b1c Iustin Pop
      result = self.ExecOp(op)
213 175f44c2 Iustin Pop
    except errors.GenericError, err:
214 175f44c2 Iustin Pop
      err_code, msg = cli.FormatError(err)
215 21546b1c Iustin Pop
      Log(msg)
216 175f44c2 Iustin Pop
      sys.exit(err_code)
217 175f44c2 Iustin Pop
    self.nodes = [data[0] for data in result]
218 175f44c2 Iustin Pop
219 1f9430d6 Iustin Pop
    result = self.ExecOp(opcodes.OpDiagnoseOS(output_fields=["name", "valid"],
220 1f9430d6 Iustin Pop
                                              names=[]))
221 175f44c2 Iustin Pop
222 175f44c2 Iustin Pop
    if not result:
223 21546b1c Iustin Pop
      Log("Can't get the OS list")
224 175f44c2 Iustin Pop
      sys.exit(1)
225 175f44c2 Iustin Pop
226 175f44c2 Iustin Pop
    # filter non-valid OS-es
227 1f9430d6 Iustin Pop
    os_set = [val[0] for val in result if val[1]]
228 175f44c2 Iustin Pop
229 175f44c2 Iustin Pop
    if self.opts.os not in os_set:
230 21546b1c Iustin Pop
      Log("OS '%s' not found" % self.opts.os)
231 175f44c2 Iustin Pop
      sys.exit(1)
232 175f44c2 Iustin Pop
233 175f44c2 Iustin Pop
  def CreateInstances(self):
234 175f44c2 Iustin Pop
    """Create the given instances.
235 175f44c2 Iustin Pop
236 175f44c2 Iustin Pop
    """
237 175f44c2 Iustin Pop
    self.to_rem = []
238 175f44c2 Iustin Pop
    mytor = izip(cycle(self.nodes),
239 175f44c2 Iustin Pop
                 islice(cycle(self.nodes), 1, None),
240 175f44c2 Iustin Pop
                 self.instances)
241 ec5c88dc Iustin Pop
    jobset = []
242 338e51e8 Iustin Pop
243 175f44c2 Iustin Pop
    for pnode, snode, instance in mytor:
244 b91bde14 Iustin Pop
      if self.opts.iallocator:
245 b91bde14 Iustin Pop
        pnode = snode = None
246 6d54548e Guido Trotter
        Log("- Add instance %s (iallocator: %s)" %
247 6d54548e Guido Trotter
              (instance, self.opts.iallocator))
248 6d54548e Guido Trotter
      elif self.opts.disk_template not in constants.DTS_NET_MIRROR:
249 6d54548e Guido Trotter
        snode = None
250 6d54548e Guido Trotter
        Log("- Add instance %s on node %s" % (instance, pnode))
251 6d54548e Guido Trotter
      else:
252 6d54548e Guido Trotter
        Log("- Add instance %s on nodes %s/%s" % (instance, pnode, snode))
253 6d54548e Guido Trotter
254 175f44c2 Iustin Pop
      op = opcodes.OpCreateInstance(instance_name=instance,
255 175f44c2 Iustin Pop
                                    disk_size=self.opts.os_size,
256 175f44c2 Iustin Pop
                                    swap_size=self.opts.swap_size,
257 175f44c2 Iustin Pop
                                    disk_template=self.opts.disk_template,
258 a8083063 Iustin Pop
                                    mode=constants.INSTANCE_CREATE,
259 175f44c2 Iustin Pop
                                    os_type=self.opts.os,
260 175f44c2 Iustin Pop
                                    pnode=pnode,
261 175f44c2 Iustin Pop
                                    snode=snode,
262 a8083063 Iustin Pop
                                    start=True,
263 e9f745aa Iustin Pop
                                    ip_check=True,
264 4501af56 Iustin Pop
                                    wait_for_sync=True,
265 4501af56 Iustin Pop
                                    mac="auto",
266 2f505cb5 Manuel Franceschini
                                    file_driver="loop",
267 b91bde14 Iustin Pop
                                    file_storage_dir=None,
268 6e2dc934 Alexander Schreiber
                                    iallocator=self.opts.iallocator,
269 338e51e8 Iustin Pop
                                    beparams=self.bep,
270 338e51e8 Iustin Pop
                                    hvparams=self.hvp,
271 338e51e8 Iustin Pop
                                    )
272 6e2dc934 Alexander Schreiber
273 ec5c88dc Iustin Pop
      if self.opts.parallel:
274 ec5c88dc Iustin Pop
        jobset.append([op])
275 ec5c88dc Iustin Pop
        # FIXME: here we should not append to to_rem uncoditionally,
276 ec5c88dc Iustin Pop
        # but only when the job is successful
277 ec5c88dc Iustin Pop
        self.to_rem.append(instance)
278 ec5c88dc Iustin Pop
      else:
279 ec5c88dc Iustin Pop
        self.ExecOp(op)
280 ec5c88dc Iustin Pop
        self.to_rem.append(instance)
281 ec5c88dc Iustin Pop
    if self.opts.parallel:
282 ec5c88dc Iustin Pop
      self.ExecJobSet(jobset)
283 175f44c2 Iustin Pop
284 659712c8 Iustin Pop
  def GrowDisks(self):
285 659712c8 Iustin Pop
    """Grow both the os and the swap disks by the requested amount, if any."""
286 659712c8 Iustin Pop
    for instance in self.instances:
287 659712c8 Iustin Pop
      for disk in ['sda', 'sdb']:
288 659712c8 Iustin Pop
        growth = getattr(self.opts, '%s_growth' % disk)
289 659712c8 Iustin Pop
        if growth > 0:
290 659712c8 Iustin Pop
          op = opcodes.OpGrowDisk(instance_name=instance, disk=disk,
291 6605411d Iustin Pop
                                  amount=growth, wait_for_sync=True)
292 659712c8 Iustin Pop
          Log("- Increase %s's %s disk by %s MB" % (instance, disk, growth))
293 659712c8 Iustin Pop
          self.ExecOp(op)
294 659712c8 Iustin Pop
295 175f44c2 Iustin Pop
  def ReplaceDisks1D8(self):
296 175f44c2 Iustin Pop
    """Replace disks on primary and secondary for drbd8."""
297 175f44c2 Iustin Pop
    for instance in self.instances:
298 175f44c2 Iustin Pop
      for mode in constants.REPLACE_DISK_SEC, constants.REPLACE_DISK_PRI:
299 175f44c2 Iustin Pop
        op = opcodes.OpReplaceDisks(instance_name=instance,
300 175f44c2 Iustin Pop
                                    mode=mode,
301 175f44c2 Iustin Pop
                                    disks=["sda", "sdb"])
302 21546b1c Iustin Pop
        Log("- Replace disks (%s) for instance %s" % (mode, instance))
303 21546b1c Iustin Pop
        self.ExecOp(op)
304 175f44c2 Iustin Pop
305 175f44c2 Iustin Pop
  def ReplaceDisks2(self):
306 175f44c2 Iustin Pop
    """Replace secondary node."""
307 f9193417 Iustin Pop
    mode = constants.REPLACE_DISK_SEC
308 175f44c2 Iustin Pop
309 175f44c2 Iustin Pop
    mytor = izip(islice(cycle(self.nodes), 2, None),
310 175f44c2 Iustin Pop
                 self.instances)
311 175f44c2 Iustin Pop
    for tnode, instance in mytor:
312 b6e82a65 Iustin Pop
      if self.opts.iallocator:
313 b6e82a65 Iustin Pop
        tnode = None
314 175f44c2 Iustin Pop
      op = opcodes.OpReplaceDisks(instance_name=instance,
315 175f44c2 Iustin Pop
                                  mode=mode,
316 175f44c2 Iustin Pop
                                  remote_node=tnode,
317 b6e82a65 Iustin Pop
                                  iallocator=self.opts.iallocator,
318 175f44c2 Iustin Pop
                                  disks=["sda", "sdb"])
319 21546b1c Iustin Pop
      Log("- Replace secondary (%s) for instance %s" % (mode, instance))
320 21546b1c Iustin Pop
      self.ExecOp(op)
321 175f44c2 Iustin Pop
322 175f44c2 Iustin Pop
  def Failover(self):
323 175f44c2 Iustin Pop
    """Failover the instances."""
324 175f44c2 Iustin Pop
325 175f44c2 Iustin Pop
    for instance in self.instances:
326 175f44c2 Iustin Pop
      op = opcodes.OpFailoverInstance(instance_name=instance,
327 175f44c2 Iustin Pop
                                      ignore_consistency=False)
328 175f44c2 Iustin Pop
329 21546b1c Iustin Pop
      Log("- Failover instance %s" % (instance))
330 21546b1c Iustin Pop
      self.ExecOp(op)
331 175f44c2 Iustin Pop
332 bd5e77f9 Guido Trotter
  def ImportExport(self):
333 bd5e77f9 Guido Trotter
    """Export the instance, delete it, and import it back.
334 bd5e77f9 Guido Trotter
335 bd5e77f9 Guido Trotter
    """
336 bd5e77f9 Guido Trotter
337 bd5e77f9 Guido Trotter
    mytor = izip(cycle(self.nodes),
338 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 1, None),
339 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 2, None),
340 bd5e77f9 Guido Trotter
                 self.instances)
341 bd5e77f9 Guido Trotter
342 bd5e77f9 Guido Trotter
    for pnode, snode, enode, instance in mytor:
343 f9af35c8 Guido Trotter
344 f9af35c8 Guido Trotter
      if self.opts.iallocator:
345 f9af35c8 Guido Trotter
        pnode = snode = None
346 f9af35c8 Guido Trotter
        import_log_msg = ("- Import instance %s from node %s (iallocator: %s)" %
347 f9af35c8 Guido Trotter
                          (instance, enode, self.opts.iallocator))
348 f9af35c8 Guido Trotter
      elif self.opts.disk_template not in constants.DTS_NET_MIRROR:
349 f9af35c8 Guido Trotter
        snode = None
350 f9af35c8 Guido Trotter
        import_log_msg = ("- Import instance %s from node %s to node %s" %
351 f9af35c8 Guido Trotter
                          (instance, enode, pnode))
352 f9af35c8 Guido Trotter
      else:
353 f9af35c8 Guido Trotter
        import_log_msg = ("- Import instance %s from node %s to nodes %s/%s" %
354 f9af35c8 Guido Trotter
                          (instance, enode, pnode, snode))
355 f9af35c8 Guido Trotter
356 bd5e77f9 Guido Trotter
      exp_op = opcodes.OpExportInstance(instance_name=instance,
357 bd5e77f9 Guido Trotter
                                           target_node=enode,
358 bd5e77f9 Guido Trotter
                                           shutdown=True)
359 5c54b832 Iustin Pop
      rem_op = opcodes.OpRemoveInstance(instance_name=instance,
360 5c54b832 Iustin Pop
                                        ignore_failures=True)
361 bd5e77f9 Guido Trotter
      nam_op = opcodes.OpQueryInstances(output_fields=["name"],
362 bd5e77f9 Guido Trotter
                                           names=[instance])
363 bd5e77f9 Guido Trotter
      full_name = self.ExecOp(nam_op)[0][0]
364 bd5e77f9 Guido Trotter
      imp_dir = os.path.join(constants.EXPORT_DIR, full_name)
365 bd5e77f9 Guido Trotter
      imp_op = opcodes.OpCreateInstance(instance_name=instance,
366 bd5e77f9 Guido Trotter
                                        disk_size=self.opts.os_size,
367 bd5e77f9 Guido Trotter
                                        swap_size=self.opts.swap_size,
368 bd5e77f9 Guido Trotter
                                        disk_template=self.opts.disk_template,
369 bd5e77f9 Guido Trotter
                                        mode=constants.INSTANCE_IMPORT,
370 bd5e77f9 Guido Trotter
                                        src_node=enode,
371 bd5e77f9 Guido Trotter
                                        src_path=imp_dir,
372 bd5e77f9 Guido Trotter
                                        pnode=pnode,
373 bd5e77f9 Guido Trotter
                                        snode=snode,
374 bd5e77f9 Guido Trotter
                                        start=True,
375 bd5e77f9 Guido Trotter
                                        ip_check=True,
376 bd5e77f9 Guido Trotter
                                        wait_for_sync=True,
377 96bb2f71 Manuel Franceschini
                                        mac="auto",
378 96bb2f71 Manuel Franceschini
                                        file_storage_dir=None,
379 f9af35c8 Guido Trotter
                                        file_driver=None,
380 6e2dc934 Alexander Schreiber
                                        iallocator=self.opts.iallocator,
381 338e51e8 Iustin Pop
                                        beparams=self.bep,
382 338e51e8 Iustin Pop
                                        hvparams=self.hvp,
383 338e51e8 Iustin Pop
                                        )
384 6e2dc934 Alexander Schreiber
385 4a7ff493 Guido Trotter
      erem_op = opcodes.OpRemoveExport(instance_name=instance)
386 bd5e77f9 Guido Trotter
387 bd5e77f9 Guido Trotter
      Log("- Export instance %s to node %s" % (instance, enode))
388 bd5e77f9 Guido Trotter
      self.ExecOp(exp_op)
389 bd5e77f9 Guido Trotter
      Log("- Remove instance %s" % (instance))
390 bd5e77f9 Guido Trotter
      self.ExecOp(rem_op)
391 bd5e77f9 Guido Trotter
      self.to_rem.remove(instance)
392 f9af35c8 Guido Trotter
      Log(import_log_msg)
393 bd5e77f9 Guido Trotter
      self.ExecOp(imp_op)
394 4a7ff493 Guido Trotter
      Log("- Remove export of instance %s" % (instance))
395 4a7ff493 Guido Trotter
      self.ExecOp(erem_op)
396 4a7ff493 Guido Trotter
397 bd5e77f9 Guido Trotter
      self.to_rem.append(instance)
398 bd5e77f9 Guido Trotter
399 054a8696 Manuel Franceschini
  def StopInstance(self, instance):
400 054a8696 Manuel Franceschini
    """Stop given instance."""
401 054a8696 Manuel Franceschini
    op = opcodes.OpShutdownInstance(instance_name=instance)
402 054a8696 Manuel Franceschini
    Log("- Shutdown instance %s" % instance)
403 054a8696 Manuel Franceschini
    self.ExecOp(op)
404 054a8696 Manuel Franceschini
405 054a8696 Manuel Franceschini
  def StartInstance(self, instance):
406 054a8696 Manuel Franceschini
    """Start given instance."""
407 054a8696 Manuel Franceschini
    op = opcodes.OpStartupInstance(instance_name=instance, force=False)
408 054a8696 Manuel Franceschini
    Log("- Start instance %s" % instance)
409 054a8696 Manuel Franceschini
    self.ExecOp(op)
410 054a8696 Manuel Franceschini
411 054a8696 Manuel Franceschini
  def RenameInstance(self, instance, instance_new):
412 054a8696 Manuel Franceschini
    """Rename instance."""
413 054a8696 Manuel Franceschini
    op = opcodes.OpRenameInstance(instance_name=instance,
414 054a8696 Manuel Franceschini
                                  new_name=instance_new)
415 054a8696 Manuel Franceschini
    Log("- Rename instance %s to %s" % (instance, instance_new))
416 054a8696 Manuel Franceschini
    self.ExecOp(op)
417 054a8696 Manuel Franceschini
418 175f44c2 Iustin Pop
  def StopStart(self):
419 175f44c2 Iustin Pop
    """Stop/start the instances."""
420 175f44c2 Iustin Pop
    for instance in self.instances:
421 054a8696 Manuel Franceschini
      self.StopInstance(instance)
422 054a8696 Manuel Franceschini
      self.StartInstance(instance)
423 175f44c2 Iustin Pop
424 175f44c2 Iustin Pop
  def Remove(self):
425 175f44c2 Iustin Pop
    """Remove the instances."""
426 175f44c2 Iustin Pop
    for instance in self.to_rem:
427 5c54b832 Iustin Pop
      op = opcodes.OpRemoveInstance(instance_name=instance,
428 5c54b832 Iustin Pop
                                    ignore_failures=True)
429 21546b1c Iustin Pop
      Log("- Remove instance %s" % instance)
430 21546b1c Iustin Pop
      self.ExecOp(op)
431 175f44c2 Iustin Pop
432 054a8696 Manuel Franceschini
433 054a8696 Manuel Franceschini
  def Rename(self):
434 054a8696 Manuel Franceschini
    """Rename the instances."""
435 054a8696 Manuel Franceschini
    rename = self.opts.rename
436 054a8696 Manuel Franceschini
    for instance in self.instances:
437 054a8696 Manuel Franceschini
      self.StopInstance(instance)
438 054a8696 Manuel Franceschini
      self.RenameInstance(instance, rename)
439 054a8696 Manuel Franceschini
      self.StartInstance(rename)
440 054a8696 Manuel Franceschini
      self.StopInstance(rename)
441 054a8696 Manuel Franceschini
      self.RenameInstance(rename, instance)
442 054a8696 Manuel Franceschini
      self.StartInstance(instance)
443 054a8696 Manuel Franceschini
444 175f44c2 Iustin Pop
  def BurninCluster(self):
445 175f44c2 Iustin Pop
    """Test a cluster intensively.
446 175f44c2 Iustin Pop
447 175f44c2 Iustin Pop
    This will create instances and then start/stop/failover them.
448 175f44c2 Iustin Pop
    It is safe for existing instances but could impact performance.
449 175f44c2 Iustin Pop
450 175f44c2 Iustin Pop
    """
451 175f44c2 Iustin Pop
452 175f44c2 Iustin Pop
    opts = self.opts
453 175f44c2 Iustin Pop
454 21546b1c Iustin Pop
    Log("- Testing global parameters")
455 175f44c2 Iustin Pop
456 bd249e2f Iustin Pop
    if (len(self.nodes) == 1 and
457 2f505cb5 Manuel Franceschini
        opts.disk_template not in (constants.DT_DISKLESS, constants.DT_PLAIN,
458 2f505cb5 Manuel Franceschini
                                   constants.DT_FILE)):
459 21546b1c Iustin Pop
      Log("When one node is available/selected the disk template must"
460 2f505cb5 Manuel Franceschini
          " be 'diskless', 'file' or 'plain'")
461 175f44c2 Iustin Pop
      sys.exit(1)
462 175f44c2 Iustin Pop
463 21546b1c Iustin Pop
    has_err = True
464 175f44c2 Iustin Pop
    try:
465 175f44c2 Iustin Pop
      self.CreateInstances()
466 175f44c2 Iustin Pop
      if opts.do_replace1 and opts.disk_template in constants.DTS_NET_MIRROR:
467 f9193417 Iustin Pop
        self.ReplaceDisks1D8()
468 175f44c2 Iustin Pop
      if (opts.do_replace2 and len(self.nodes) > 2 and
469 175f44c2 Iustin Pop
          opts.disk_template in constants.DTS_NET_MIRROR) :
470 175f44c2 Iustin Pop
        self.ReplaceDisks2()
471 175f44c2 Iustin Pop
472 659712c8 Iustin Pop
      if opts.disk_template != constants.DT_DISKLESS:
473 659712c8 Iustin Pop
        self.GrowDisks()
474 659712c8 Iustin Pop
475 175f44c2 Iustin Pop
      if opts.do_failover and opts.disk_template in constants.DTS_NET_MIRROR:
476 175f44c2 Iustin Pop
        self.Failover()
477 175f44c2 Iustin Pop
478 bd5e77f9 Guido Trotter
      if opts.do_importexport:
479 bd5e77f9 Guido Trotter
        self.ImportExport()
480 bd5e77f9 Guido Trotter
481 d4844f0f Guido Trotter
      if opts.do_startstop:
482 d4844f0f Guido Trotter
        self.StopStart()
483 d4844f0f Guido Trotter
484 054a8696 Manuel Franceschini
      if opts.rename:
485 054a8696 Manuel Franceschini
        self.Rename()
486 054a8696 Manuel Franceschini
487 21546b1c Iustin Pop
      has_err = False
488 175f44c2 Iustin Pop
    finally:
489 21546b1c Iustin Pop
      if has_err:
490 21546b1c Iustin Pop
        Log("Error detected: opcode buffer follows:\n\n")
491 21546b1c Iustin Pop
        Log(self.GetFeedbackBuf())
492 21546b1c Iustin Pop
        Log("\n\n")
493 175f44c2 Iustin Pop
      self.Remove()
494 175f44c2 Iustin Pop
495 175f44c2 Iustin Pop
    return 0
496 a8083063 Iustin Pop
497 01b69ec5 Michael Hanselmann
498 a8083063 Iustin Pop
def main():
499 3ecf6786 Iustin Pop
  """Main function"""
500 3ecf6786 Iustin Pop
501 175f44c2 Iustin Pop
  burner = Burner()
502 a4af651e Iustin Pop
  return burner.BurninCluster()
503 a8083063 Iustin Pop
504 01b69ec5 Michael Hanselmann
505 a8083063 Iustin Pop
if __name__ == "__main__":
506 3ecf6786 Iustin Pop
  main()