Statistics
| Branch: | Tag: | Revision:

root / tools / burnin @ 519bfbae

History | View | Annotate | Download (7.1 kB)

1
#!/usr/bin/python
2
#
3

    
4
import sys
5
import optparse
6

    
7
from ganeti import opcodes
8
from ganeti import mcpu
9
from ganeti import objects
10
from ganeti import constants
11
from ganeti import cli
12
from ganeti import logger
13
from ganeti import errors
14
from ganeti import utils
15

    
16
USAGE = ("\tburnin -o OS_NAME [options...] instance_name ...")
17

    
18
def Usage():
19
  """Shows program usage information and exits the program."""
20

    
21
  print >> sys.stderr, "Usage:"
22
  print >> sys.stderr, USAGE
23
  sys.exit(2)
24

    
25

    
26
def Feedback(msg):
27
  """Simple function that prints out its argument.
28

    
29
  """
30
  print msg
31

    
32

    
33
def ParseOptions():
34
  """Parses the command line options.
35

    
36
  In case of command line errors, it will show the usage and exit the
37
  program.
38

    
39
  Returns:
40
    (options, args), as returned by OptionParser.parse_args
41
  """
42

    
43
  parser = optparse.OptionParser(usage="\n%s" % USAGE,
44
                                 version="%%prog (ganeti) %s" %
45
                                 constants.RELEASE_VERSION,
46
                                 option_class=cli.CliOption)
47

    
48
  parser.add_option("-o", "--os", dest="os", default=None,
49
                    help="OS to use during burnin",
50
                    metavar="<OS>")
51
  parser.add_option("--os-size", dest="os_size", help="Disk size",
52
                    default=4 * 1024, type="unit", metavar="<size>")
53
  parser.add_option("--swap-size", dest="swap_size", help="Swap size",
54
                    default=4 * 1024, type="unit", metavar="<size>")
55
  parser.add_option("-v", "--verbose",
56
                    action="store_true", dest="verbose", default=False,
57
                    help="print command execution messages to stdout")
58
  parser.add_option("--no-replace1", dest="do_replace1",
59
                    help="Do disk replacement with the same secondary",
60
                    action="store_false", default=True)
61
  parser.add_option("--no-replace2", dest="do_replace2",
62
                    help="Do disk replacement with a different secondary",
63
                    action="store_false", default=True)
64
  parser.add_option("--no-failover", dest="do_failover",
65
                    help="Do instance failovers", action="store_false",
66
                    default=True)
67
  parser.add_option("-t", "--disk-template", dest="disk_template",
68
                    choices=("remote_raid1", "drbd8"), default="remote_raid1",
69
                    help="Template type for network mirroring (remote_raid1"
70
                    " or drbd8) [remote_raid1]")
71
  parser.add_option("-n", "--nodes", dest="nodes", default="",
72
                    help="Comma separated list of nodes to perform the burnin"
73
                    " on (defaults to all nodes)")
74

    
75
  options, args = parser.parse_args()
76
  if len(args) < 1 or options.os is None:
77
    Usage()
78

    
79
  return options, args
80

    
81

    
82
def BurninCluster(opts, args):
83
  """Test a cluster intensively.
84

    
85
  This will create instances and then start/stop/failover them.
86
  It is safe for existing instances but could impact performance.
87

    
88
  """
89

    
90
  logger.SetupLogging(debug=True, program="ganeti/burnin")
91
  proc = mcpu.Processor(feedback=Feedback)
92
  if opts.nodes:
93
    names = opts.nodes.split(",")
94
  else:
95
    names = []
96
  try:
97
    result = proc.ExecOpCode(opcodes.OpQueryNodes(output_fields=["name"],
98
                                                  names=names))
99
  except errors.GenericError, err:
100
    err_code, msg = cli.FormatError(err)
101
    Feedback(msg)
102
    return err_code
103
  nodelist = [data[0] for data in result]
104

    
105
  Feedback("- Testing global parameters")
106

    
107
  result = proc.ExecOpCode(opcodes.OpDiagnoseOS())
108

    
109
  if not result:
110
    Feedback("Can't get the OS list")
111
    return 1
112

    
113
  # filter non-valid OS-es
114
  oses = {}
115
  for node_name in result:
116
    oses[node_name] = [obj for obj in result[node_name]
117
                       if isinstance(obj, objects.OS)]
118

    
119
  fnode = oses.keys()[0]
120
  os_set = set([os_inst.name for os_inst in oses[fnode]])
121
  del oses[fnode]
122
  for node in oses:
123
    os_set &= set([os_inst.name for os_inst in oses[node]])
124

    
125
  if opts.os not in os_set:
126
    Feedback("OS '%s' not found" % opts.os)
127
    return 1
128

    
129
  to_remove = []
130
  if opts.disk_template == "remote_raid1":
131
    disk_template = constants.DT_REMOTE_RAID1
132
  elif opts.disk_template == "drbd8":
133
    disk_template = constants.DT_DRBD8
134
  else:
135
    Feedback("Unknown disk template '%s'" % opts.disk_template)
136
    return 1
137
  try:
138
    idx = 0
139
    for instance_name in args:
140
      next_idx = idx + 1
141
      if next_idx >= len(nodelist):
142
        next_idx = 0
143
      pnode = nodelist[idx]
144
      snode = nodelist[next_idx]
145
      if len(nodelist) > 1:
146
        tplate = disk_template
147
      else:
148
        tplate = constants.DT_PLAIN
149

    
150
      op = opcodes.OpCreateInstance(instance_name=instance_name, mem_size=128,
151
                                    disk_size=opts.os_size,
152
                                    swap_size=opts.swap_size,
153
                                    disk_template=tplate,
154
                                    mode=constants.INSTANCE_CREATE,
155
                                    os_type=opts.os, pnode=pnode,
156
                                    snode=snode, vcpus=1,
157
                                    start=True,
158
                                    ip_check=True,
159
                                    wait_for_sync=True)
160
      Feedback("- Add instance %s on node %s" % (instance_name, pnode))
161
      result = proc.ExecOpCode(op)
162
      to_remove.append(instance_name)
163
      idx = next_idx
164

    
165

    
166
    if opts.do_replace1:
167
      if len(nodelist) > 1:
168
        # failover
169
        for instance_name in args:
170
          op = opcodes.OpReplaceDisks(instance_name=instance_name,
171
                                      remote_node=None,
172
                                      mode=constants.REPLACE_DISK_ALL,
173
                                      disks=["sda", "sdb"])
174

    
175
          Feedback("- Replace disks for instance %s" % (instance_name))
176
          result = proc.ExecOpCode(op)
177
      else:
178
        Feedback("- Can't run replace1, not enough nodes")
179

    
180
    if opts.do_failover:
181
      if len(nodelist) > 1:
182
        # failover
183
        for instance_name in args:
184
          op = opcodes.OpFailoverInstance(instance_name=instance_name,
185
                                          ignore_consistency=True)
186

    
187
          Feedback("- Failover instance %s" % (instance_name))
188
          result = proc.ExecOpCode(op)
189
      else:
190
        Feedback("- Can't run failovers, not enough nodes")
191

    
192
    # stop / start
193
    for instance_name in args:
194
      op = opcodes.OpShutdownInstance(instance_name=instance_name)
195
      Feedback("- Shutdown instance %s" % instance_name)
196
      result = proc.ExecOpCode(op)
197
      op = opcodes.OpStartupInstance(instance_name=instance_name, force=False)
198
      Feedback("- Start instance %s" % instance_name)
199
      result = proc.ExecOpCode(op)
200

    
201
  finally:
202
    # remove
203
    for instance_name in to_remove:
204
      op = opcodes.OpRemoveInstance(instance_name=instance_name)
205
      Feedback("- Remove instance %s" % instance_name)
206
      result = proc.ExecOpCode(op)
207

    
208
  return 0
209

    
210
def main():
211
  """Main function"""
212

    
213
  opts, args = ParseOptions()
214
  try:
215
    utils.Lock('cmd', max_retries=15, debug=True)
216
  except errors.LockError, err:
217
    logger.ToStderr(str(err))
218
    return 1
219
  try:
220
    retval = BurninCluster(opts, args)
221
  finally:
222
    utils.Unlock('cmd')
223
    utils.LockCleanup()
224
  return retval
225

    
226
if __name__ == "__main__":
227
  main()