Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 82d9caef

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