Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ d7b47a77

History | View | Annotate | Download (13.5 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 175f44c2 Iustin Pop
from itertools import izip, islice, cycle
30 21546b1c Iustin Pop
from cStringIO import StringIO
31 a8083063 Iustin Pop
32 a8083063 Iustin Pop
from ganeti import opcodes
33 a8083063 Iustin Pop
from ganeti import mcpu
34 a8083063 Iustin Pop
from ganeti import constants
35 a8083063 Iustin Pop
from ganeti import cli
36 a8083063 Iustin Pop
from ganeti import logger
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 21546b1c Iustin Pop
    logger.SetupLogging(debug=False, program="ganeti/burnin")
66 21546b1c Iustin Pop
    self._feed_buf = StringIO()
67 21546b1c Iustin Pop
    self.proc = mcpu.Processor(feedback=self.Feedback)
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 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 21546b1c Iustin Pop
    self._feed_buf.write(msg)
86 21546b1c Iustin Pop
    self._feed_buf.write("\n")
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 21546b1c Iustin Pop
    return self.proc.ExecOpCode(op)
94 21546b1c Iustin Pop
95 175f44c2 Iustin Pop
  def ParseOptions(self):
96 175f44c2 Iustin Pop
    """Parses the command line options.
97 175f44c2 Iustin Pop
98 175f44c2 Iustin Pop
    In case of command line errors, it will show the usage and exit the
99 175f44c2 Iustin Pop
    program.
100 175f44c2 Iustin Pop
101 175f44c2 Iustin Pop
    """
102 175f44c2 Iustin Pop
103 175f44c2 Iustin Pop
    parser = optparse.OptionParser(usage="\n%s" % USAGE,
104 175f44c2 Iustin Pop
                                   version="%%prog (ganeti) %s" %
105 175f44c2 Iustin Pop
                                   constants.RELEASE_VERSION,
106 175f44c2 Iustin Pop
                                   option_class=cli.CliOption)
107 175f44c2 Iustin Pop
108 175f44c2 Iustin Pop
    parser.add_option("-o", "--os", dest="os", default=None,
109 175f44c2 Iustin Pop
                      help="OS to use during burnin",
110 175f44c2 Iustin Pop
                      metavar="<OS>")
111 175f44c2 Iustin Pop
    parser.add_option("--os-size", dest="os_size", help="Disk size",
112 175f44c2 Iustin Pop
                      default=4 * 1024, type="unit", metavar="<size>")
113 175f44c2 Iustin Pop
    parser.add_option("--swap-size", dest="swap_size", help="Swap size",
114 175f44c2 Iustin Pop
                      default=4 * 1024, type="unit", metavar="<size>")
115 175f44c2 Iustin Pop
    parser.add_option("-v", "--verbose",
116 175f44c2 Iustin Pop
                      action="store_true", dest="verbose", default=False,
117 175f44c2 Iustin Pop
                      help="print command execution messages to stdout")
118 175f44c2 Iustin Pop
    parser.add_option("--no-replace1", dest="do_replace1",
119 175f44c2 Iustin Pop
                      help="Skip disk replacement with the same secondary",
120 175f44c2 Iustin Pop
                      action="store_false", default=True)
121 175f44c2 Iustin Pop
    parser.add_option("--no-replace2", dest="do_replace2",
122 175f44c2 Iustin Pop
                      help="Skip disk replacement with a different secondary",
123 175f44c2 Iustin Pop
                      action="store_false", default=True)
124 175f44c2 Iustin Pop
    parser.add_option("--no-failover", dest="do_failover",
125 175f44c2 Iustin Pop
                      help="Skip instance failovers", action="store_false",
126 175f44c2 Iustin Pop
                      default=True)
127 bd5e77f9 Guido Trotter
    parser.add_option("--no-importexport", dest="do_importexport",
128 bd5e77f9 Guido Trotter
                      help="Skip instance export/import", action="store_false",
129 bd5e77f9 Guido Trotter
                      default=True)
130 d4844f0f Guido Trotter
    parser.add_option("--no-startstop", dest="do_startstop",
131 d4844f0f Guido Trotter
                      help="Skip instance stop/start", action="store_false",
132 d4844f0f Guido Trotter
                      default=True)
133 175f44c2 Iustin Pop
    parser.add_option("-t", "--disk-template", dest="disk_template",
134 bd249e2f Iustin Pop
                      choices=("diskless", "plain", "remote_raid1", "drbd"),
135 175f44c2 Iustin Pop
                      default="remote_raid1",
136 175f44c2 Iustin Pop
                      help="Template type for network mirroring (remote_raid1"
137 12c3449a Michael Hanselmann
                      " or drbd) [remote_raid1]")
138 175f44c2 Iustin Pop
    parser.add_option("-n", "--nodes", dest="nodes", default="",
139 175f44c2 Iustin Pop
                      help="Comma separated list of nodes to perform"
140 175f44c2 Iustin Pop
                      " the burnin on (defaults to all nodes)")
141 175f44c2 Iustin Pop
142 175f44c2 Iustin Pop
    options, args = parser.parse_args()
143 175f44c2 Iustin Pop
    if len(args) < 1 or options.os is None:
144 175f44c2 Iustin Pop
      Usage()
145 175f44c2 Iustin Pop
146 bd249e2f Iustin Pop
    supported_disk_templates = (constants.DT_DISKLESS, constants.DT_PLAIN,
147 bd249e2f Iustin Pop
                                constants.DT_REMOTE_RAID1,
148 12c3449a Michael Hanselmann
                                constants.DT_DRBD8)
149 12c3449a Michael Hanselmann
    if options.disk_template not in supported_disk_templates:
150 21546b1c Iustin Pop
      Log("Unknown disk template '%s'" % options.disk_template)
151 175f44c2 Iustin Pop
      sys.exit(1)
152 175f44c2 Iustin Pop
153 175f44c2 Iustin Pop
    self.opts = options
154 175f44c2 Iustin Pop
    self.instances = args
155 175f44c2 Iustin Pop
156 175f44c2 Iustin Pop
  def GetState(self):
157 175f44c2 Iustin Pop
    """Read the cluster state from the config."""
158 175f44c2 Iustin Pop
    if self.opts.nodes:
159 175f44c2 Iustin Pop
      names = self.opts.nodes.split(",")
160 175f44c2 Iustin Pop
    else:
161 175f44c2 Iustin Pop
      names = []
162 175f44c2 Iustin Pop
    try:
163 175f44c2 Iustin Pop
      op = opcodes.OpQueryNodes(output_fields=["name"], names=names)
164 21546b1c Iustin Pop
      result = self.ExecOp(op)
165 175f44c2 Iustin Pop
    except errors.GenericError, err:
166 175f44c2 Iustin Pop
      err_code, msg = cli.FormatError(err)
167 21546b1c Iustin Pop
      Log(msg)
168 175f44c2 Iustin Pop
      sys.exit(err_code)
169 175f44c2 Iustin Pop
    self.nodes = [data[0] for data in result]
170 175f44c2 Iustin Pop
171 21546b1c Iustin Pop
    result = self.ExecOp(opcodes.OpDiagnoseOS())
172 175f44c2 Iustin Pop
173 175f44c2 Iustin Pop
    if not result:
174 21546b1c Iustin Pop
      Log("Can't get the OS list")
175 175f44c2 Iustin Pop
      sys.exit(1)
176 175f44c2 Iustin Pop
177 175f44c2 Iustin Pop
    # filter non-valid OS-es
178 175f44c2 Iustin Pop
    oses = {}
179 175f44c2 Iustin Pop
    for node_name in result:
180 175f44c2 Iustin Pop
      oses[node_name] = [obj for obj in result[node_name] if obj]
181 175f44c2 Iustin Pop
182 175f44c2 Iustin Pop
    fnode = oses.keys()[0]
183 175f44c2 Iustin Pop
    os_set = set([os_inst.name for os_inst in oses[fnode]])
184 175f44c2 Iustin Pop
    del oses[fnode]
185 175f44c2 Iustin Pop
    for node in oses:
186 175f44c2 Iustin Pop
      os_set &= set([os_inst.name for os_inst in oses[node]])
187 175f44c2 Iustin Pop
188 175f44c2 Iustin Pop
    if self.opts.os not in os_set:
189 21546b1c Iustin Pop
      Log("OS '%s' not found" % self.opts.os)
190 175f44c2 Iustin Pop
      sys.exit(1)
191 175f44c2 Iustin Pop
192 175f44c2 Iustin Pop
  def CreateInstances(self):
193 175f44c2 Iustin Pop
    """Create the given instances.
194 175f44c2 Iustin Pop
195 175f44c2 Iustin Pop
    """
196 175f44c2 Iustin Pop
    self.to_rem = []
197 175f44c2 Iustin Pop
    mytor = izip(cycle(self.nodes),
198 175f44c2 Iustin Pop
                 islice(cycle(self.nodes), 1, None),
199 175f44c2 Iustin Pop
                 self.instances)
200 175f44c2 Iustin Pop
    for pnode, snode, instance in mytor:
201 175f44c2 Iustin Pop
      op = opcodes.OpCreateInstance(instance_name=instance,
202 175f44c2 Iustin Pop
                                    mem_size=128,
203 175f44c2 Iustin Pop
                                    disk_size=self.opts.os_size,
204 175f44c2 Iustin Pop
                                    swap_size=self.opts.swap_size,
205 175f44c2 Iustin Pop
                                    disk_template=self.opts.disk_template,
206 a8083063 Iustin Pop
                                    mode=constants.INSTANCE_CREATE,
207 175f44c2 Iustin Pop
                                    os_type=self.opts.os,
208 175f44c2 Iustin Pop
                                    pnode=pnode,
209 175f44c2 Iustin Pop
                                    snode=snode,
210 175f44c2 Iustin Pop
                                    vcpus=1,
211 a8083063 Iustin Pop
                                    start=True,
212 e9f745aa Iustin Pop
                                    ip_check=True,
213 4501af56 Iustin Pop
                                    wait_for_sync=True,
214 4501af56 Iustin Pop
                                    mac="auto",
215 4501af56 Iustin Pop
                                    kernel_path=None,
216 25c5878d Alexander Schreiber
                                    initrd_path=None,
217 25c5878d Alexander Schreiber
                                    hvm_boot_order=None)
218 d7b47a77 Iustin Pop
      Log("- Add instance %s on nodes %s/%s" % (instance, pnode, snode))
219 21546b1c Iustin Pop
      self.ExecOp(op)
220 175f44c2 Iustin Pop
      self.to_rem.append(instance)
221 175f44c2 Iustin Pop
222 175f44c2 Iustin Pop
  def ReplaceDisks1R1(self):
223 175f44c2 Iustin Pop
    """Replace disks with the same secondary for rr1."""
224 175f44c2 Iustin Pop
    # replace all, both disks
225 175f44c2 Iustin Pop
    for instance in self.instances:
226 175f44c2 Iustin Pop
      op = opcodes.OpReplaceDisks(instance_name=instance,
227 175f44c2 Iustin Pop
                                  remote_node=None,
228 175f44c2 Iustin Pop
                                  mode=constants.REPLACE_DISK_ALL,
229 175f44c2 Iustin Pop
                                  disks=["sda", "sdb"])
230 175f44c2 Iustin Pop
231 21546b1c Iustin Pop
      Log("- Replace disks for instance %s" % (instance))
232 21546b1c Iustin Pop
      self.ExecOp(op)
233 175f44c2 Iustin Pop
234 175f44c2 Iustin Pop
  def ReplaceDisks1D8(self):
235 175f44c2 Iustin Pop
    """Replace disks on primary and secondary for drbd8."""
236 175f44c2 Iustin Pop
    for instance in self.instances:
237 175f44c2 Iustin Pop
      for mode in constants.REPLACE_DISK_SEC, constants.REPLACE_DISK_PRI:
238 175f44c2 Iustin Pop
        op = opcodes.OpReplaceDisks(instance_name=instance,
239 175f44c2 Iustin Pop
                                    mode=mode,
240 175f44c2 Iustin Pop
                                    disks=["sda", "sdb"])
241 21546b1c Iustin Pop
        Log("- Replace disks (%s) for instance %s" % (mode, instance))
242 21546b1c Iustin Pop
        self.ExecOp(op)
243 175f44c2 Iustin Pop
244 175f44c2 Iustin Pop
  def ReplaceDisks2(self):
245 175f44c2 Iustin Pop
    """Replace secondary node."""
246 175f44c2 Iustin Pop
    if self.opts.disk_template == constants.DT_REMOTE_RAID1:
247 175f44c2 Iustin Pop
      mode = constants.REPLACE_DISK_ALL
248 175f44c2 Iustin Pop
    else:
249 175f44c2 Iustin Pop
      mode = constants.REPLACE_DISK_SEC
250 175f44c2 Iustin Pop
251 175f44c2 Iustin Pop
    mytor = izip(islice(cycle(self.nodes), 2, None),
252 175f44c2 Iustin Pop
                 self.instances)
253 175f44c2 Iustin Pop
    for tnode, instance in mytor:
254 175f44c2 Iustin Pop
      op = opcodes.OpReplaceDisks(instance_name=instance,
255 175f44c2 Iustin Pop
                                  mode=mode,
256 175f44c2 Iustin Pop
                                  remote_node=tnode,
257 175f44c2 Iustin Pop
                                  disks=["sda", "sdb"])
258 21546b1c Iustin Pop
      Log("- Replace secondary (%s) for instance %s" % (mode, instance))
259 21546b1c Iustin Pop
      self.ExecOp(op)
260 175f44c2 Iustin Pop
261 175f44c2 Iustin Pop
  def Failover(self):
262 175f44c2 Iustin Pop
    """Failover the instances."""
263 175f44c2 Iustin Pop
264 175f44c2 Iustin Pop
    for instance in self.instances:
265 175f44c2 Iustin Pop
      op = opcodes.OpFailoverInstance(instance_name=instance,
266 175f44c2 Iustin Pop
                                      ignore_consistency=False)
267 175f44c2 Iustin Pop
268 21546b1c Iustin Pop
      Log("- Failover instance %s" % (instance))
269 21546b1c Iustin Pop
      self.ExecOp(op)
270 175f44c2 Iustin Pop
271 bd5e77f9 Guido Trotter
  def ImportExport(self):
272 bd5e77f9 Guido Trotter
    """Export the instance, delete it, and import it back.
273 bd5e77f9 Guido Trotter
274 bd5e77f9 Guido Trotter
    """
275 bd5e77f9 Guido Trotter
276 bd5e77f9 Guido Trotter
    mytor = izip(cycle(self.nodes),
277 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 1, None),
278 bd5e77f9 Guido Trotter
                 islice(cycle(self.nodes), 2, None),
279 bd5e77f9 Guido Trotter
                 self.instances)
280 bd5e77f9 Guido Trotter
281 bd5e77f9 Guido Trotter
    for pnode, snode, enode, instance in mytor:
282 bd5e77f9 Guido Trotter
      exp_op = opcodes.OpExportInstance(instance_name=instance,
283 bd5e77f9 Guido Trotter
                                           target_node=enode,
284 bd5e77f9 Guido Trotter
                                           shutdown=True)
285 bd5e77f9 Guido Trotter
      rem_op = opcodes.OpRemoveInstance(instance_name=instance)
286 bd5e77f9 Guido Trotter
      nam_op = opcodes.OpQueryInstances(output_fields=["name"],
287 bd5e77f9 Guido Trotter
                                           names=[instance])
288 bd5e77f9 Guido Trotter
      full_name = self.ExecOp(nam_op)[0][0]
289 bd5e77f9 Guido Trotter
      imp_dir = os.path.join(constants.EXPORT_DIR, full_name)
290 bd5e77f9 Guido Trotter
      imp_op = opcodes.OpCreateInstance(instance_name=instance,
291 bd5e77f9 Guido Trotter
                                        mem_size=128,
292 bd5e77f9 Guido Trotter
                                        disk_size=self.opts.os_size,
293 bd5e77f9 Guido Trotter
                                        swap_size=self.opts.swap_size,
294 bd5e77f9 Guido Trotter
                                        disk_template=self.opts.disk_template,
295 bd5e77f9 Guido Trotter
                                        mode=constants.INSTANCE_IMPORT,
296 bd5e77f9 Guido Trotter
                                        src_node=enode,
297 bd5e77f9 Guido Trotter
                                        src_path=imp_dir,
298 bd5e77f9 Guido Trotter
                                        pnode=pnode,
299 bd5e77f9 Guido Trotter
                                        snode=snode,
300 bd5e77f9 Guido Trotter
                                        vcpus=1,
301 bd5e77f9 Guido Trotter
                                        start=True,
302 bd5e77f9 Guido Trotter
                                        ip_check=True,
303 bd5e77f9 Guido Trotter
                                        wait_for_sync=True,
304 bd5e77f9 Guido Trotter
                                        mac="auto")
305 bd5e77f9 Guido Trotter
306 bd5e77f9 Guido Trotter
      Log("- Export instance %s to node %s" % (instance, enode))
307 bd5e77f9 Guido Trotter
      self.ExecOp(exp_op)
308 bd5e77f9 Guido Trotter
      Log("- Remove instance %s" % (instance))
309 bd5e77f9 Guido Trotter
      self.ExecOp(rem_op)
310 bd5e77f9 Guido Trotter
      self.to_rem.remove(instance)
311 bd5e77f9 Guido Trotter
      Log("- Import instance %s from node %s to node %s" %
312 bd5e77f9 Guido Trotter
          (instance, enode, pnode))
313 bd5e77f9 Guido Trotter
      self.ExecOp(imp_op)
314 bd5e77f9 Guido Trotter
      self.to_rem.append(instance)
315 bd5e77f9 Guido Trotter
316 175f44c2 Iustin Pop
  def StopStart(self):
317 175f44c2 Iustin Pop
    """Stop/start the instances."""
318 175f44c2 Iustin Pop
    for instance in self.instances:
319 175f44c2 Iustin Pop
      op = opcodes.OpShutdownInstance(instance_name=instance)
320 21546b1c Iustin Pop
      Log("- Shutdown instance %s" % instance)
321 21546b1c Iustin Pop
      self.ExecOp(op)
322 175f44c2 Iustin Pop
      op = opcodes.OpStartupInstance(instance_name=instance, force=False)
323 21546b1c Iustin Pop
      Log("- Start instance %s" % instance)
324 21546b1c Iustin Pop
      self.ExecOp(op)
325 175f44c2 Iustin Pop
326 175f44c2 Iustin Pop
  def Remove(self):
327 175f44c2 Iustin Pop
    """Remove the instances."""
328 175f44c2 Iustin Pop
    for instance in self.to_rem:
329 175f44c2 Iustin Pop
      op = opcodes.OpRemoveInstance(instance_name=instance)
330 21546b1c Iustin Pop
      Log("- Remove instance %s" % instance)
331 21546b1c Iustin Pop
      self.ExecOp(op)
332 175f44c2 Iustin Pop
333 175f44c2 Iustin Pop
  def BurninCluster(self):
334 175f44c2 Iustin Pop
    """Test a cluster intensively.
335 175f44c2 Iustin Pop
336 175f44c2 Iustin Pop
    This will create instances and then start/stop/failover them.
337 175f44c2 Iustin Pop
    It is safe for existing instances but could impact performance.
338 175f44c2 Iustin Pop
339 175f44c2 Iustin Pop
    """
340 175f44c2 Iustin Pop
341 175f44c2 Iustin Pop
    opts = self.opts
342 175f44c2 Iustin Pop
343 21546b1c Iustin Pop
    Log("- Testing global parameters")
344 175f44c2 Iustin Pop
345 bd249e2f Iustin Pop
    if (len(self.nodes) == 1 and
346 bd249e2f Iustin Pop
        opts.disk_template not in (constants.DT_DISKLESS, constants.DT_PLAIN)):
347 21546b1c Iustin Pop
      Log("When one node is available/selected the disk template must"
348 bd249e2f Iustin Pop
               " be 'plain' or 'diskless'")
349 175f44c2 Iustin Pop
      sys.exit(1)
350 175f44c2 Iustin Pop
351 21546b1c Iustin Pop
    has_err = True
352 175f44c2 Iustin Pop
    try:
353 175f44c2 Iustin Pop
      self.CreateInstances()
354 175f44c2 Iustin Pop
      if opts.do_replace1 and opts.disk_template in constants.DTS_NET_MIRROR:
355 175f44c2 Iustin Pop
        if opts.disk_template == constants.DT_REMOTE_RAID1:
356 175f44c2 Iustin Pop
          self.ReplaceDisks1R1()
357 175f44c2 Iustin Pop
        elif opts.disk_template == constants.DT_DRBD8:
358 175f44c2 Iustin Pop
          self.ReplaceDisks1D8()
359 175f44c2 Iustin Pop
      if (opts.do_replace2 and len(self.nodes) > 2 and
360 175f44c2 Iustin Pop
          opts.disk_template in constants.DTS_NET_MIRROR) :
361 175f44c2 Iustin Pop
        self.ReplaceDisks2()
362 175f44c2 Iustin Pop
363 175f44c2 Iustin Pop
      if opts.do_failover and opts.disk_template in constants.DTS_NET_MIRROR:
364 175f44c2 Iustin Pop
        self.Failover()
365 175f44c2 Iustin Pop
366 bd5e77f9 Guido Trotter
      if opts.do_importexport:
367 bd5e77f9 Guido Trotter
        self.ImportExport()
368 bd5e77f9 Guido Trotter
369 d4844f0f Guido Trotter
      if opts.do_startstop:
370 d4844f0f Guido Trotter
        self.StopStart()
371 d4844f0f Guido Trotter
372 21546b1c Iustin Pop
      has_err = False
373 175f44c2 Iustin Pop
    finally:
374 21546b1c Iustin Pop
      if has_err:
375 21546b1c Iustin Pop
        Log("Error detected: opcode buffer follows:\n\n")
376 21546b1c Iustin Pop
        Log(self.GetFeedbackBuf())
377 21546b1c Iustin Pop
        Log("\n\n")
378 175f44c2 Iustin Pop
      self.Remove()
379 175f44c2 Iustin Pop
380 175f44c2 Iustin Pop
    return 0
381 a8083063 Iustin Pop
382 01b69ec5 Michael Hanselmann
383 a8083063 Iustin Pop
def main():
384 3ecf6786 Iustin Pop
  """Main function"""
385 3ecf6786 Iustin Pop
386 175f44c2 Iustin Pop
  burner = Burner()
387 3ecf6786 Iustin Pop
  try:
388 3ecf6786 Iustin Pop
    utils.Lock('cmd', max_retries=15, debug=True)
389 3ecf6786 Iustin Pop
  except errors.LockError, err:
390 3ecf6786 Iustin Pop
    logger.ToStderr(str(err))
391 3ecf6786 Iustin Pop
    return 1
392 3ecf6786 Iustin Pop
  try:
393 175f44c2 Iustin Pop
    retval = burner.BurninCluster()
394 3ecf6786 Iustin Pop
  finally:
395 3ecf6786 Iustin Pop
    utils.Unlock('cmd')
396 3ecf6786 Iustin Pop
    utils.LockCleanup()
397 3ecf6786 Iustin Pop
  return retval
398 a8083063 Iustin Pop
399 01b69ec5 Michael Hanselmann
400 a8083063 Iustin Pop
if __name__ == "__main__":
401 3ecf6786 Iustin Pop
  main()